Search Linux Wireless

[PATCH 2/8] ath6kl: Re-architect suspend mode handling in ath6kl_sdio_suspend()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Raja Mani <rmani@xxxxxxxxxxxxxxxx>

Dynamic suspend mode selection logic based on the host sdio
controller capability (MMC_PM_KEEP_POWER and MMC_PM_WAKE_SDIO_IRQ)
is completely removed.

Now, ath6kl_sdio_suspend() func will react based on the suspend mode
specified at the time of loading the driver (via module parameter
suspend_mode).

Additionally, new logic is added to have backup retry.
In other words, If the driver fails to enter into either
WOW (or) DEEP SLEEP mode, it would give a try in CUT POWER mode.

Signed-off-by: Raja Mani <rmani@xxxxxxxxxxxxxxxx>
---
 drivers/net/wireless/ath/ath6kl/sdio.c |  105 ++++++++++++++++++++------------
 1 files changed, 66 insertions(+), 39 deletions(-)

diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c
index 278a9f3..9eae745 100644
--- a/drivers/net/wireless/ath/ath6kl/sdio.c
+++ b/drivers/net/wireless/ath/ath6kl/sdio.c
@@ -787,66 +787,93 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
 	struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
 	struct sdio_func *func = ar_sdio->func;
 	mmc_pm_flag_t flags;
-	int ret;
+	unsigned char pmode_to_try;
+	int ret = -EINVAL;
 
 	flags = sdio_get_host_pm_caps(func);
 
 	ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sdio suspend pm_caps 0x%x\n", flags);
 
-	if (!(flags & MMC_PM_KEEP_POWER) ||
-	    (ar->conf_flags & ATH6KL_CONF_SUSPEND_CUTPOWER)) {
-		/* as host doesn't support keep power we need to cut power */
-		return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER,
-					       NULL);
-	}
-
-	ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
-	if (ret) {
-		printk(KERN_ERR "ath6kl: set sdio pm flags failed: %d\n",
-		       ret);
-		return ret;
-	}
+	/* Schedule scan uses WOW internally */
+	pmode_to_try = (ar->state == ATH6KL_STATE_SCHED_SCAN) ?
+			WLAN_POWER_STATE_WOW : ar->suspend_mode;
+retry:
+	switch (pmode_to_try) {
+	case WLAN_POWER_STATE_CUT_PWR:
+		ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER,
+					      NULL);
+		break;
 
-	if (!(flags & MMC_PM_WAKE_SDIO_IRQ))
-		goto deepsleep;
+	case WLAN_POWER_STATE_DEEP_SLEEP:
+		/* Try cut power if deep sleep suspend fails */
+		pmode_to_try = WLAN_POWER_STATE_CUT_PWR;
 
-	/* sdio irq wakes up host */
+		if (!(flags & MMC_PM_KEEP_POWER))
+			goto retry;
 
-	if (ar->state == ATH6KL_STATE_SCHED_SCAN) {
-		ret =  ath6kl_cfg80211_suspend(ar,
-					       ATH6KL_CFG_SUSPEND_SCHED_SCAN,
-					       NULL);
+		ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
 		if (ret) {
-			ath6kl_warn("Schedule scan suspend failed: %d", ret);
-			return ret;
+			ath6kl_warn("failed to set sdio keep power flag: %d\n",
+				     ret);
+			goto retry;
 		}
 
-		ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
+		ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP,
+					      NULL);
 		if (ret)
-			ath6kl_warn("set sdio wake irq flag failed: %d\n", ret);
+			goto retry;
 
-		return ret;
-	}
+		break;
 
-	if (wow) {
+	case WLAN_POWER_STATE_WOW:
+		/* Try cut power if wow suspend fails */
+		pmode_to_try = WLAN_POWER_STATE_CUT_PWR;
+
+		if (!(flags & MMC_PM_KEEP_POWER) ||
+		    !(flags & MMC_PM_WAKE_SDIO_IRQ))
+			goto retry;
+
+		ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+		if (ret) {
+			ath6kl_warn("failed to set sdio keep power flag: %d\n",
+				     ret);
+			goto retry;
+		}
+
+		ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
+		if (ret) {
+			ath6kl_warn("failed to set sdio wake irq flag: %d\n",
+				     ret);
+			goto retry;
+		}
 		/*
 		 * The host sdio controller is capable of keep power and
-		 * sdio irq wake up at this point. It's fine to continue
-		 * wow suspend operation.
+		 * sdio irq wake up at this point.
 		 */
-		ret = ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_WOW, wow);
-		if (ret)
-			return ret;
-
-		ret = sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
+		if (ar->state == ATH6KL_STATE_SCHED_SCAN) {
+			ath6kl_dbg(ATH6KL_DBG_SUSPEND,
+				  "sched scan is in progress\n");
+			ret =  ath6kl_cfg80211_suspend(ar,
+						ATH6KL_CFG_SUSPEND_SCHED_SCAN,
+						NULL);
+			if (ret)
+				ath6kl_warn("schedule scan suspend failed: %d",
+					    ret);
+		} else
+			ret = ath6kl_cfg80211_suspend(ar,
+					ATH6KL_CFG_SUSPEND_WOW, wow);
 		if (ret)
-			ath6kl_err("set sdio wake irq flag failed: %d\n", ret);
+			goto retry;
+		break;
 
-		return ret;
+	default:
+		/* We shouldn't be here. */
+		WARN_ON(1);
+		break;
 	}
 
-deepsleep:
-	return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_DEEPSLEEP, NULL);
+	return ret;
+
 }
 
 static int ath6kl_sdio_resume(struct ath6kl *ar)
-- 
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux