linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/6] wl12xx: add initial wowlan support
@ 2011-05-13  8:57 Eliad Peller
  2011-05-13  8:57 ` [PATCH v2 1/6] wl12xx_sdio: set interrupt as wake_up interrupt Eliad Peller
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Eliad Peller @ 2011-05-13  8:57 UTC (permalink / raw)
  To: Luciano Coelho; +Cc: linux-wireless

Add initial support for Wake-On-Wireless.

Currently, we support only the ANY trigger, which basically means
the device stays awake while the host is being suspended, and will
wake up the host by any irq it will trigger (but since the wl12xx
fw offloads a lot of its work, it will probably wake up the host
because of rx frame/beacon loss)

Note that this patchset needs some additional omap/mmc patches in 
order to support the MMC_PM_KEEP_POWER flag and wake-irq correctly
(however, if the MMC_PM_KEEP_POWER flag is not being supported we 
don't advertise support for wowlan triggers, so this patchset alone
shouldn't harm).

Changes from v1:
* reflow wl1271_hardirq (return immediately)
* squash one patch 
* define WL1271_PS_COMPLETE_TIMEOUT

Eliad Peller (6):
  wl12xx_sdio: set interrupt as wake_up interrupt
  wl12xx: declare suspend/resume callbacks (for wowlan)
  wl12xx_sdio: set MMC_PM_KEEP_POWER flag on suspend
  wl12xx: prevent scheduling while suspending (WoW enabled)
  wl12xx_sdio: declare support for NL80211_WOW_TRIGGER_ANYTHING trigger
  wl12xx: enter/exit psm on wowlan suspend/resume

 drivers/net/wireless/wl12xx/event.c  |    7 ++
 drivers/net/wireless/wl12xx/main.c   |  146 ++++++++++++++++++++++++++++++++++
 drivers/net/wireless/wl12xx/ps.h     |    2 +
 drivers/net/wireless/wl12xx/sdio.c   |   64 +++++++++++++++-
 drivers/net/wireless/wl12xx/wl12xx.h |    9 ++
 5 files changed, 227 insertions(+), 1 deletions(-)


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2 1/6] wl12xx_sdio: set interrupt as wake_up interrupt
  2011-05-13  8:57 [PATCH v2 0/6] wl12xx: add initial wowlan support Eliad Peller
@ 2011-05-13  8:57 ` Eliad Peller
  2011-05-13  8:57 ` [PATCH v2 2/6] wl12xx: declare suspend/resume callbacks (for wowlan) Eliad Peller
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Eliad Peller @ 2011-05-13  8:57 UTC (permalink / raw)
  To: Luciano Coelho; +Cc: linux-wireless

set the sdio interrupt as wake_up interrupt, so we will be able
to wake up the suspended system (Wake-On-Wireless)

Signed-off-by: Eliad Peller <eliad@wizery.com>
---
 drivers/net/wireless/wl12xx/sdio.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c
index bcd4ad7..1298461 100644
--- a/drivers/net/wireless/wl12xx/sdio.c
+++ b/drivers/net/wireless/wl12xx/sdio.c
@@ -267,6 +267,8 @@ static int __devinit wl1271_probe(struct sdio_func *func,
 		goto out_free;
 	}
 
+	enable_irq_wake(wl->irq);
+
 	disable_irq(wl->irq);
 
 	ret = wl1271_init_ieee80211(wl);
@@ -303,6 +305,7 @@ static void __devexit wl1271_remove(struct sdio_func *func)
 	pm_runtime_get_noresume(&func->dev);
 
 	wl1271_unregister_hw(wl);
+	disable_irq_wake(wl->irq);
 	free_irq(wl->irq, wl);
 	wl1271_free_hw(wl);
 }
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 2/6] wl12xx: declare suspend/resume callbacks (for wowlan)
  2011-05-13  8:57 [PATCH v2 0/6] wl12xx: add initial wowlan support Eliad Peller
  2011-05-13  8:57 ` [PATCH v2 1/6] wl12xx_sdio: set interrupt as wake_up interrupt Eliad Peller
