diff options
Diffstat (limited to 'drivers/net/wireless/mwifiex/sdio.c')
-rw-r--r-- | drivers/net/wireless/mwifiex/sdio.c | 39 |
1 files changed, 36 insertions, 3 deletions
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 82cf0fa..5a1c1d0 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -906,8 +906,8 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) /* * SDIO interrupt handler. * - * This function reads the interrupt status from firmware and assigns - * the main process in workqueue which will handle the interrupt. + * This function reads the interrupt status from firmware and handles + * the interrupt in current thread (ksdioirqd) right away. */ static void mwifiex_sdio_interrupt(struct sdio_func *func) @@ -930,7 +930,7 @@ mwifiex_sdio_interrupt(struct sdio_func *func) adapter->ps_state = PS_STATE_AWAKE; mwifiex_interrupt_status(adapter); - queue_work(adapter->workqueue, &adapter->main_work); + mwifiex_main_process(adapter); } /* @@ -1749,6 +1749,37 @@ mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port) port, card->mp_data_port_mask); } +static struct mmc_host *reset_host; +static void sdio_card_reset_worker(struct work_struct *work) +{ + /* The actual reset operation must be run outside of driver thread. + * This is because mmc_remove_host() will cause the device to be + * instantly destroyed, and the driver then needs to end its thread, + * leading to a deadlock. + * + * We run it in a totally independent workqueue. + */ + + pr_err("Resetting card...\n"); + mmc_remove_host(reset_host); + /* 20ms delay is based on experiment with sdhci controller */ + mdelay(20); + mmc_add_host(reset_host); +} +static DECLARE_WORK(card_reset_work, sdio_card_reset_worker); + +/* This function resets the card */ +static void mwifiex_sdio_card_reset(struct mwifiex_adapter *adapter) +{ + struct sdio_mmc_card *card = adapter->card; + + if (work_pending(&card_reset_work)) + return; + + reset_host = card->func->card->host; + schedule_work(&card_reset_work); +} + static struct mwifiex_if_ops sdio_ops = { .init_if = mwifiex_init_sdio, .cleanup_if = mwifiex_cleanup_sdio, @@ -1767,6 +1798,7 @@ static struct mwifiex_if_ops sdio_ops = { .cleanup_mpa_buf = mwifiex_cleanup_mpa_buf, .cmdrsp_complete = mwifiex_sdio_cmdrsp_complete, .event_complete = mwifiex_sdio_event_complete, + .card_reset = mwifiex_sdio_card_reset, }; /* @@ -1804,6 +1836,7 @@ mwifiex_sdio_cleanup_module(void) /* Set the flag as user is removing this module. */ user_rmmod = 1; + cancel_work_sync(&card_reset_work); sdio_unregister_driver(&mwifiex_sdio); } |