return ret;
 }
 
+static void brcmf_sdiod_nomedium_state(struct brcmf_sdio_dev *sdiodev)
+{
+       sdiodev->state = BRCMF_STATE_NOMEDIUM;
+       brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_DOWN);
+}
+
 static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
                                   u8 regsz, void *data, bool write)
 {
        s32 retry = 0;
        int ret;
 
-       if (sdiodev->bus_if->state == BRCMF_BUS_NOMEDIUM)
+       if (sdiodev->state == BRCMF_STATE_NOMEDIUM)
                return -ENOMEDIUM;
 
        /*
                 retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
 
        if (ret == -ENOMEDIUM)
-               brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_NOMEDIUM);
+               brcmf_sdiod_nomedium_state(sdiodev);
        else if (ret != 0) {
                /*
                 * SleepCSR register access can fail when
        int err = 0, i;
        u8 addr[3];
 
-       if (sdiodev->bus_if->state == BRCMF_BUS_NOMEDIUM)
+       if (sdiodev->state == BRCMF_STATE_NOMEDIUM)
                return -ENOMEDIUM;
 
        addr[0] = (address >> 8) & SBSDIO_SBADDRLOW_MASK;
                err = sdio_readsb(sdiodev->func[fn], ((u8 *)(pkt->data)), addr,
                                  req_sz);
        if (err == -ENOMEDIUM)
-               brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_NOMEDIUM);
+               brcmf_sdiod_nomedium_state(sdiodev);
        return err;
 }
 
 
                ret = mmc_cmd.error ? mmc_cmd.error : mmc_dat.error;
                if (ret == -ENOMEDIUM) {
-                       brcmf_bus_change_state(sdiodev->bus_if,
-                                              BRCMF_BUS_NOMEDIUM);
+                       brcmf_sdiod_nomedium_state(sdiodev);
                        break;
                } else if (ret != 0) {
                        brcmf_err("CMD53 sg block %s failed %d\n",
 
 
 /* The level of bus communication with the dongle */
 enum brcmf_bus_state {
-       BRCMF_BUS_UNKNOWN,      /* Not determined yet */
-       BRCMF_BUS_NOMEDIUM,     /* No medium access to dongle */
        BRCMF_BUS_DOWN,         /* Not ready for frame transfers */
-       BRCMF_BUS_LOAD,         /* Download access only (CPU reset) */
-       BRCMF_BUS_DATA          /* Ready for frame transfers */
+       BRCMF_BUS_UP            /* Ready for frame transfers */
 };
 
 /* The level of bus communication with the dongle */
                bus->ops->wowl_config(bus->dev, enabled);
 }
 
-static inline bool brcmf_bus_ready(struct brcmf_bus *bus)
-{
-       return bus->state == BRCMF_BUS_LOAD || bus->state == BRCMF_BUS_DATA;
-}
-
 static inline void brcmf_bus_change_state(struct brcmf_bus *bus,
                                          enum brcmf_bus_state new_state)
 {
-       /* NOMEDIUM is permanent */
-       if (bus->state == BRCMF_BUS_NOMEDIUM)
-               return;
-
        brcmf_dbg(TRACE, "%d -> %d\n", bus->state, new_state);
        bus->state = new_state;
 }
 
        brcmf_dbg(DATA, "Enter, idx=%d\n", ifp->bssidx);
 
        /* Can the device send data? */
