mwifiex: add support for SDIO card reset
When command timeout happens due to a bug in firmware/hardware,
the timeout handler just prints some debug information. User is
unable to reload the driver in this case.
Inspired by 9a821f5
"libertas: add sd8686 reset_card support",
this patch adds card reset support for SDIO interface when
command timeout happens. If the SDIO host contoller supports
MMC_POWER_OFF|UP|ON operations, the chip will be reset and the
firmware will be re-downloaded.
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
b2cb1a900a
commit
d31ab3577e
@ -944,6 +944,9 @@ mwifiex_cmd_timeout_func(unsigned long function_context)
|
||||
}
|
||||
if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING)
|
||||
mwifiex_init_fw_complete(adapter);
|
||||
|
||||
if (adapter->if_ops.card_reset)
|
||||
adapter->if_ops.card_reset(adapter);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -600,6 +600,7 @@ struct mwifiex_if_ops {
|
||||
int (*event_complete) (struct mwifiex_adapter *, struct sk_buff *);
|
||||
int (*data_complete) (struct mwifiex_adapter *, struct sk_buff *);
|
||||
int (*dnld_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *);
|
||||
void (*card_reset) (struct mwifiex_adapter *);
|
||||
};
|
||||
|
||||
struct mwifiex_adapter {
|
||||
|
@ -1748,6 +1748,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,
|
||||
@ -1766,6 +1797,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,
|
||||
};
|
||||
|
||||
/*
|
||||
@ -1803,6 +1835,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);
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <linux/mmc/sdio_ids.h>
|
||||
#include <linux/mmc/sdio_func.h>
|
||||
#include <linux/mmc/card.h>
|
||||
#include <linux/mmc/host.h>
|
||||
|
||||
#include "main.h"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user