@ 2011-05-13  8:57 ` Eliad Peller
  2011-05-13  8:57 ` [PATCH v2 3/6] wl12xx_sdio: set MMC_PM_KEEP_POWER flag on suspend Eliad Peller
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Eliad Peller @ 2011-05-13  8:57 UTC (permalink / raw)
  To: Luciano Coelho; +Cc: linux-wireless

Additionally, add wow_enabled field to wl, to indicate
whether wowlan was configured.

Signed-off-by: Eliad Peller <eliad@wizery.com>
---
 drivers/net/wireless/wl12xx/main.c   |   19 +++++++++++++++++++
 drivers/net/wireless/wl12xx/wl12xx.h |    6 ++++++
 2 files changed, 25 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index f82e736..9ca71ce 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -1332,6 +1332,23 @@ static struct notifier_block wl1271_dev_notifier = {
 	.notifier_call = wl1271_dev_notify,
 };
 
+static int wl1271_op_suspend(struct ieee80211_hw *hw,
+			    struct cfg80211_wowlan *wow)
+{
+	struct wl1271 *wl = hw->priv;
+	wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
+	wl->wow_enabled = !!wow;
+	return 0;
+}
+
+static int wl1271_op_resume(struct ieee80211_hw *hw)
+{
+	struct wl1271 *wl = hw->priv;
+	wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
+		     wl->wow_enabled);
+	return 0;
+}
+
 static int wl1271_op_start(struct ieee80211_hw *hw)
 {
 	wl1271_debug(DEBUG_MAC80211, "mac80211 start");
@@ -3426,6 +3443,8 @@ static const struct ieee80211_ops wl1271_ops = {
 	.stop = wl1271_op_stop,
 	.add_interface = wl1271_op_add_interface,
 	.remove_interface = wl1271_op_remove_interface,
+	.suspend = wl1271_op_suspend,
+	.resume = wl1271_op_resume,
 	.config = wl1271_op_config,
 	.prepare_multicast = wl1271_op_prepare_multicast,
 	.configure_filter = wl1271_op_configure_filter,
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index b760143..f9d0a14 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -564,6 +564,12 @@ struct wl1271 {
 	int tcxo_clock;
 
 	/*
+	 * wowlan trigger was configured during suspend.
+	 * (currently, only "ANY" trigger is supported)
+	 */
+	bool wow_enabled;
+
+	/*
 	 * AP-mode - links indexed by HLID. The global and broadcast links
 	 * are always active.
 	 */
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 3/6] wl12xx_sdio: set MMC_PM_KEEP_POWER flag on suspend
  2011-05-13  8:57 [PATCH v2 0/6] wl12xx: add initial wowlan support Eliad Peller
  2011-05-13  8:57 ` [PATCH v2 1/6] wl12xx_sdio: set interrupt as wake_up interrupt Eliad Peller
  2011-05-13  8:57 ` [PATCH v2 2/6] wl12xx: declare suspend/resume callbacks (for wowlan) Eliad Peller
@ 2011-05-13  8:57 ` Eliad Peller
  2011-05-13  8:57 ` [PATCH v2 4/6] wl12xx: prevent scheduling while suspending (WoW enabled) Eliad Peller
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Eliad Peller @ 2011-05-13  8:57 UTC (permalink / raw)
  To: Luciano Coelho; +Cc: linux-wireless

if a wow trigger was configured, set the MMC_PM_KEEP_POWER flag
on suspend, so our power will be kept while the system is suspended.

We needed to set this flag on each suspend attempt (when we want
to keep power)

Signed-off-by: Eliad Peller <eliad@wizery.com>
---
 drivers/net/wireless/wl12xx/sdio.c |   29 ++++++++++++++++++++++++++++-
 1 files changed, 28 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c
index 1298461..5b03fd5 100644
--- a/drivers/net/wireless/wl12xx/sdio.c
+++ b/drivers/net/wireless/wl12xx/sdio.c
@@ -314,7 +314,34 @@ static int wl1271_suspend(struct device *dev)
 {
 	/* Tell MMC/SDIO core it's OK to power down the card
 	 * (if it isn't already), but not to remove it completely */
-	return 0;
+	struct sdio_func *func = dev_to_sdio_func(dev);
+	struct wl1271 *wl = sdio_get_drvdata(func);
+	mmc_pm_flag_t sdio_flags;
+	int ret = 0;
+
+	wl1271_debug(DEBUG_MAC80211, "wl1271 suspend. wow_enabled: %d",
+		     wl->wow_enabled);
+
+	/* check whether sdio should keep power */
+	if (wl->wow_enabled) {
+		sdio_flags = sdio_get_host_pm_caps(func);
+
+		if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
+			wl1271_error("can't keep power while host "
+				     "is suspended");
+			ret = -EINVAL;
+			goto out;
+		}
+
+		/* keep power while host suspended */
+		ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+		if (ret) {
+			wl1271_error("error while trying to keep power");
+			goto out;
+		}
+	}
+out:
+	return ret;
 }
 
 static int wl1271_resume(struct device *dev)
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 4/6] wl12xx: prevent scheduling while suspending (WoW enabled)
  2011-05-13  8:57 [PATCH v2 0/6] wl12xx: add initial wowlan support Eliad Peller
                   ` (2 preceding siblings ...)
  2011-05-13  8:57 ` [PATCH v2 3/6] wl12xx_sdio: set MMC_PM_KEEP_POWER flag on suspend Eliad Peller
