diff options
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c')
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 164 |
1 files changed, 83 insertions, 81 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 129cfd6bc686..7817ededcf7d 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -2303,6 +2303,87 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes) return cnt; } +static void brcmf_sdbrcm_bus_stop(struct device *dev) +{ + u32 local_hostintmask; + u8 saveclk; + uint retries; + int err; + struct brcmf_bus *bus_if = dev_get_drvdata(dev); + struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv; + struct brcmf_sdio *bus = sdiodev->bus; + + brcmf_dbg(TRACE, "Enter\n"); + + if (bus->watchdog_tsk) { + send_sig(SIGTERM, bus->watchdog_tsk, 1); + kthread_stop(bus->watchdog_tsk); + bus->watchdog_tsk = NULL; + } + + if (bus->dpc_tsk && bus->dpc_tsk != current) { + send_sig(SIGTERM, bus->dpc_tsk, 1); + kthread_stop(bus->dpc_tsk); + bus->dpc_tsk = NULL; + } + + down(&bus->sdsem); + + bus_wake(bus); + + /* Enable clock for device interrupts */ + brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); + + /* Disable and clear interrupts at the chip level also */ + w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask), &retries); + local_hostintmask = bus->hostintmask; + bus->hostintmask = 0; + + /* Change our idea of bus state */ + bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; + + /* Force clocks on backplane to be sure F2 interrupt propagates */ + saveclk = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, &err); + if (!err) { + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, + (saveclk | SBSDIO_FORCE_HT), &err); + } + if (err) + brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err); + + /* Turn off the bus (F2), free any pending packets */ + brcmf_dbg(INTR, "disable SDIO interrupts\n"); + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx, + SDIO_FUNC_ENABLE_1, NULL); + + /* Clear any pending interrupts now that F2 is disabled */ + w_sdreg32(bus, local_hostintmask, + offsetof(struct sdpcmd_regs, intstatus), &retries); + + /* Turn off the backplane clock (only) */ + brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); + + /* Clear the data packet queues */ + brcmu_pktq_flush(&bus->txq, true, NULL, NULL); + + /* Clear any held glomming stuff */ + if (bus->glomd) + brcmu_pkt_buf_free_skb(bus->glomd); + brcmf_sdbrcm_free_glom(bus); + + /* Clear rx control and wake any waiters */ + bus->rxlen = 0; + brcmf_sdbrcm_dcmd_resp_wake(bus); + + /* Reset some F2 state stuff */ + bus->rxskip = false; + bus->tx_seq = bus->rx_seq = 0; + + up(&bus->sdsem); +} + static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) { u32 intstatus, newstatus = 0; @@ -3342,87 +3423,6 @@ brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus) return ret; } -void brcmf_sdbrcm_bus_stop(struct device *dev) -{ - u32 local_hostintmask; - u8 saveclk; - uint retries; - int err; - struct brcmf_bus *bus_if = dev_get_drvdata(dev); - struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv; - struct brcmf_sdio *bus = sdiodev->bus; - - brcmf_dbg(TRACE, "Enter\n"); - - if (bus->watchdog_tsk) { - send_sig(SIGTERM, bus->watchdog_tsk, 1); - kthread_stop(bus->watchdog_tsk); - bus->watchdog_tsk = NULL; - } - - if (bus->dpc_tsk && bus->dpc_tsk != current) { - send_sig(SIGTERM, bus->dpc_tsk, 1); - kthread_stop(bus->dpc_tsk); - bus->dpc_tsk = NULL; - } - - down(&bus->sdsem); - - bus_wake(bus); - - /* Enable clock for device interrupts */ - brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); - - /* Disable and clear interrupts at the chip level also */ - w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask), &retries); - local_hostintmask = bus->hostintmask; - bus->hostintmask = 0; - - /* Change our idea of bus state */ - bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; - - /* Force clocks on backplane to be sure F2 interrupt propagates */ - saveclk = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, &err); - if (!err) { - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, - (saveclk | SBSDIO_FORCE_HT), &err); - } - if (err) - brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err); - - /* Turn off the bus (F2), free any pending packets */ - brcmf_dbg(INTR, "disable SDIO interrupts\n"); - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx, - SDIO_FUNC_ENABLE_1, NULL); - - /* Clear any pending interrupts now that F2 is disabled */ - w_sdreg32(bus, local_hostintmask, - offsetof(struct sdpcmd_regs, intstatus), &retries); - - /* Turn off the backplane clock (only) */ - brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); - - /* Clear the data packet queues */ - brcmu_pktq_flush(&bus->txq, true, NULL, NULL); - - /* Clear any held glomming stuff */ - if (bus->glomd) - brcmu_pkt_buf_free_skb(bus->glomd); - brcmf_sdbrcm_free_glom(bus); - - /* Clear rx control and wake any waiters */ - bus->rxlen = 0; - brcmf_sdbrcm_dcmd_resp_wake(bus); - - /* Reset some F2 state stuff */ - bus->rxskip = false; - bus->tx_seq = bus->rx_seq = 0; - - up(&bus->sdsem); -} - int brcmf_sdbrcm_bus_init(struct device *dev) { struct brcmf_bus *bus_if = dev_get_drvdata(dev); @@ -3952,6 +3952,8 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) bus->dpc_tsk = NULL; } + /* Assign bus interface call back */ + bus->sdiodev->bus_if->brcmf_bus_stop = brcmf_sdbrcm_bus_stop; /* Attach to the brcmf/OS/network interface */ ret = brcmf_attach(SDPCM_RESERVE, bus->sdiodev->dev); if (ret != 0) { |