brcmfmac: Handle mmc exceptions during init correct.
authorHante Meuleman <meuleman@broadcom.com>
Thu, 15 Nov 2012 02:46:18 +0000 (18:46 -0800)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 16 Nov 2012 19:28:59 +0000 (14:28 -0500)
when brcmf_sdbrcm_probe_attach results in error then cleanup
will result in null pointer access. In brcmf_sdbrcm_release and
in brcmf_ops_sdio_remove. This patch fixes order of init and
de-init.

Reviewed-by: Arend Van Spriel <arend@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
Signed-off-by: Franky Lin <frankyl@broadcom.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c

index c62ec2a5b271edd181ece7be3181f898fa0ce06b..854573386f236fbf665bc7c27a8a35a847db85a9 100644 (file)
@@ -512,6 +512,8 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
 
                brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_probe...\n");
                ret = brcmf_sdio_probe(sdiodev);
+               if (ret)
+                       dev_set_drvdata(&func->dev, NULL);
        }
 
        return ret;
@@ -532,8 +534,12 @@ static void brcmf_ops_sdio_remove(struct sdio_func *func)
                sdiodev = bus_if->bus_priv.sdio;
                brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_remove...\n");
                brcmf_sdio_remove(sdiodev);
-               dev_set_drvdata(&func->card->dev, NULL);
                dev_set_drvdata(&func->dev, NULL);
+       }
+       if (func->num == 1) {
+               sdiodev = dev_get_drvdata(&func->card->dev);
+               bus_if = sdiodev->bus_if;
+               dev_set_drvdata(&func->card->dev, NULL);
                kfree(bus_if);
                kfree(sdiodev);
        }
index e2351a7969a7526e095fdf2fc132789c67bbc8db..40a37ac049706c3a3ea51fac3b3da011e75bb540 100644 (file)
@@ -3867,7 +3867,8 @@ static void brcmf_sdbrcm_release(struct brcmf_sdio *bus)
                brcmf_sdio_intr_unregister(bus->sdiodev);
 
                cancel_work_sync(&bus->datawork);
-               destroy_workqueue(bus->brcmf_wq);
+               if (bus->brcmf_wq)
+                       destroy_workqueue(bus->brcmf_wq);
 
                if (bus->sdiodev->bus_if->drvr) {
                        brcmf_detach(bus->sdiodev->dev);
@@ -3909,6 +3910,13 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
        bus->txminmax = BRCMF_TXMINMAX;
        bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
 
+       INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);
+       bus->brcmf_wq = create_singlethread_workqueue("brcmf_wq");
+       if (bus->brcmf_wq == NULL) {
+               brcmf_dbg(ERROR, "insufficient memory to create txworkqueue\n");
+               goto fail;
+       }
+
        /* attempt to attach to the dongle */
        if (!(brcmf_sdbrcm_probe_attach(bus, regsva))) {
                brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_attach failed\n");
@@ -3920,13 +3928,6 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
        init_waitqueue_head(&bus->ctrl_wait);
        init_waitqueue_head(&bus->dcmd_resp_wait);
 
-       bus->brcmf_wq = create_singlethread_workqueue("brcmf_wq");
-       if (bus->brcmf_wq == NULL) {
-               brcmf_dbg(ERROR, "insufficient memory to create txworkqueue\n");
-               goto fail;
-       }
-       INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);
-
        /* Set up the watchdog timer */
        init_timer(&bus->timer);
        bus->timer.data = (unsigned long)bus;