@ 2011-05-13  8:57 ` Eliad Peller
  2011-05-13  8:57 ` [PATCH v2 5/6] wl12xx_sdio: declare support for NL80211_WOW_TRIGGER_ANYTHING trigger Eliad Peller
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Eliad Peller @ 2011-05-13  8:57 UTC (permalink / raw)
  To: Luciano Coelho; +Cc: linux-wireless

When WoW is enabled, the interface will stay up and the chip will
be powered on, so we have to flush/cancel any remaining work, and
prevent the irq handler from scheduling a new work until the system
is resumed.

Add 2 new flags:
* WL1271_FLAG_SUSPENDED - the system is (about to be) suspended.
* WL1271_FLAG_PENDING_WORK - there is a pending irq work which
   should be scheduled when the system is being resumed.

In order to wake-up the system while getting an irq, we initialize
the device as wakeup device, and calling pm_wakeup_event() upon
getting the interrupt (while the system is about to be suspended)

Signed-off-by: Eliad Peller <eliad@wizery.com>
---
v1->v2:
	change wl1271_hardirq flow when returning IRQ_HANDLED

 drivers/net/wireless/wl12xx/main.c   |   46 ++++++++++++++++++++++++++++++++++
 drivers/net/wireless/wl12xx/sdio.c   |   24 +++++++++++++++++
 drivers/net/wireless/wl12xx/wl12xx.h |    2 +
 3 files changed, 72 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 9ca71ce..308855a 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -1338,6 +1338,28 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
 	struct wl1271 *wl = hw->priv;
 	wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
 	wl->wow_enabled = !!wow;
+	if (wl->wow_enabled) {
+		/* flush any remaining work */
+		wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
+		flush_delayed_work(&wl->scan_complete_work);
+
+		/*
+		 * disable and re-enable interrupts in order to flush
+		 * the threaded_irq
+		 */
+		wl1271_disable_interrupts(wl);
+
+		/*
+		 * set suspended flag to avoid triggering a new threaded_irq
+		 * work. no need for spinlock as interrupts are disabled.
+		 */
+		set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
+
+		wl1271_enable_interrupts(wl);
+		flush_work(&wl->tx_work);
+		flush_delayed_work(&wl->pspoll_work);
+		flush_delayed_work(&wl->elp_work);
+	}
 	return 0;
 }
 
