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
4 changed files with 38 additions and 0 deletions
|
@ -944,6 +944,9 @@ mwifiex_cmd_timeout_func(unsigned long function_context)
|
||||||
}
|
}
|
||||||
if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING)
|
if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING)
|
||||||
mwifiex_init_fw_complete(adapter);
|
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 (*event_complete) (struct mwifiex_adapter *, struct sk_buff *);
|
||||||
int (*data_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 *);
|
int (*dnld_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *);
|
||||||
|
void (*card_reset) (struct mwifiex_adapter *);
|
||||||
};
|
};
|
||||||
|
|
||||||
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);
|
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 = {
|
static struct mwifiex_if_ops sdio_ops = {
|
||||||
.init_if = mwifiex_init_sdio,
|
.init_if = mwifiex_init_sdio,
|
||||||
.cleanup_if = mwifiex_cleanup_sdio,
|
.cleanup_if = mwifiex_cleanup_sdio,
|
||||||
|
@ -1766,6 +1797,7 @@ static struct mwifiex_if_ops sdio_ops = {
|
||||||
.cleanup_mpa_buf = mwifiex_cleanup_mpa_buf,
|
.cleanup_mpa_buf = mwifiex_cleanup_mpa_buf,
|
||||||
.cmdrsp_complete = mwifiex_sdio_cmdrsp_complete,
|
.cmdrsp_complete = mwifiex_sdio_cmdrsp_complete,
|
||||||
.event_complete = mwifiex_sdio_event_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. */
|
/* Set the flag as user is removing this module. */
|
||||||
user_rmmod = 1;
|
user_rmmod = 1;
|
||||||
|
|
||||||
|
cancel_work_sync(&card_reset_work);
|
||||||
sdio_unregister_driver(&mwifiex_sdio);
|
sdio_unregister_driver(&mwifiex_sdio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <linux/mmc/sdio_ids.h>
|
#include <linux/mmc/sdio_ids.h>
|
||||||
#include <linux/mmc/sdio_func.h>
|
#include <linux/mmc/sdio_func.h>
|
||||||
#include <linux/mmc/card.h>
|
#include <linux/mmc/card.h>
|
||||||
|
#include <linux/mmc/host.h>
|
||||||
|
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue