mwifiex: add recovery code if the firmware becomes wedged.
The firmware can get into a state where it does not respond and the
driver does not attempt a reset.
The symptom in the log messages is:
mwifiex_sdio mmc1:0001:1: host_to_card, write iomem (1) failed: -1
Add code to issue a reset when the driver gets into this state to aid
recovery. For now this is off by default and can be enabled by writing
a non-zero value into debugfs firmware_recover.
In addition, add test code to simulate the failure. Writing a non-zero
value into debugfs firmware_wedge immediately simulates the firmware
not responding, and if firmware_recover is enabled, this variable is
cleared in reset.
See b/31916833
Change-Id: I8a5a3b9e9438a1af3ee144dc9a4cb0be5c0c978a
diff --git a/drivers/net/wireless/marvell/mwifiex/debugfs.c b/drivers/net/wireless/marvell/mwifiex/debugfs.c
index 0b9c580..587f39c 100644
--- a/drivers/net/wireless/marvell/mwifiex/debugfs.c
+++ b/drivers/net/wireless/marvell/mwifiex/debugfs.c
@@ -25,6 +25,11 @@
static struct dentry *mwifiex_dfs_dir;
+u32 firmware_wedge = 0;
+u32 firmware_recover = 0;
+EXPORT_SYMBOL(firmware_wedge);
+EXPORT_SYMBOL(firmware_recover);
+
static char *bss_modes[] = {
"UNSPECIFIED",
"ADHOC",
@@ -968,6 +973,11 @@
MWIFIEX_DFS_ADD_FILE(debug_mask);
MWIFIEX_DFS_ADD_FILE(timeshare_coex);
MWIFIEX_DFS_ADD_FILE(reset);
+
+ debugfs_create_u32("firmware_wedge", 0644, priv->dfs_dev_dir,
+ &firmware_wedge);
+ debugfs_create_u32("firmware_recover", 0644, priv->dfs_dev_dir,
+ &firmware_recover);
}
/*
diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c
index c264ead..acc7afc 100644
--- a/drivers/net/wireless/marvell/mwifiex/sdio.c
+++ b/drivers/net/wireless/marvell/mwifiex/sdio.c
@@ -44,10 +44,14 @@
* is removed, and will be set to TRUE for module removal when
* module_exit function is called.
*/
+extern u32 firmware_recover;
+extern u32 firmware_wedge;
+
static u8 user_rmmod;
static struct mwifiex_if_ops sdio_ops;
static unsigned long iface_work_flags;
+static void mwifiex_sdio_card_reset(struct mwifiex_adapter *adapter);
static struct semaphore add_remove_card_sem;
@@ -569,6 +573,9 @@
do {
ret = mwifiex_write_data_sync(adapter, payload, pkt_len, port);
+ if (firmware_wedge)
+ ret = -1;
+
if (ret) {
i++;
mwifiex_dbg(adapter, ERROR,
@@ -579,8 +586,16 @@
"write CFG reg failed\n");
ret = -1;
- if (i > MAX_WRITE_IOMEM_RETRY)
+ if (i > MAX_WRITE_IOMEM_RETRY) {
+ if (firmware_recover) {
+ mwifiex_dbg(adapter, ERROR,
+ "host_to_card, reset. "
+ "firmware_wedge: %d",
+ firmware_wedge);
+ mwifiex_sdio_card_reset(adapter);
+ }
return ret;
+ }
}
} while (ret == -1);
@@ -2163,6 +2178,7 @@
* We run it in a totally independent workqueue.
*/
+ firmware_wedge = 0;
mwifiex_dbg(adapter, WARN, "Resetting card...\n");
mmc_remove_host(target);
/* 200ms delay is based on experiment with sdhci controller */