@@ -1346,6 +1368,30 @@ static int wl1271_op_resume(struct ieee80211_hw *hw)
 	struct wl1271 *wl = hw->priv;
 	wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
 		     wl->wow_enabled);
+
+	/*
+	 * re-enable irq_work enqueuing, and call irq_work directly if
+	 * there is a pending work.
+	 */
+	if (wl->wow_enabled) {
+		struct wl1271 *wl = hw->priv;
+		unsigned long flags;
+		bool run_irq_work = false;
+
+		spin_lock_irqsave(&wl->wl_lock, flags);
+		clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
+		if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
+			run_irq_work = true;
+		spin_unlock_irqrestore(&wl->wl_lock, flags);
+
+		if (run_irq_work) {
+			wl1271_debug(DEBUG_MAC80211,
+				     "run postponed irq_work directly");
+			wl1271_irq(0, wl);
+			wl1271_enable_interrupts(wl);
+		}
+	}
+
 	return 0;
 }
 
diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c
index 5b03fd5..41183db 100644
--- a/drivers/net/wireless/wl12xx/sdio.c
+++ b/drivers/net/wireless/wl12xx/sdio.c
@@ -82,6 +82,16 @@ static irqreturn_t wl1271_hardirq(int irq, void *cookie)
 		complete(wl->elp_compl);
 		wl->elp_compl = NULL;
 	}
+
+	if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
+		/* don't enqueue a work right now. mark it as pending */
+		set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
+		wl1271_debug(DEBUG_IRQ, "should not enqueue work");
+		disable_irq_nosync(wl->irq);
+		pm_wakeup_event(wl1271_sdio_wl_to_dev(wl), 0);
+		spin_unlock_irqrestore(&wl->wl_lock, flags);
+		return IRQ_HANDLED;
+	}
 	spin_unlock_irqrestore(&wl->wl_lock, flags);
 
 	return IRQ_WAKE_THREAD;
@@ -268,6 +278,7 @@ static int __devinit wl1271_probe(struct sdio_func *func,
 	}
 
 	enable_irq_wake(wl->irq);
+	device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 1);
 
 	disable_irq(wl->irq);
 
@@ -305,6 +316,7 @@ static void __devexit wl1271_remove(struct sdio_func *func)
 	pm_runtime_get_noresume(&func->dev);
 
 	wl1271_unregister_hw(wl);
+	device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 0);
 	disable_irq_wake(wl->irq);
 	free_irq(wl->irq, wl);
 	wl1271_free_hw(wl);
@@ -339,6 +351,9 @@ static int wl1271_suspend(struct device *dev)
 			wl1271_error("error while trying to keep power");
 			goto out;
 		}
+
+		/* release host */
+		sdio_release_host(func);
 	}
 out:
 	return ret;
@@ -346,6 +361,15 @@ out:
 
 static int wl1271_resume(struct device *dev)
 {
+	struct sdio_func *func = dev_to_sdio_func(dev);
+	struct wl1271 *wl = sdio_get_drvdata(func);
+
+	wl1271_debug(DEBUG_MAC80211, "wl1271 resume");
+	if (wl->wow_enabled) {
+		/* claim back host */
+		sdio_claim_host(func);
+	}
+
 	return 0;
 }
 
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index f9d0a14..daf941d 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -358,6 +358,8 @@ enum wl12xx_flags {
 	WL1271_FLAG_AP_STARTED,
 	WL1271_FLAG_IF_INITIALIZED,
 	WL1271_FLAG_DUMMY_PACKET_PENDING,
+	WL1271_FLAG_SUSPENDED,
+	WL1271_FLAG_PENDING_WORK,
 };
 
 struct wl1271_link {
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 5/6] wl12xx_sdio: declare support for NL80211_WOW_TRIGGER_ANYTHING trigger
  2011-05-13  8:57 [PATCH v2 0/6] wl12xx: add initial wowlan support Eliad Peller
                   ` (3 preceding siblings ...)
  2011-05-13  8:57 ` [PATCH v2 4/6] wl12xx: prevent scheduling while suspending (WoW enabled) Eliad Peller
