mirror of https://gitee.com/openkylin/linux.git
libertas: add sd8686 reset_card support
At http://dev.laptop.org/ticket/10748 we are seeing a case of the libertas firmware randomly stopping responding to commands after resume. Careful monitoring of communications indicates a firmware or hardware bug, which has been reported to Marvell. Work around this issue by adding a reset_card method; this is automatically called when command timeouts are detected and provides an instant recovery to this situation. Signed-off-by: Daniel Drake <dsd@laptop.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
43a1c2721a
commit
9a821f5d0f
|
@ -892,6 +892,37 @@ static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct mmc_host *reset_host;
|
||||||
|
|
||||||
|
static void if_sdio_reset_card_worker(struct work_struct *work)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The actual reset operation must be run outside of lbs_thread. This
|
||||||
|
* is because mmc_remove_host() will cause the device to be instantly
|
||||||
|
* destroyed, and the libertas driver then needs to end lbs_thread,
|
||||||
|
* leading to a deadlock.
|
||||||
|
*
|
||||||
|
* We run it in a workqueue totally independent from the if_sdio_card
|
||||||
|
* instance for that reason.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pr_info("Resetting card...");
|
||||||
|
mmc_remove_host(reset_host);
|
||||||
|
mmc_add_host(reset_host);
|
||||||
|
}
|
||||||
|
static DECLARE_WORK(card_reset_work, if_sdio_reset_card_worker);
|
||||||
|
|
||||||
|
static void if_sdio_reset_card(struct lbs_private *priv)
|
||||||
|
{
|
||||||
|
struct if_sdio_card *card = priv->card;
|
||||||
|
|
||||||
|
if (work_pending(&card_reset_work))
|
||||||
|
return;
|
||||||
|
|
||||||
|
reset_host = card->func->card->host;
|
||||||
|
schedule_work(&card_reset_work);
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************************************/
|
/*******************************************************************/
|
||||||
/* SDIO callbacks */
|
/* SDIO callbacks */
|
||||||
/*******************************************************************/
|
/*******************************************************************/
|
||||||
|
@ -1065,6 +1096,7 @@ static int if_sdio_probe(struct sdio_func *func,
|
||||||
priv->enter_deep_sleep = if_sdio_enter_deep_sleep;
|
priv->enter_deep_sleep = if_sdio_enter_deep_sleep;
|
||||||
priv->exit_deep_sleep = if_sdio_exit_deep_sleep;
|
priv->exit_deep_sleep = if_sdio_exit_deep_sleep;
|
||||||
priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup;
|
priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup;
|
||||||
|
priv->reset_card = if_sdio_reset_card;
|
||||||
|
|
||||||
sdio_claim_host(func);
|
sdio_claim_host(func);
|
||||||
|
|
||||||
|
@ -1301,6 +1333,8 @@ static void __exit if_sdio_exit_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(&if_sdio_driver);
|
sdio_unregister_driver(&if_sdio_driver);
|
||||||
|
|
||||||
lbs_deb_leave(LBS_DEB_SDIO);
|
lbs_deb_leave(LBS_DEB_SDIO);
|
||||||
|
|
Loading…
Reference in New Issue