Skip to content

Commit 7444a80

Browse files
zonqueKalle Valo
authored andcommitted
libertas: fix suspend and resume for SDIO connected cards
Prior to commit 573185c ("mmc: core: Invoke sdio func driver's PM callbacks from the sdio bus"), the MMC core used to call into the power management functions of SDIO clients itself and removed the card if the return code was non-zero. IOW, the mmc handled errors gracefully and didn't upchain them to the pm core. Since this change, the mmc core relies on generic power management functions which treat all errors as a reason to cancel the suspend immediately. This causes suspend attempts to fail when the libertas driver is loaded. To fix this, power down the card explicitly in if_sdio_suspend() when we know we're about to lose power and return success. Also set a flag in these cases, and power up the card again in if_sdio_resume(). Fixes: 573185c ("mmc: core: Invoke sdio func driver's PM callbacks from the sdio bus") Cc: <stable@vger.kernel.org> Signed-off-by: Daniel Mack <daniel@zonque.org> Reviewed-by: Chris Ball <chris@printf.net> Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
1 parent 07b1ae4 commit 7444a80

File tree

2 files changed

+25
-6
lines changed

2 files changed

+25
-6
lines changed

drivers/net/wireless/marvell/libertas/dev.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ struct lbs_private {
104104
u8 fw_ready;
105105
u8 surpriseremoved;
106106
u8 setup_fw_on_resume;
107+
u8 power_up_on_resume;
107108
int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
108109
void (*reset_card) (struct lbs_private *priv);
109110
int (*power_save) (struct lbs_private *priv);

drivers/net/wireless/marvell/libertas/if_sdio.c

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1290,25 +1290,38 @@ static void if_sdio_remove(struct sdio_func *func)
12901290
static int if_sdio_suspend(struct device *dev)
12911291
{
12921292
struct sdio_func *func = dev_to_sdio_func(dev);
1293-
int ret;
12941293
struct if_sdio_card *card = sdio_get_drvdata(func);
1294+
struct lbs_private *priv = card->priv;
1295+
int ret;
12951296

12961297
mmc_pm_flag_t flags = sdio_get_host_pm_caps(func);
1298+
priv->power_up_on_resume = false;
12971299

12981300
/* If we're powered off anyway, just let the mmc layer remove the
12991301
* card. */
1300-
if (!lbs_iface_active(card->priv))
1301-
return -ENOSYS;
1302+
if (!lbs_iface_active(priv)) {
1303+
if (priv->fw_ready) {
1304+
priv->power_up_on_resume = true;
1305+
if_sdio_power_off(card);
1306+
}
1307+
1308+
return 0;
1309+
}
13021310

13031311
dev_info(dev, "%s: suspend: PM flags = 0x%x\n",
13041312
sdio_func_id(func), flags);
13051313

13061314
/* If we aren't being asked to wake on anything, we should bail out
13071315
* and let the SD stack power down the card.
13081316
*/
1309-
if (card->priv->wol_criteria == EHS_REMOVE_WAKEUP) {
1317+
if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
13101318
dev_info(dev, "Suspend without wake params -- powering down card\n");
1311-
return -ENOSYS;
1319+
if (priv->fw_ready) {
1320+
priv->power_up_on_resume = true;
1321+
if_sdio_power_off(card);
1322+
}
1323+
1324+
return 0;
13121325
}
13131326

13141327
if (!(flags & MMC_PM_KEEP_POWER)) {
@@ -1321,7 +1334,7 @@ static int if_sdio_suspend(struct device *dev)
13211334
if (ret)
13221335
return ret;
13231336

1324-
ret = lbs_suspend(card->priv);
1337+
ret = lbs_suspend(priv);
13251338
if (ret)
13261339
return ret;
13271340

@@ -1336,6 +1349,11 @@ static int if_sdio_resume(struct device *dev)
13361349

13371350
dev_info(dev, "%s: resume: we're back\n", sdio_func_id(func));
13381351

1352+
if (card->priv->power_up_on_resume) {
1353+
if_sdio_power_on(card);
1354+
wait_event(card->pwron_waitq, card->priv->fw_ready);
1355+
}
1356+
13391357
ret = lbs_resume(card->priv);
13401358

13411359
return ret;

0 commit comments

Comments
 (0)