@ 2011-05-13  8:57 ` Eliad Peller
  2011-05-13  8:57 ` [PATCH v2 6/6] wl12xx: enter/exit psm on wowlan suspend/resume Eliad Peller
  2011-05-13 12:14 ` [PATCH v2 0/6] wl12xx: add initial wowlan support Luciano Coelho
  6 siblings, 0 replies; 8+ messages in thread
From: Eliad Peller @ 2011-05-13  8:57 UTC (permalink / raw)
  To: Luciano Coelho; +Cc: linux-wireless

Since wowlan requires the ability to stay awake while the host
is suspended, declare support for NL80211_WOW_TRIGGER_ANYTHING
if the MMC_PM_KEEP_POWER capability is being supported.

Signed-off-by: Eliad Peller <eliad@wizery.com>
---
 drivers/net/wireless/wl12xx/sdio.c |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c
index 41183db..92d29a8 100644
--- a/drivers/net/wireless/wl12xx/sdio.c
+++ b/drivers/net/wireless/wl12xx/sdio.c
@@ -231,6 +231,7 @@ static int __devinit wl1271_probe(struct sdio_func *func,
 	const struct wl12xx_platform_data *wlan_data;
 	struct wl1271 *wl;
 	unsigned long irqflags;
+	mmc_pm_flag_t mmcflags;
 	int ret;
 
 	/* We are only able to handle the wlan function */
@@ -282,6 +283,13 @@ static int __devinit wl1271_probe(struct sdio_func *func,
 
 	disable_irq(wl->irq);
 
+	/* if sdio can keep power while host is suspended, enable wow */
+	mmcflags = sdio_get_host_pm_caps(func);
+	wl1271_debug(DEBUG_SDIO, "sdio PM caps = 0x%x", mmcflags);
+
+	if (mmcflags & MMC_PM_KEEP_POWER)
+		hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
+
 	ret = wl1271_init_ieee80211(wl);
 	if (ret)
 		goto out_irq;
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 6/6] wl12xx: enter/exit psm on wowlan suspend/resume
  2011-05-13  8:57 [PATCH v2 0/6] wl12xx: add initial wowlan support Eliad Peller
                   ` (4 preceding siblings ...)
  2011-05-13  8:57 ` [PATCH v2 5/6] wl12xx_sdio: declare support for NL80211_WOW_TRIGGER_ANYTHING trigger Eliad Peller
@ 2011-05-13  8:57 ` Eliad Peller
  2011-05-13 12:14 ` [PATCH v2 0/6] wl12xx: add initial wowlan support Luciano Coelho
  6 siblings, 0 replies; 8+ messages in thread
From: Eliad Peller @ 2011-05-13  8:57 UTC (permalink / raw)
  To: Luciano Coelho; +Cc: linux-wireless

When operating as station, enter psm before suspending
the device into wowlan state.

Add a new completion event to signal when psm was entered
successfully.

Signed-off-by: Eliad Peller <eliad@wizery.com>
---
v1->v2:
	define WL1271_PS_COMPLETE_TIMEOUT

 drivers/net/wireless/wl12xx/event.c  |    7 +++
 drivers/net/wireless/wl12xx/main.c   |   81 ++++++++++++++++++++++++++++++++++
 drivers/net/wireless/wl12xx/ps.h     |    2 +
 drivers/net/wireless/wl12xx/wl12xx.h |    1 +
 4 files changed, 91 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c
index ae69330..21e52ed 100644
--- a/drivers/net/wireless/wl12xx/event.c
+++ b/drivers/net/wireless/wl12xx/event.c
@@ -135,6 +135,13 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
 
 		/* enable beacon early termination */
 		ret = wl1271_acx_bet_enable(wl, true);
+		if (ret < 0)
+			break;
+
+		if (wl->ps_compl) {
+			complete(wl->ps_compl);
+			wl->ps_compl = NULL;
+		}
 		break;
 	default:
 		break;
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 308855a..1de0963 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -1332,6 +1332,79 @@ static struct notifier_block wl1271_dev_notifier = {
 	.notifier_call = wl1271_dev_notify,
 };
 
+static int wl1271_configure_suspend(struct wl1271 *wl)
+{
+	int ret;
+
+	if (wl->bss_type != BSS_TYPE_STA_BSS)
+		return 0;
+
+	mutex_lock(&wl->mutex);
+
+	ret = wl1271_ps_elp_wakeup(wl);
+	if (ret < 0)
+		goto out_unlock;
+
+	/* enter psm if needed*/
+	if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
+		DECLARE_COMPLETION_ONSTACK(compl);
+
+		wl->ps_compl = &compl;
+		ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
+				   wl->basic_rate, true);
+		if (ret < 0)
+			goto out_sleep;
+
+		/* we must unlock here so we will be able to get events */
+		wl1271_ps_elp_sleep(wl);
+		mutex_unlock(&wl->mutex);
+
+		ret = wait_for_completion_timeout(
+			&compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
+		if (ret <= 0) {
+			wl1271_warning("couldn't enter ps mode!");
+			ret = -EBUSY;
+			goto out;
+		}
+
+		/* take mutex again, and wakeup */
+		mutex_lock(&wl->mutex);
+
+		ret = wl1271_ps_elp_wakeup(wl);
+		if (ret < 0)
+			goto out_unlock;
+	}
+out_sleep:
+	wl1271_ps_elp_sleep(wl);
+out_unlock:
+	mutex_unlock(&wl->mutex);
+out:
+	return ret;
+
+}
+
+static void wl1271_configure_resume(struct wl1271 *wl)
+{
+	int ret;
+
+	if (wl->bss_type != BSS_TYPE_STA_BSS)
+		return;
+
+	mutex_lock(&wl->mutex);
+	ret = wl1271_ps_elp_wakeup(wl);
+	if (ret < 0)
+		goto out;
+
+	/* exit psm if it wasn't configured */
+	if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
+		wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
+				   wl->basic_rate, true);
+
+	wl1271_ps_elp_sleep(wl);
+out:
+	mutex_unlock(&wl->mutex);
+}
+
 static int wl1271_op_suspend(struct ieee80211_hw *hw,
 			    struct cfg80211_wowlan *wow)
 {
@@ -1339,6 +1412,12 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
 	wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
 	wl->wow_enabled = !!wow;
 	if (wl->wow_enabled) {
+		int ret;
+		ret = wl1271_configure_suspend(wl);
+		if (ret < 0) {
+			wl1271_warning("couldn't prepare device to suspend");
+			return ret;
+		}
 		/* flush any remaining work */
 		wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
 		flush_delayed_work(&wl->scan_complete_work);
@@ -1390,6 +1469,8 @@ static int wl1271_op_resume(struct ieee80211_hw *hw)
 			wl1271_irq(0, wl);
 			wl1271_enable_interrupts(wl);
 		}
+
+		wl1271_configure_resume(wl);
 	}
 
 	return 0;
diff --git a/drivers/net/wireless/wl12xx/ps.h b/drivers/net/wireless/wl12xx/ps.h
index c41bd0a..25eb9bc 100644
--- a/drivers/net/wireless/wl12xx/ps.h
+++ b/drivers/net/wireless/wl12xx/ps.h
@@ -35,4 +35,6 @@ void wl1271_elp_work(struct work_struct *work);
 void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues);
 void wl1271_ps_link_end(struct wl1271 *wl, u8 hlid);
 
+#define WL1271_PS_COMPLETE_TIMEOUT 500
+
 #endif /* __WL1271_PS_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index daf941d..cf08a9d 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -512,6 +512,7 @@ struct wl1271 {
 	unsigned int rx_filter;
 
 	struct completion *elp_compl;
+	struct completion *ps_compl;
 	struct delayed_work elp_work;
 	struct delayed_work pspoll_work;
 
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 0/6] wl12xx: add initial wowlan support
  2011-05-13  8:57 [PATCH v2 0/6] wl12xx: add initial wowlan support Eliad Peller
                   ` (5 preceding siblings ...)
  2011-05-13  8:57 ` [PATCH v2 6/6] wl12xx: enter/exit psm on wowlan suspend/resume Eliad Peller
@ 2011-05-13 12:14 ` Luciano Coelho
  6 siblings, 0 replies; 8+ messages in thread
