]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/4.14.69/libertas-fix-suspend-and-resume-for-sdio-connected-cards.patch
4.9-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 4.14.69 / libertas-fix-suspend-and-resume-for-sdio-connected-cards.patch
CommitLineData
bed0f502
GKH
1From 7444a8092906ed44c09459780c56ba57043e39b1 Mon Sep 17 00:00:00 2001
2From: Daniel Mack <daniel@zonque.org>
3Date: Wed, 27 Jun 2018 20:58:45 +0200
4Subject: libertas: fix suspend and resume for SDIO connected cards
5
6From: Daniel Mack <daniel@zonque.org>
7
8commit 7444a8092906ed44c09459780c56ba57043e39b1 upstream.
9
10Prior to commit 573185cc7e64 ("mmc: core: Invoke sdio func driver's PM
11callbacks from the sdio bus"), the MMC core used to call into the power
12management functions of SDIO clients itself and removed the card if the
13return code was non-zero. IOW, the mmc handled errors gracefully and didn't
14upchain them to the pm core.
15
16Since this change, the mmc core relies on generic power management
17functions which treat all errors as a reason to cancel the suspend
18immediately. This causes suspend attempts to fail when the libertas
19driver is loaded.
20
21To fix this, power down the card explicitly in if_sdio_suspend() when we
22know we're about to lose power and return success. Also set a flag in these
23cases, and power up the card again in if_sdio_resume().
24
25Fixes: 573185cc7e64 ("mmc: core: Invoke sdio func driver's PM callbacks from the sdio bus")
26Cc: <stable@vger.kernel.org>
27Signed-off-by: Daniel Mack <daniel@zonque.org>
28Reviewed-by: Chris Ball <chris@printf.net>
29Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
30Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
31Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
32
33---
34 drivers/net/wireless/marvell/libertas/dev.h | 1
35 drivers/net/wireless/marvell/libertas/if_sdio.c | 30 +++++++++++++++++++-----
36 2 files changed, 25 insertions(+), 6 deletions(-)
37
38--- a/drivers/net/wireless/marvell/libertas/dev.h
39+++ b/drivers/net/wireless/marvell/libertas/dev.h
40@@ -104,6 +104,7 @@ struct lbs_private {
41 u8 fw_ready;
42 u8 surpriseremoved;
43 u8 setup_fw_on_resume;
44+ u8 power_up_on_resume;
45 int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb);
46 void (*reset_card) (struct lbs_private *priv);
47 int (*power_save) (struct lbs_private *priv);
48--- a/drivers/net/wireless/marvell/libertas/if_sdio.c
49+++ b/drivers/net/wireless/marvell/libertas/if_sdio.c
50@@ -1290,15 +1290,23 @@ static void if_sdio_remove(struct sdio_f
51 static int if_sdio_suspend(struct device *dev)
52 {
53 struct sdio_func *func = dev_to_sdio_func(dev);
54- int ret;
55 struct if_sdio_card *card = sdio_get_drvdata(func);
56+ struct lbs_private *priv = card->priv;
57+ int ret;
58
59 mmc_pm_flag_t flags = sdio_get_host_pm_caps(func);
60+ priv->power_up_on_resume = false;
61
62 /* If we're powered off anyway, just let the mmc layer remove the
63 * card. */
64- if (!lbs_iface_active(card->priv))
65- return -ENOSYS;
66+ if (!lbs_iface_active(priv)) {
67+ if (priv->fw_ready) {
68+ priv->power_up_on_resume = true;
69+ if_sdio_power_off(card);
70+ }
71+
72+ return 0;
73+ }
74
75 dev_info(dev, "%s: suspend: PM flags = 0x%x\n",
76 sdio_func_id(func), flags);
77@@ -1306,9 +1314,14 @@ static int if_sdio_suspend(struct device
78 /* If we aren't being asked to wake on anything, we should bail out
79 * and let the SD stack power down the card.
80 */
81- if (card->priv->wol_criteria == EHS_REMOVE_WAKEUP) {
82+ if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
83 dev_info(dev, "Suspend without wake params -- powering down card\n");
84- return -ENOSYS;
85+ if (priv->fw_ready) {
86+ priv->power_up_on_resume = true;
87+ if_sdio_power_off(card);
88+ }
89+
90+ return 0;
91 }
92
93 if (!(flags & MMC_PM_KEEP_POWER)) {
94@@ -1321,7 +1334,7 @@ static int if_sdio_suspend(struct device
95 if (ret)
96 return ret;
97
98- ret = lbs_suspend(card->priv);
99+ ret = lbs_suspend(priv);
100 if (ret)
101 return ret;
102
103@@ -1336,6 +1349,11 @@ static int if_sdio_resume(struct device
104
105 dev_info(dev, "%s: resume: we're back\n", sdio_func_id(func));
106
107+ if (card->priv->power_up_on_resume) {
108+ if_sdio_power_on(card);
109+ wait_event(card->pwron_waitq, card->priv->fw_ready);
110+ }
111+
112 ret = lbs_resume(card->priv);
113
114 return ret;