From c9f4996df9c950561f9caa6cca1158cb28111fb2 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 25 Oct 2019 09:28:17 +0200 Subject: mwifiex: Re-work support for SDIO HW reset To fix the HW reset behaviour when multiple SDIO funcs shares the same SDIO card, the SDIO core have added support for SDIO func reset notifiers. These are used to inform clients about the reset process, which allows them to take relevant actions. As a mwifiex SDIO func can shared the SDIO interface with a bluetooth SDIO func, this is needed to properly support SDIO HW reset. Therefore, register the corresponding notifier with the SDIO core and implement support for this. Signed-off-by: Ulf Hansson --- drivers/net/wireless/marvell/mwifiex/sdio.c | 49 ++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c index 24c041dad9f6..ebce0b3e1913 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.c +++ b/drivers/net/wireless/marvell/mwifiex/sdio.c @@ -32,6 +32,8 @@ #define SDIO_VERSION "1.0" static void mwifiex_sdio_work(struct work_struct *work); +static int mwifiex_sdio_nb(struct notifier_block *nb, unsigned long val, + void *data); static struct mwifiex_if_ops sdio_ops; @@ -147,6 +149,8 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) goto err_disable; } + func->nb.notifier_call = mwifiex_sdio_nb; + sdio_add_notifier(func); return 0; err_disable: @@ -377,6 +381,8 @@ mwifiex_sdio_remove(struct sdio_func *func) int ret = 0; u16 firmware_stat; + sdio_remove_notifier(func); + card = sdio_get_drvdata(func); if (!card) return; @@ -2214,28 +2220,43 @@ mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port) port, card->mp_data_port_mask); } -static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter) +static int mwifiex_sdio_nb(struct notifier_block *nb, unsigned long val, + void *data) { - struct sdio_mmc_card *card = adapter->card; - struct sdio_func *func = card->func; + struct sdio_func *func = nb_to_sdio_func(nb); + struct sdio_mmc_card *card; int ret; - mwifiex_shutdown_sw(adapter); + card = sdio_get_drvdata(func); + if (!card || !card->adapter) + return 0; + + switch (val) { + case SDIO_HW_RESET_PREP: + mwifiex_shutdown_sw(adapter); + clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags); + clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags); + break; + case SDIO_HW_RESET_POST: + ret = mwifiex_reinit_sw(adapter); + if (ret) + dev_err(&func->dev, "reinit failed: %d\n", ret); + break; + default: + break; + } + + return 0; +} + +static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter) +{ + struct sdio_func *func = adapter->card->func; /* power cycle the adapter */ sdio_claim_host(func); mmc_hw_reset(func->card->host); sdio_release_host(func); - - /* Previous save_adapter won't be valid after this. We will cancel - * pending work requests. - */ - clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags); - clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags); - - ret = mwifiex_reinit_sw(adapter); - if (ret) - dev_err(&func->dev, "reinit failed: %d\n", ret); } /* This function read/write firmware */ -- cgit v1.2.3