From: Luciano Coelho @ 2011-05-13 12:14 UTC (permalink / raw)
  To: Eliad Peller; +Cc: linux-wireless

On Fri, 2011-05-13 at 11:57 +0300, Eliad Peller wrote:
> Add initial support for Wake-On-Wireless.
> 
> Currently, we support only the ANY trigger, which basically means
> the device stays awake while the host is being suspended, and will
> wake up the host by any irq it will trigger (but since the wl12xx
> fw offloads a lot of its work, it will probably wake up the host
> because of rx frame/beacon loss)
> 
> Note that this patchset needs some additional omap/mmc patches in 
> order to support the MMC_PM_KEEP_POWER flag and wake-irq correctly
> (however, if the MMC_PM_KEEP_POWER flag is not being supported we 
> don't advertise support for wowlan triggers, so this patchset alone
> shouldn't harm).
> 
> Changes from v1:
> * reflow wl1271_hardirq (return immediately)
> * squash one patch 
> * define WL1271_PS_COMPLETE_TIMEOUT
> 
> Eliad Peller (6):
>   wl12xx_sdio: set interrupt as wake_up interrupt
>   wl12xx: declare suspend/resume callbacks (for wowlan)
>   wl12xx_sdio: set MMC_PM_KEEP_POWER flag on suspend
>   wl12xx: prevent scheduling while suspending (WoW enabled)
>   wl12xx_sdio: declare support for NL80211_WOW_TRIGGER_ANYTHING trigger
>   wl12xx: enter/exit psm on wowlan suspend/resume
> 
>  drivers/net/wireless/wl12xx/event.c  |    7 ++
>  drivers/net/wireless/wl12xx/main.c   |  146 ++++++++++++++++++++++++++++++++++
>  drivers/net/wireless/wl12xx/ps.h     |    2 +
>  drivers/net/wireless/wl12xx/sdio.c   |   64 +++++++++++++++-
>  drivers/net/wireless/wl12xx/wl12xx.h |    9 ++
>  5 files changed, 227 insertions(+), 1 deletions(-)

Applied the series.  Thank you!

-- 
Cheers,
Luca.


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2011-05-13 12:14 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-05-13  8:57 [PATCH v2 0/6] wl12xx: add initial wowlan support Eliad Peller
2011-05-13  8:57 ` [PATCH v2 1/6] wl12xx_sdio: set interrupt as wake_up interrupt Eliad Peller
2011-05-13  8:57 ` [PATCH v2 2/6] wl12xx: declare suspend/resume callbacks (for wowlan) Eliad Peller
2011-05-13  8:57 ` [PATCH v2 3/6] wl12xx_sdio: set MMC_PM_KEEP_POWER flag on suspend Eliad Peller
2011-05-13  8:57 ` [PATCH v2 4/6] wl12xx: prevent scheduling while suspending (WoW enabled) Eliad Peller
2011-05-13  8:57 ` [PATCH v2 5/6] wl12xx_sdio: declare support for NL80211_WOW_TRIGGER_ANYTHING trigger Eliad Peller
2011-05-13  8:57 ` [PATCH v2 6/6] wl12xx: enter/exit psm on wowlan suspend/resume Eliad Peller
2011-05-13 12:14 ` [PATCH v2 0/6] wl12xx: add initial wowlan support Luciano Coelho

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).