-       if (drvr->bus_if->state != BRCMF_BUS_DATA) {
+       if (drvr->bus_if->state != BRCMF_BUS_UP) {
                brcmf_err("xmit rejected state=%d\n", drvr->bus_if->state);
                netif_stop_queue(ndev);
                dev_kfree_skb(skb);
        brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
 
        /* If bus is not ready, can't continue */
-       if (bus_if->state != BRCMF_BUS_DATA) {
+       if (bus_if->state != BRCMF_BUS_UP) {
                brcmf_err("failed bus is not ready\n");
                return -EAGAIN;
        }
                p2p_ifp = NULL;
 
        /* signal bus ready */
-       brcmf_bus_change_state(bus_if, BRCMF_BUS_DATA);
+       brcmf_bus_change_state(bus_if, BRCMF_BUS_UP);
 
        /* Bus is ready, do any initialization */
        ret = brcmf_c_preinit_dcmds(ifp);
 
        struct brcmf_pub *drvr = ifp->drvr;
        s32 err;
 
-       if (drvr->bus_if->state != BRCMF_BUS_DATA) {
+       if (drvr->bus_if->state != BRCMF_BUS_UP) {
                brcmf_err("bus is down. we have nothing to do.\n");
                return -EIO;
        }
 
                                goto cleanup;
                        brcmf_dbg(PCIE, "Hot resume, continue....\n");
                        brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2);
-                       brcmf_bus_change_state(bus, BRCMF_BUS_DATA);
+                       brcmf_bus_change_state(bus, BRCMF_BUS_UP);
                        brcmf_pcie_intr_enable(devinfo);
                        return 0;
                }
 
        bus->rxpending = true;
 
        for (rd->seq_num = bus->rx_seq, rxleft = maxframes;
-            !bus->rxskip && rxleft && brcmf_bus_ready(bus->sdiodev->bus_if);
+            !bus->rxskip && rxleft && bus->sdiodev->state == BRCMF_STATE_DATA;
             rd->seq_num++, rxleft--) {
 
                /* Handle glomming separately */
        }
 
        /* Deflow-control stack if needed */
-       if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DATA) &&
+       if ((bus->sdiodev->state == BRCMF_STATE_DATA) &&
            bus->txoff && (pktq_len(&bus->txq) < TXLOW)) {
                bus->txoff = false;
                brcmf_txflowblock(bus->sdiodev->dev, false);
                bus->watchdog_tsk = NULL;
        }
 
-       if (bus_if->state == BRCMF_BUS_DOWN) {
+       if (sdiodev->state != BRCMF_STATE_NOMEDIUM) {
                sdio_claim_host(sdiodev->func[1]);
 
                /* Enable clock for device interrupts */
                brcmf_sdio_sendfromq(bus, framecnt);
        }
 
-       if (!brcmf_bus_ready(bus->sdiodev->bus_if) || (err != 0)) {
+       if ((bus->sdiodev->state != BRCMF_STATE_DATA) || (err != 0)) {
                brcmf_err("failed backplane access over SDIO, halting operation\n");
                atomic_set(&bus->intstatus, 0);
        } else if (atomic_read(&bus->intstatus) ||
                goto err;
        }
 
-       /* Allow HT Clock now that the ARM is running. */
-       brcmf_bus_change_state(bus->sdiodev->bus_if, BRCMF_BUS_LOAD);
+       /* Allow full data communication using DPC from now on. */
+       bus->sdiodev->state = BRCMF_STATE_DATA;
        bcmerror = 0;
 
 err:
                return;
        }
 
-       if (!brcmf_bus_ready(bus->sdiodev->bus_if)) {
+       if (bus->sdiodev->state != BRCMF_STATE_DATA) {
                brcmf_err("bus is down. we have nothing to do\n");
                return;
        }
 
 static bool brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus)
 {
-#ifdef DEBUG
-       struct brcmf_bus *bus_if = dev_get_drvdata(bus->sdiodev->dev);
-#endif /* DEBUG */
-
        brcmf_dbg(TIMER, "Enter\n");
 
        /* Poll period: check device if appropriate. */
        }
 #ifdef DEBUG
        /* Poll for console output periodically */
-       if (bus_if && bus_if->state == BRCMF_BUS_DATA &&
+       if (bus->sdiodev->state == BRCMF_STATE_DATA &&
            bus->console_interval != 0) {
                bus->console.count += BRCMF_WD_POLL_MS;
                if (bus->console.count >= bus->console_interval) {
                goto fail;
        }
 
-       /* SDIO register access works so moving
-        * state from UNKNOWN to DOWN.
-        */
-       brcmf_bus_change_state(bus->sdiodev->bus_if, BRCMF_BUS_DOWN);
-
        bus->ci = brcmf_chip_attach(bus->sdiodev, &brcmf_sdio_buscore_ops);
        if (IS_ERR(bus->ci)) {
                brcmf_err("brcmf_chip_attach failed!\n");
 
        brcmf_dbg(TRACE, "Enter: dev=%s\n", dev_name(dev));
 
-       /* try to download image and nvram to the dongle */
-       if (bus_if->state == BRCMF_BUS_DOWN) {
-               bus->alp_only = true;
-               err = brcmf_sdio_download_firmware(bus, code, nvram, nvram_len);
-               if (err)
-                       goto fail;
-               bus->alp_only = false;
-       }
-
        if (!bus_if->drvr)
                return;
 
+       /* try to download image and nvram to the dongle */
+       bus->alp_only = true;
+       err = brcmf_sdio_download_firmware(bus, code, nvram, nvram_len);
+       if (err)
+               goto fail;
+       bus->alp_only = false;
+
        /* Start the watchdog timer */
        bus->sdcnt.tickcnt = 0;
        brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);
                        destroy_workqueue(bus->brcmf_wq);
 
                if (bus->ci) {
-                       if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) {
+                       if (bus->sdiodev->state != BRCMF_STATE_NOMEDIUM) {
                                sdio_claim_host(bus->sdiodev->func[1]);
                                brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
                                /* Leave the device in state where it is
        }
 
        /* don't start the wd until fw is loaded */
-       if (bus->sdiodev->bus_if->state != BRCMF_BUS_DATA)
+       if (bus->sdiodev->state != BRCMF_STATE_DATA)
                return;
 
        if (wdtick) {
 
 /* watchdog polling interval in ms */
 #define BRCMF_WD_POLL_MS       10
 
+/* The state of the bus */
+enum brcmf_sdio_state {
+       BRCMF_STATE_DOWN,       /* Device available, still initialising */
+       BRCMF_STATE_DATA,       /* Ready for data transfers, DPC enabled */
+       BRCMF_STATE_NOMEDIUM    /* No medium access to dongle possible */
+};
+
 struct brcmf_sdreg {
        int func;
        int offset;
        char fw_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN];
        char nvram_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN];
        bool wowl_enabled;
+       enum brcmf_sdio_state state;
 };
 
 /* sdio core registers */
 
                brcmf_bus_change_state(bcmf_bus, BRCMF_BUS_DOWN);
        } else if (state == BRCMFMAC_USB_STATE_UP) {
                brcmf_dbg(USB, "DBUS is up\n");
-               brcmf_bus_change_state(bcmf_bus, BRCMF_BUS_DATA);
+               brcmf_bus_change_state(bcmf_bus, BRCMF_BUS_UP);
        } else {
                brcmf_dbg(USB, "DBUS current state=%d\n", state);
        }