All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 0/5] mac80211 suspend cleanups/helpers
@ 2009-05-11  9:24 Luis R. Rodriguez
  2009-05-11  9:25 ` [RFC 1/5] ath9k: do not stop the queues in driver stop Luis R. Rodriguez
                   ` (4 more replies)
  0 siblings, 5 replies; 16+ messages in thread
From: Luis R. Rodriguez @ 2009-05-11  9:24 UTC (permalink / raw)
  To: johannes, linux-wireless; +Cc: Luis R. Rodriguez

The first two are probably patch ready but it'd be nice if someone can
test adm8211. The rest are stuff to be able to use WoW. This still
doesn't add the driver APIs for WoW but it at least lets us pass information
during suspend so we can be aware of what to do internally.

The ath9k WoW stuff now has the device stuff for sleep. We also enable
link and beacon miss events as otherwise you won't be able to remotely
wake the device up if you can't talk to it. I still have no luck, will
try tomorrow with some other cards.

Luis R. Rodriguez (5):
  ath9k: do not stop the queues in driver stop
  adm8211: remove uneeded code during suspend/resume
  mac80211: fix idle trigger upon resume
  mac80211: add a struct for info upon device stop
  ath9k: Add Wake-on-Wireless-LAN support

 drivers/net/wireless/adm8211.c              |   14 +-
 drivers/net/wireless/at76c50x-usb.c         |    3 +-
 drivers/net/wireless/ath/ar9170/main.c      |    3 +-
 drivers/net/wireless/ath/ath5k/base.c       |    6 +-
 drivers/net/wireless/ath/ath9k/Makefile     |    1 +
 drivers/net/wireless/ath/ath9k/ath9k.h      |   19 +
 drivers/net/wireless/ath/ath9k/debug.c      |   51 +++
 drivers/net/wireless/ath/ath9k/debug.h      |    4 +
 drivers/net/wireless/ath/ath9k/hw.c         |   22 ++
 drivers/net/wireless/ath/ath9k/hw.h         |   21 +
 drivers/net/wireless/ath/ath9k/initvals.h   |   31 ++
 drivers/net/wireless/ath/ath9k/main.c       |   26 ++-
 drivers/net/wireless/ath/ath9k/pci.c        |   87 +++++
 drivers/net/wireless/ath/ath9k/reg.h        |  154 ++++++++
 drivers/net/wireless/ath/ath9k/wow.c        |  543 +++++++++++++++++++++++++++
 drivers/net/wireless/b43/main.c             |    3 +-
 drivers/net/wireless/b43legacy/main.c       |    3 +-
 drivers/net/wireless/iwlwifi/iwl-agn.c      |    3 +-
 drivers/net/wireless/iwlwifi/iwl3945-base.c |    3 +-
 drivers/net/wireless/libertas_tf/main.c     |    3 +-
 drivers/net/wireless/mac80211_hwsim.c       |    3 +-
 drivers/net/wireless/mwl8k.c                |    3 +-
 drivers/net/wireless/p54/p54common.c        |    3 +-
 drivers/net/wireless/rt2x00/rt2x00.h        |    3 +-
 drivers/net/wireless/rt2x00/rt2x00mac.c     |    3 +-
 drivers/net/wireless/rtl818x/rtl8180_dev.c  |    3 +-
 drivers/net/wireless/rtl818x/rtl8187_dev.c  |    3 +-
 drivers/net/wireless/wl12xx/main.c          |    3 +-
 drivers/net/wireless/zd1211rw/zd_mac.c      |    3 +-
 include/net/mac80211.h                      |   39 ++-
 net/mac80211/driver-ops.h                   |    5 +-
 net/mac80211/ieee80211_i.h                  |    2 +
 net/mac80211/iface.c                        |   23 +-
 net/mac80211/pm.c                           |    4 +-
 net/mac80211/util.c                         |   39 ++
 35 files changed, 1093 insertions(+), 46 deletions(-)
 create mode 100644 drivers/net/wireless/ath/ath9k/wow.c


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

* [RFC 1/5] ath9k: do not stop the queues in driver stop
  2009-05-11  9:24 [RFC 0/5] mac80211 suspend cleanups/helpers Luis R. Rodriguez
@ 2009-05-11  9:25 ` Luis R. Rodriguez
  2009-05-11  9:25 ` [RFC 2/5] adm8211: remove uneeded code during suspend/resume Luis R. Rodriguez
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 16+ messages in thread
From: Luis R. Rodriguez @ 2009-05-11  9:25 UTC (permalink / raw)
  To: johannes, linux-wireless; +Cc: Luis R. Rodriguez

mac80211 will have disabled the queues for us when
needed.

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 drivers/net/wireless/ath/ath9k/main.c |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index bbbfdcd..4fe0f8a 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -2132,8 +2132,6 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 
 	mutex_lock(&sc->mutex);
 
-	ieee80211_stop_queues(hw);
-
 	if (ath9k_wiphy_started(sc)) {
 		mutex_unlock(&sc->mutex);
 		return; /* another wiphy still in use */
-- 
1.6.0.6


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

* [RFC 2/5] adm8211: remove uneeded code during suspend/resume
  2009-05-11  9:24 [RFC 0/5] mac80211 suspend cleanups/helpers Luis R. Rodriguez
  2009-05-11  9:25 ` [RFC 1/5] ath9k: do not stop the queues in driver stop Luis R. Rodriguez
@ 2009-05-11  9:25 ` Luis R. Rodriguez
  2009-05-11  9:25 ` [RFC 3/5] mac80211: fix idle trigger upon resume Luis R. Rodriguez
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 16+ messages in thread
From: Luis R. Rodriguez @ 2009-05-11  9:25 UTC (permalink / raw)
  To: johannes, linux-wireless; +Cc: Luis R. Rodriguez

mac80211 drivers do not need to stop the software queues
or call their own stop() callback upon suspend as we do it
for drivers. Equally drivers don't have to call their own
start() or start the queues as mac80211 will do it for us.

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 drivers/net/wireless/adm8211.c |   11 -----------
 1 files changed, 0 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index 2b9e379..316df03 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -1964,12 +1964,6 @@ static void __devexit adm8211_remove(struct pci_dev *pdev)
 static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct ieee80211_hw *dev = pci_get_drvdata(pdev);
-	struct adm8211_priv *priv = dev->priv;
-
-	if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) {
-		ieee80211_stop_queues(dev);
-		adm8211_stop(dev);
-	}
 
 	pci_save_state(pdev);
 	pci_set_power_state(pdev, pci_choose_state(pdev, state));
@@ -1984,11 +1978,6 @@ static int adm8211_resume(struct pci_dev *pdev)
 	pci_set_power_state(pdev, PCI_D0);
 	pci_restore_state(pdev);
 
-	if (priv->mode != NL80211_IFTYPE_UNSPECIFIED) {
-		adm8211_start(dev);
-		ieee80211_wake_queues(dev);
-	}
-
 	return 0;
 }
 #endif /* CONFIG_PM */
-- 
1.6.0.6


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

* [RFC 3/5] mac80211: fix idle trigger upon resume
  2009-05-11  9:24 [RFC 0/5] mac80211 suspend cleanups/helpers Luis R. Rodriguez
  2009-05-11  9:25 ` [RFC 1/5] ath9k: do not stop the queues in driver stop Luis R. Rodriguez
  2009-05-11  9:25 ` [RFC 2/5] adm8211: remove uneeded code during suspend/resume Luis R. Rodriguez
@ 2009-05-11  9:25 ` Luis R. Rodriguez
  2009-05-11 10:01   ` Johannes Berg
  2009-05-11  9:25 ` [RFC 4/5] mac80211: add a struct for info upon device stop Luis R. Rodriguez
  2009-05-11  9:25 ` [RFC 5/5] ath9k: Add Wake-on-Wireless-LAN support Luis R. Rodriguez
  4 siblings, 1 reply; 16+ messages in thread
From: Luis R. Rodriguez @ 2009-05-11  9:25 UTC (permalink / raw)
  To: johannes, linux-wireless; +Cc: Luis R. Rodriguez

When we suspend we stop the queues, then upon resume
the new idle checks will immediately pick up we're
idle and ask call our driver's config callback. At
this point its pointless to to call this callback
as we haven't yet come back from suspend. We avoid
then making assumptions about being idle until we know
we've come back from suspend. We do this by checking
the reason stop on all our queues.

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 net/mac80211/ieee80211_i.h |    2 ++
 net/mac80211/iface.c       |    5 +++++
 net/mac80211/util.c        |   39 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 46 insertions(+), 0 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 03e0d22..b8f3013 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1099,6 +1099,8 @@ void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
 				    enum queue_stop_reason reason);
 void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
 				    enum queue_stop_reason reason);
+bool ieee80211_any_queues_stopped_by_reason(struct ieee80211_hw *hw,
+					    enum queue_stop_reason reason);
 
 void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
 			 u16 transaction, u16 auth_alg,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 8c9f1c7..f8eefad 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -931,6 +931,11 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
 	struct ieee80211_sub_if_data *sdata;
 	int count = 0;
 
+	/* allow resume to finish before we make any assumptions */
+	if (ieee80211_any_queues_stopped_by_reason(&local->hw,
+				IEEE80211_QUEUE_STOP_REASON_SUSPEND))
+		return 0;
+
 	if (local->hw_scanning || local->sw_scanning)
 		return ieee80211_idle_off(local, "scanning");
 
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 97b613a..3f82d51 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -447,6 +447,45 @@ int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue)
 }
 EXPORT_SYMBOL(ieee80211_queue_stopped);
 
+static bool __ieee80211_queues_stopped_by_reason(struct ieee80211_hw *hw,
+						 int queue,
+						 enum queue_stop_reason reason)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+
+	if (WARN_ON(queue >= hw->queues))
+		return false;
+
+	if (!local->queue_stop_reasons[queue])
+		return false;
+
+	if (test_bit(reason, &local->queue_stop_reasons[queue]))
+		return true;
+
+	return false;
+}
+
+bool ieee80211_any_queues_stopped_by_reason(struct ieee80211_hw *hw,
+					    enum queue_stop_reason reason)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	unsigned long flags;
+	unsigned int i;
+	bool queue_match = false;
+
+	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+
+	for (i = 0; i < hw->queues; i++) {
+		if (__ieee80211_queues_stopped_by_reason(hw, i, reason))
+			queue_match = true;
+	}
+
+	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+	return queue_match;
+}
+EXPORT_SYMBOL(ieee80211_any_queues_stopped_by_reason);
+
+
 void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
 				     enum queue_stop_reason reason)
 {
-- 
1.6.0.6


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

* [RFC 4/5] mac80211: add a struct for info upon device stop
  2009-05-11  9:24 [RFC 0/5] mac80211 suspend cleanups/helpers Luis R. Rodriguez
                   ` (2 preceding siblings ...)
  2009-05-11  9:25 ` [RFC 3/5] mac80211: fix idle trigger upon resume Luis R. Rodriguez
@ 2009-05-11  9:25 ` Luis R. Rodriguez
  2009-05-11  9:53   ` Johannes Berg
  2009-05-11  9:25 ` [RFC 5/5] ath9k: Add Wake-on-Wireless-LAN support Luis R. Rodriguez
  4 siblings, 1 reply; 16+ messages in thread
From: Luis R. Rodriguez @ 2009-05-11  9:25 UTC (permalink / raw)
  To: johannes, linux-wireless; +Cc: Luis R. Rodriguez

This allows us to stuff information to give to the driver
for stoping the device. This will come more in handy later
when we add WoW support.

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 drivers/net/wireless/adm8211.c              |    3 +-
 drivers/net/wireless/at76c50x-usb.c         |    3 +-
 drivers/net/wireless/ath/ar9170/main.c      |    3 +-
 drivers/net/wireless/ath/ath5k/base.c       |    6 +++-
 drivers/net/wireless/ath/ath9k/main.c       |    3 +-
 drivers/net/wireless/b43/main.c             |    3 +-
 drivers/net/wireless/b43legacy/main.c       |    3 +-
 drivers/net/wireless/iwlwifi/iwl-agn.c      |    3 +-
 drivers/net/wireless/iwlwifi/iwl3945-base.c |    3 +-
 drivers/net/wireless/libertas_tf/main.c     |    3 +-
 drivers/net/wireless/mac80211_hwsim.c       |    3 +-
 drivers/net/wireless/mwl8k.c                |    3 +-
 drivers/net/wireless/p54/p54common.c        |    3 +-
 drivers/net/wireless/rt2x00/rt2x00.h        |    3 +-
 drivers/net/wireless/rt2x00/rt2x00mac.c     |    3 +-
 drivers/net/wireless/rtl818x/rtl8180_dev.c  |    3 +-
 drivers/net/wireless/rtl818x/rtl8187_dev.c  |    3 +-
 drivers/net/wireless/wl12xx/main.c          |    3 +-
 drivers/net/wireless/zd1211rw/zd_mac.c      |    3 +-
 include/net/mac80211.h                      |   39 +++++++++++++++++++++++---
 net/mac80211/driver-ops.h                   |    5 ++-
 net/mac80211/iface.c                        |   18 +++++++++---
 net/mac80211/pm.c                           |    4 ++-
 23 files changed, 93 insertions(+), 33 deletions(-)

diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index 316df03..2efe158 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -1546,7 +1546,8 @@ fail:
 	return retval;
 }
 
-static void adm8211_stop(struct ieee80211_hw *dev)
+static void adm8211_stop(struct ieee80211_hw *dev,
+			 struct ieee80211_device_stop_info *stop_info)
 {
 	struct adm8211_priv *priv = dev->priv;
 
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index e3caeef..54d71c6 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -1766,7 +1766,8 @@ error:
 	return 0;
 }
 
-static void at76_mac80211_stop(struct ieee80211_hw *hw)
+static void at76_mac80211_stop(struct ieee80211_hw *hw,
+			       struct ieee80211_device_stop_info *stop_info)
 {
 	struct at76_priv *priv = hw->priv;
 
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c
index 4ef1d2f..f87546d 100644
--- a/drivers/net/wireless/ath/ar9170/main.c
+++ b/drivers/net/wireless/ath/ar9170/main.c
@@ -1003,7 +1003,8 @@ out:
 	return err;
 }
 
-static void ar9170_op_stop(struct ieee80211_hw *hw)
+static void ar9170_op_stop(struct ieee80211_hw *hw,
+			   struct ieee80211_device_stop_info *stop_info)
 {
 	struct ar9170 *ar = hw->priv;
 
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 6789c5d..ef2563c 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -221,7 +221,8 @@ static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
 static int ath5k_reset(struct ath5k_softc *sc, bool stop, bool change_channel);
 static int ath5k_reset_wake(struct ath5k_softc *sc);
 static int ath5k_start(struct ieee80211_hw *hw);
-static void ath5k_stop(struct ieee80211_hw *hw);
+static void ath5k_stop(struct ieee80211_hw *hw,
+		       struct ieee80211_device_stop_info *stop_info);
 static int ath5k_add_interface(struct ieee80211_hw *hw,
 		struct ieee80211_if_init_conf *conf);
 static void ath5k_remove_interface(struct ieee80211_hw *hw,
@@ -2696,7 +2697,8 @@ static int ath5k_start(struct ieee80211_hw *hw)
 	return ath5k_init(hw->priv);
 }
 
-static void ath5k_stop(struct ieee80211_hw *hw)
+static void ath5k_stop(struct ieee80211_hw *hw,
+		       struct ieee80211_device_stop_info *stop_info)
 {
 	ath5k_stop_hw(hw->priv);
 }
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 4fe0f8a..23a3a4c 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -2118,7 +2118,8 @@ exit:
 	return 0;
 }
 
-static void ath9k_stop(struct ieee80211_hw *hw)
+static void ath9k_stop(struct ieee80211_hw *hw,
+		       struct ieee80211_device_stop_info *stop_info)
 {
 	struct ath_wiphy *aphy = hw->priv;
 	struct ath_softc *sc = aphy->sc;
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 2615aaf..ffe0bf0 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -4348,7 +4348,8 @@ static int b43_op_start(struct ieee80211_hw *hw)
 	return err;
 }
 
-static void b43_op_stop(struct ieee80211_hw *hw)
+static void b43_op_stop(struct ieee80211_hw *hw,
+			struct ieee80211_device_stop_info *stop_info)
 {
 	struct b43_wl *wl = hw_to_b43_wl(hw);
 	struct b43_wldev *dev = wl->current_dev;
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 07c7898..3ac73c5 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -3514,7 +3514,8 @@ out_mutex_unlock:
 	return err;
 }
 
-static void b43legacy_op_stop(struct ieee80211_hw *hw)
+static void b43legacy_op_stop(struct ieee80211_hw *hw,
+			      struct ieee80211_device_stop_info *stop_info)
 {
 	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
 	struct b43legacy_wldev *dev = wl->current_dev;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 6cdee0b..4355812 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -2001,7 +2001,8 @@ out:
 	return 0;
 }
 
-static void iwl_mac_stop(struct ieee80211_hw *hw)
+static void iwl_mac_stop(struct ieee80211_hw *hw,
+			 struct ieee80211_device_stop_info *stop_info)
 {
 	struct iwl_priv *priv = hw->priv;
 
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index f6c1489..ad002e6 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -3411,7 +3411,8 @@ out_release_irq:
 	return ret;
 }
 
-static void iwl3945_mac_stop(struct ieee80211_hw *hw)
+static void iwl3945_mac_stop(struct ieee80211_hw *hw,
+			     struct ieee80211_device_stop_info *stop_info)
 {
 	struct iwl_priv *priv = hw->priv;
 
diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c
index 10a99e2..d3db5ca 100644
--- a/drivers/net/wireless/libertas_tf/main.c
+++ b/drivers/net/wireless/libertas_tf/main.c
@@ -291,7 +291,8 @@ err_prog_firmware:
 	return ret;
 }
 
-static void lbtf_op_stop(struct ieee80211_hw *hw)
+static void lbtf_op_stop(struct ieee80211_hw *hw,
+			 struct ieee80211_device_stop_info *stop_info)
 {
 	struct lbtf_private *priv = hw->priv;
 	unsigned long flags;
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index b1213b6..2c191fa 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -477,7 +477,8 @@ static int mac80211_hwsim_start(struct ieee80211_hw *hw)
 }
 
 
-static void mac80211_hwsim_stop(struct ieee80211_hw *hw)
+static void mac80211_hwsim_stop(struct ieee80211_hw *hw,
+				struct ieee80211_device_stop_info *stop_info)
 {
 	struct mac80211_hwsim_data *data = hw->priv;
 	data->started = 0;
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 46b288d..303b952 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -2916,7 +2916,8 @@ static int mwl8k_stop_wt(struct work_struct *wt)
 	return rc;
 }
 
-static void mwl8k_stop(struct ieee80211_hw *hw)
+static void mwl8k_stop(struct ieee80211_hw *hw,
+		       struct ieee80211_device_stop_info *stop_info)
 {
 	int rc;
 	struct mwl8k_stop_worker *worker;
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
index 48d81d9..67d4483 100644
--- a/drivers/net/wireless/p54/p54common.c
+++ b/drivers/net/wireless/p54/p54common.c
@@ -2087,7 +2087,8 @@ out:
 	return err;
 }
 
-static void p54_stop(struct ieee80211_hw *dev)
+static void p54_stop(struct ieee80211_hw *dev,
+		     struct ieee80211_device_stop_info *stop_info)
 {
 	struct p54_common *priv = dev->priv;
 	struct sk_buff *skb;
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 419b1b9..db7d61f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -958,7 +958,8 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev,
  */
 int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
 int rt2x00mac_start(struct ieee80211_hw *hw);
-void rt2x00mac_stop(struct ieee80211_hw *hw);
+void rt2x00mac_stop(struct ieee80211_hw *hw,
+		    struct ieee80211_device_stop_info *stop_info);
 int rt2x00mac_add_interface(struct ieee80211_hw *hw,
 			    struct ieee80211_if_init_conf *conf);
 void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index c4c06b4..e9f4c3a 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -178,7 +178,8 @@ int rt2x00mac_start(struct ieee80211_hw *hw)
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_start);
 
-void rt2x00mac_stop(struct ieee80211_hw *hw)
+void rt2x00mac_stop(struct ieee80211_hw *hw,
+		    struct ieee80211_device_stop_info *stop_info)
 {
 	struct rt2x00_dev *rt2x00dev = hw->priv;
 
diff --git a/drivers/net/wireless/rtl818x/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c
index 7e65d7c..d84a597 100644
--- a/drivers/net/wireless/rtl818x/rtl8180_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c
@@ -627,7 +627,8 @@ static int rtl8180_start(struct ieee80211_hw *dev)
 	return ret;
 }
 
-static void rtl8180_stop(struct ieee80211_hw *dev)
+static void rtl8180_stop(struct ieee80211_hw *dev,
+			 struct ieee80211_device_stop_info *stop_info)
 {
 	struct rtl8180_priv *priv = dev->priv;
 	u8 reg;
diff --git a/drivers/net/wireless/rtl818x/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c
index 158827e..62a462c 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c
@@ -991,7 +991,8 @@ static int rtl8187_start(struct ieee80211_hw *dev)
 	return 0;
 }
 
-static void rtl8187_stop(struct ieee80211_hw *dev)
+static void rtl8187_stop(struct ieee80211_hw *dev,
+			 struct ieee80211_device_stop_info *stop_info)
 {
 	struct rtl8187_priv *priv = dev->priv;
 	struct sk_buff *skb;
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 603d611..971794b 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -363,7 +363,8 @@ out:
 	return ret;
 }
 
-static void wl12xx_op_stop(struct ieee80211_hw *hw)
+static void wl12xx_op_stop(struct ieee80211_hw *hw,
+			   struct ieee80211_device_stop_info *stop_info)
 {
 	struct wl12xx *wl = hw->priv;
 
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 6bdb170..db3d894 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -256,7 +256,8 @@ out:
 	return r;
 }
 
-static void zd_op_stop(struct ieee80211_hw *hw)
+static void zd_op_stop(struct ieee80211_hw *hw,
+		       struct ieee80211_device_stop_info *stop_info)
 {
 	struct zd_mac *mac = zd_hw_mac(hw);
 	struct zd_chip *chip = &mac->chip;
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 38dc1cd..d7460a4 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1291,6 +1291,31 @@ enum ieee80211_ampdu_mlme_action {
 };
 
 /**
+ * enum ieee80211_device_stop_reason - device stop reasons
+ *
+ * These are reasons why mac80211 would call the driver's stop()
+ * callback. Devices should probably not care other than when
+ * we call to stop during suspend, in these cases the device may
+ * want to leave the radio on for WoW events for example.
+ * @IEEE80211_DEV_STOP_INVALID_MAC: invalid mac address was detected for device
+ * @IEEE80211_DEV_STOP_NO_OPEN_DEV: we were not able to open any
+	netdevice for the current wireless device during user initialization.
+ * @IEEE80211_DEV_STOP_DEV_CLOSE_REQUEST: user requested the device to be
+ *	closed.
+ * @IEEE80211_DEV_STOP_SUSPEND: we are going to suspend
+ */
+enum ieee80211_device_stop_reasons {
+	IEEE80211_DEV_STOP_INVALID_MAC,
+	IEEE80211_DEV_STOP_NO_OPEN_DEV,
+	IEEE80211_DEV_STOP_DEV_CLOSE_REQUEST,
+	IEEE80211_DEV_STOP_SUSPEND,
+};
+
+struct ieee80211_device_stop_info {
+	enum ieee80211_device_stop_reasons reason;
+};
+
+/**
  * struct ieee80211_ops - callbacks from mac80211 to the driver
  *
  * This structure contains various callbacks that the driver may
@@ -1318,10 +1343,13 @@ enum ieee80211_ampdu_mlme_action {
  *	Must be implemented.
  *
  * @stop: Called after last netdevice attached to the hardware
- *	is disabled. This should turn off the hardware (at least
- *	it must turn off frame reception.)
- *	May be called right after add_interface if that rejects
- *	an interface.
+ *	is disabled or during suspend. This should turn off the
+ *	hardware (at least it must turn off frame reception) unless
+ *	the device wants to enable Wake-on-Wireless-LAN.
+ *	This may be called right after add_interface if that rejects
+ *	an interface. To assist drivers we provide stop detail
+ *	information through &struct ieee80211_device_stop_info. This
+ *	will help later for WoW support.
  *	Must be implemented.
  *
  * @add_interface: Called when a netdevice attached to the hardware is
@@ -1443,7 +1471,8 @@ enum ieee80211_ampdu_mlme_action {
 struct ieee80211_ops {
 	int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
 	int (*start)(struct ieee80211_hw *hw);
-	void (*stop)(struct ieee80211_hw *hw);
+	void (*stop)(struct ieee80211_hw *hw,
+		     struct ieee80211_device_stop_info *stop_info);
 	int (*add_interface)(struct ieee80211_hw *hw,
 			     struct ieee80211_if_init_conf *conf);
 	void (*remove_interface)(struct ieee80211_hw *hw,
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 3912b53..3864353 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -14,9 +14,10 @@ static inline int drv_start(struct ieee80211_local *local)
 	return local->ops->start(&local->hw);
 }
 
-static inline void drv_stop(struct ieee80211_local *local)
+static inline void drv_stop(struct ieee80211_local *local,
+			    struct ieee80211_device_stop_info *stop_info)
 {
-	local->ops->stop(&local->hw);
+	local->ops->stop(&local->hw, stop_info);
 }
 
 static inline int drv_add_interface(struct ieee80211_local *local,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index f8eefad..54d9b91 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -81,6 +81,7 @@ static int ieee80211_open(struct net_device *dev)
 	struct ieee80211_local *local = sdata->local;
 	struct sta_info *sta;
 	struct ieee80211_if_init_conf conf;
+	struct ieee80211_device_stop_info stop_info;
 	u32 changed = 0;
 	int res;
 	u32 hw_reconf_flags = 0;
@@ -198,8 +199,10 @@ static int ieee80211_open(struct net_device *dev)
 	 * Validate the MAC address for this device.
 	 */
 	if (!is_valid_ether_addr(dev->dev_addr)) {
-		if (!local->open_count)
-			drv_stop(local);
+		if (!local->open_count) {
+			stop_info.reason = IEEE80211_DEV_STOP_INVALID_MAC;
+			drv_stop(local, &stop_info);
+		}
 		return -EADDRNOTAVAIL;
 	}
 
@@ -331,8 +334,10 @@ static int ieee80211_open(struct net_device *dev)
  err_del_interface:
 	drv_remove_interface(local, &conf);
  err_stop:
-	if (!local->open_count)
-		drv_stop(local);
+	if (!local->open_count) {
+		stop_info.reason = IEEE80211_DEV_STOP_NO_OPEN_DEV;
+		drv_stop(local, &stop_info);
+	}
  err_del_bss:
 	sdata->bss = NULL;
 	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
@@ -555,10 +560,13 @@ static int ieee80211_stop(struct net_device *dev)
 	ieee80211_recalc_ps(local, -1);
 
 	if (local->open_count == 0) {
+		struct ieee80211_device_stop_info stop_info;
+
 		if (netif_running(local->mdev))
 			dev_close(local->mdev);
 
-		drv_stop(local);
+		stop_info.reason = IEEE80211_DEV_STOP_DEV_CLOSE_REQUEST;
+		drv_stop(local, &stop_info);
 
 		ieee80211_led_radio(local, 0);
 
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index 9d3d89a..24aa109 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -67,8 +67,10 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
 
 	/* stop hardware */
 	if (local->open_count) {
+		struct ieee80211_device_stop_info stop_info;
 		ieee80211_led_radio(local, false);
-		drv_stop(local);
+		stop_info.reason = IEEE80211_DEV_STOP_SUSPEND;
+		drv_stop(local, &stop_info);
 	}
 	return 0;
 }
-- 
1.6.0.6


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

* [RFC 5/5] ath9k: Add Wake-on-Wireless-LAN support
  2009-05-11  9:24 [RFC 0/5] mac80211 suspend cleanups/helpers Luis R. Rodriguez
                   ` (3 preceding siblings ...)
  2009-05-11  9:25 ` [RFC 4/5] mac80211: add a struct for info upon device stop Luis R. Rodriguez
@ 2009-05-11  9:25 ` Luis R. Rodriguez
  4 siblings, 0 replies; 16+ messages in thread
From: Luis R. Rodriguez @ 2009-05-11  9:25 UTC (permalink / raw)
  To: johannes, linux-wireless; +Cc: Luis R. Rodriguez

This adds WoWLAN suppport for ath9k. We support this initially
through debugfs. Once this gets proper testing we can move it
through proper driver APIs. We start by enabling only magic
packet WoWLAN.

You can use regular ethernet Wake-on-LAN applications to trigger
a WoWLAN event.

Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
---
 drivers/net/wireless/ath/ath9k/Makefile   |    1 +
 drivers/net/wireless/ath/ath9k/ath9k.h    |   19 +
 drivers/net/wireless/ath/ath9k/debug.c    |   51 +++
 drivers/net/wireless/ath/ath9k/debug.h    |    4 +
 drivers/net/wireless/ath/ath9k/hw.c       |   22 ++
 drivers/net/wireless/ath/ath9k/hw.h       |   21 ++
 drivers/net/wireless/ath/ath9k/initvals.h |   31 ++
 drivers/net/wireless/ath/ath9k/main.c     |   21 ++
 drivers/net/wireless/ath/ath9k/pci.c      |   87 +++++
 drivers/net/wireless/ath/ath9k/reg.h      |  154 ++++++++
 drivers/net/wireless/ath/ath9k/wow.c      |  543 +++++++++++++++++++++++++++++
 11 files changed, 954 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/wireless/ath/ath9k/wow.c

diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index 783bc39..d4a598d 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -14,5 +14,6 @@ ath9k-y +=	hw.o \
 ath9k-$(CONFIG_PCI) += pci.o
 ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o
 ath9k-$(CONFIG_ATH9K_DEBUG) += debug.o
+ath9k-$(CONFIG_PM) += wow.o
 
 obj-$(CONFIG_ATH9K) += ath9k.o
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 79a167c..b386b27 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -599,12 +599,31 @@ struct ath_softc {
 	struct ath_rfkill rf_kill;
 	struct ath_ani ani;
 	struct ath9k_node_stats nodestats;
+#ifdef CONFIG_PM
+	bool wow_enable;
+	bool wow_asleep;
+	bool wow_got_bmiss_intr;
+	bool wow_sleep_proc_intr;
+	u32 wow_intr_before_sleep;
+#endif
 #ifdef CONFIG_ATH9K_DEBUG
 	struct ath9k_debug debug;
 #endif
 	struct ath_bus_ops *bus_ops;
 };
 
+#ifdef CONFIG_PM
+/*
+ * WoW trigger types
+ */
+#define AH_WOW_USER_PATTERN_EN		0x1
+#define AH_WOW_MAGIC_PATTERN_EN		0x2
+#define AH_WOW_LINK_CHANGE		0x4
+#define AH_WOW_BEACON_MISS		0x8
+#define AH_WOW_MAX_EVENTS		4
+
+#endif
+
 struct ath_wiphy {
 	struct ath_softc *sc; /* shared for all virtual wiphys */
 	struct ieee80211_hw *hw;
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 97df20c..86d7d56 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -493,6 +493,45 @@ static const struct file_operations fops_wiphy = {
 	.owner = THIS_MODULE
 };
 
+#ifdef CONFIG_PM
+static ssize_t read_file_wow_enable(struct file *file,
+				    char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	char buf[3];
+	int res;
+
+	res = scnprintf(buf, 3, "%c\n", sc->wow_enable ? '1' : '0');
+	return simple_read_from_buffer(userbuf, count, ppos, buf, res);
+}
+
+static ssize_t write_file_wow_enable(struct file *file,
+				     const char __user *user_buf,
+				     size_t count, loff_t *ppos)
+{
+	struct ath_softc *sc = file->private_data;
+	char buf[2];
+	size_t len;
+
+	len = min(count, sizeof(buf) - 1);
+	if (copy_from_user(buf, user_buf, len))
+		return -EFAULT;
+
+	if (buf[0] == '1')
+		sc->wow_enable = true;
+	else
+		sc->wow_enable = false;
+	return count;
+}
+
+static const struct file_operations fops_wow_enable = {
+	.read = read_file_wow_enable,
+	.write = write_file_wow_enable,
+	.open = ath9k_debugfs_open,
+	.owner = THIS_MODULE
+};
+#endif
 
 int ath9k_init_debug(struct ath_softc *sc)
 {
@@ -525,6 +564,15 @@ int ath9k_init_debug(struct ath_softc *sc)
 	if (!sc->debug.debugfs_rcstat)
 		goto err;
 
+#ifdef CONFIG_PM
+	sc->debug.debugfs_wow_enable = debugfs_create_file("wow_enable",
+						  S_IRUGO | S_IWUSR,
+						  sc->debug.debugfs_phy,
+						  sc, &fops_wow_enable);
+	if (!sc->debug.debugfs_wow_enable)
+		goto err;
+#endif
+
 	sc->debug.debugfs_wiphy = debugfs_create_file(
 		"wiphy", S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc,
 		&fops_wiphy);
@@ -540,6 +588,9 @@ err:
 void ath9k_exit_debug(struct ath_softc *sc)
 {
 	debugfs_remove(sc->debug.debugfs_wiphy);
+#ifdef CONFIG_PM
+	debugfs_remove(sc->debug.debugfs_wow_enable);
+#endif
 	debugfs_remove(sc->debug.debugfs_rcstat);
 	debugfs_remove(sc->debug.debugfs_interrupt);
 	debugfs_remove(sc->debug.debugfs_dma);
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 23298b9..c488591 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -29,6 +29,7 @@ enum ATH_DEBUG {
 	ATH_DBG_BEACON		= 0x00000100,
 	ATH_DBG_CONFIG		= 0x00000200,
 	ATH_DBG_FATAL		= 0x00000400,
+	ATH_DBG_POWER_MGT	= 0x00000800,
 	ATH_DBG_ANY		= 0xffffffff
 };
 
@@ -103,6 +104,9 @@ struct ath9k_debug {
 	struct dentry *debugfs_interrupt;
 	struct dentry *debugfs_rcstat;
 	struct dentry *debugfs_wiphy;
+#ifdef CONFIG_PM
+	struct dentry *debugfs_wow_enable;
+#endif
 	struct ath_stats stats;
 };
 
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 5879c73..73114de 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -718,6 +718,12 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
 			ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285_1_2),
 				  2);
 		}
+#ifdef CONFIG_PM
+		/* SerDes values during WOW sleep */
+		INIT_INI_ARRAY(&ah->iniPcieSerdesWow,
+			       ar9285PciePhy_AWOW_9285_1_2,
+			       ARRAY_SIZE(ar9285PciePhy_AWOW_9285_1_2), 2);
+#endif
 	} else if (AR_SREV_9285_10_OR_LATER(ah)) {
 		INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285,
 			       ARRAY_SIZE(ar9285Modes_9285), 6);
@@ -748,6 +754,12 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
 			       ar9280PciePhy_clkreq_always_on_L1_9280,
 			       ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2);
 		}
+#ifdef CONFIG_PM
+		/* SerDes values during WOW sleep */
+		INIT_INI_ARRAY(&ah->iniPcieSerdesWow, ar9280PciePhy_AWOW_9280,
+			       ARRAY_SIZE(ar9280PciePhy_AWOW_9280), 2);
+#endif
+
 		INIT_INI_ARRAY(&ah->iniModesAdditional,
 			       ar9280Modes_fast_clock_9280_2,
 			       ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3);
@@ -893,6 +905,16 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
 		goto bad;
 	}
 
+#ifdef CONFIG_PM
+	/* WOW */
+	ath9k_wow_set_gpio_reset_low(ah);
+	/* Clear the Wow Status */
+	REG_WRITE(ah, AR_PCIE_PM_CTRL, REG_READ(ah, AR_PCIE_PM_CTRL) |
+		  AR_PMCTRL_WOW_PME_CLR);
+	REG_WRITE(ah, AR_WOW_PATTERN_REG,
+		  AR_WOW_CLEAR_EVENTS(REG_READ(ah, AR_WOW_PATTERN_REG)));
+#endif
+
 	if (AR_SREV_9285(ah))
 		ah->tx_trig_level = (AR_FTRIG_256B >> AR_FTRIG_S);
 	else
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index ddb24c4..ff602f6 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -521,6 +521,11 @@ struct ath_hw {
 	int initPDADC;
 	int PDADCdelta;
 
+#ifdef CONFIG_PM
+	/* WoW mask -- used to indicate which WoW we have enabled */
+	u32 ah_wowEventMask;
+#endif
+
 	struct ar5416IniArray iniModes;
 	struct ar5416IniArray iniCommon;
 	struct ar5416IniArray iniBank0;
@@ -536,6 +541,10 @@ struct ath_hw {
 	struct ar5416IniArray iniModesAdditional;
 	struct ar5416IniArray iniModesRxGain;
 	struct ar5416IniArray iniModesTxGain;
+#ifdef CONFIG_PM
+	/* SerDes values during WOW sleep */
+	struct ar5416IniArray iniPcieSerdesWow;
+#endif
 };
 
 /* Attach, Detach, Reset */
@@ -617,4 +626,16 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints);
 
 void ath9k_hw_btcoex_enable(struct ath_hw *ah);
 
+#ifdef CONFIG_PM
+
+/* WOW - Wake on Wireless */
+void ath9k_wow_set_gpio_reset_low(struct ath_hw *ah);
+/* Called when going to suspend/hibernate */
+int ath9k_hw_wow_enable(struct ath_hw *ah, u32 patternEnable);
+/* Called when coming back up from suspend/hibernation */
+u32 ath9k_hw_wow_wake_up(struct ath_hw *ah);
+const char *ath9k_hw_wow_event_to_string(u32 wow_event);
+
+#endif /* CONFIG_PM */
+
 #endif
diff --git a/drivers/net/wireless/ath/ath9k/initvals.h b/drivers/net/wireless/ath/ath9k/initvals.h
index e2f0a34..12c3e7b 100644
--- a/drivers/net/wireless/ath/ath9k/initvals.h
+++ b/drivers/net/wireless/ath/ath9k/initvals.h
@@ -3439,6 +3439,22 @@ static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = {
     {0x00004044,  0x00000000 },
 };
 
+#ifdef CONFIG_PM
+/* Auto generated PCI-E PHY config for Merlin with WOW */
+static const u_int32_t ar9280PciePhy_AWOW_9280[][2] = {
+    {0x00004040,  0x9248fd00 },
+    {0x00004040,  0x24924924 },
+    {0x00004040,  0xa8000019 },
+    {0x00004040,  0x13160820 },
+    {0x00004040,  0xe5980560 },
+    {0x00004040,  0xc01ddffd },
+    {0x00004040,  0x1aaabe41 },
+    {0x00004040,  0xbe105554 },
+    {0x00004040,  0x00043007 },
+    {0x00004044,  0x00000000 },
+};
+#endif
+
 /* AR9285 */
 static const u_int32_t ar9285Modes_9285[][6] = {
     { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
@@ -4846,3 +4862,18 @@ static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = {
     {0x00004040,  0x00043007 },
     {0x00004044,  0x00000000 },
 };
+
+#ifdef CONFIG_PM
+static const u_int32_t ar9285PciePhy_AWOW_9285_1_2[][2] = {
+    {0x00004040,  0x9248fd00 },
+    {0x00004040,  0x24924924 },
+    {0x00004040,  0xa8000019 },
+    {0x00004040,  0x13160820 },
+    {0x00004040,  0xe5980560 },
+    {0x00004040,  0xc01ddffd },
+    {0x00004040,  0x1aaabe41 },
+    {0x00004040,  0xbe105554 },
+    {0x00004040,  0x00043007 },
+    {0x00004044,  0x00000000 },
+};
+#endif /* CONFIG_PM */
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 23a3a4c..4940fe8 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -560,6 +560,18 @@ irqreturn_t ath_isr(int irq, void *dev)
 		ath9k_hw_set_interrupts(ah, sc->imask);
 	}
 
+	if (status & ATH9K_INT_BMISS) {
+#ifdef CONFIG_PM
+		if (sc->wow_sleep_proc_intr) {
+			DPRINTF(sc, (ATH_DBG_POWER_MGT | ATH_DBG_INTERRUPT),
+				"during WoW we got a BMISS\n");
+			sc->wow_got_bmiss_intr = true;
+			sc->wow_sleep_proc_intr = false;
+		}
+#endif
+		DPRINTF(sc, ATH_DBG_INTERRUPT,
+			"spurious unattended beacon miss interrupt\n");
+	}
 	if (status & ATH9K_INT_TIM_TIMER) {
 		if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) {
 			/* Clear RxAbort bit so that we can
@@ -2126,6 +2138,15 @@ static void ath9k_stop(struct ieee80211_hw *hw,
 
 	aphy->state = ATH_WIPHY_INACTIVE;
 
+#ifdef CONFIG_PM
+	if (sc->wow_enable &&
+	    stop_info->reason == IEEE80211_DEV_STOP_SUSPEND) {
+		DPRINTF(sc, ATH_DBG_ANY, "Leaving radio on during "
+			"suspend/hibernate for WoW\n");
+		return;
+	}
+#endif
+
 	if (sc->sc_flags & SC_OP_INVALID) {
 		DPRINTF(sc, ATH_DBG_ANY, "Device not present\n");
 		return;
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index 168411d..3bf6d6e 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -133,6 +133,9 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
 	pci_set_master(pdev);
 
+	device_init_wakeup(&pdev->dev, 1);
+	device_set_wakeup_enable(&pdev->dev, 0);
+
 	ret = pci_request_region(pdev, 0, "ath9k");
 	if (ret) {
 		dev_err(&pdev->dev, "PCI memory region reserve error\n");
@@ -219,12 +222,56 @@ static void ath_pci_remove(struct pci_dev *pdev)
 
 #ifdef CONFIG_PM
 
+static void ath9k_pci_wow_enable(struct ath_softc *sc)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	int r;
+	u32 wake_up_events;
+
+	/* We'll add more support as we go */
+	wake_up_events = AH_WOW_MAGIC_PATTERN_EN |
+			 AH_WOW_LINK_CHANGE |
+			 AH_WOW_BEACON_MISS;
+
+	/* eventually we'll add this...
+	 * if (wake_up_events & AH_WOW_USER_PATTERN_EN)
+	 *	ath9k_wow_create_pattern(sc);
+	 */
+
+	/*
+	 * To avoid false wake, we enable beacon miss interrupt only when
+	 * we go to sleep. We save the current interrupt mask so that
+	 * we can restore it after the system wakes up.
+	 */
+	sc->wow_intr_before_sleep = ah->mask_reg;
+	ath9k_hw_set_interrupts(ah, ATH9K_INT_BMISS | ATH9K_INT_GLOBAL);
+	sc->imask = ATH9K_INT_BMISS | ATH9K_INT_GLOBAL;
+
+	r = ath9k_hw_wow_enable(ah, wake_up_events);
+	if (r) {
+		DPRINTF(sc, ATH_DBG_ANY,
+			"Unable to enable WoW\n");
+		return;
+	}
+
+	device_set_wakeup_enable(sc->dev, 1);
+
+	DPRINTF(sc, ATH_DBG_ANY,
+		"WoW enabled\n");
+
+	sc->wow_sleep_proc_intr = true;
+	sc->wow_asleep = true;
+}
+
 static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct ieee80211_hw *hw = pci_get_drvdata(pdev);
 	struct ath_wiphy *aphy = hw->priv;
 	struct ath_softc *sc = aphy->sc;
 
+	if (sc->wow_enable && device_can_wakeup(&pdev->dev))
+		ath9k_pci_wow_enable(sc);
+
 	ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
 
 #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
@@ -234,11 +281,48 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 
 	pci_save_state(pdev);
 	pci_disable_device(pdev);
+	if (sc->wow_enable && device_can_wakeup(&pdev->dev)) {
+		pci_prepare_to_sleep(pdev);
+		return 0;
+	}
+	pci_wake_from_d3(pdev, sc->wow_enable);
 	pci_set_power_state(pdev, PCI_D3hot);
 
 	return 0;
 }
 
+static void ath9k_pci_wow_wake(struct ath_softc *sc)
+{
+	struct ath_hw *ah = sc->sc_ah;
+	u32 wow_status;
+
+	sc->wow_asleep = false;
+	ath9k_hw_set_interrupts(ah, sc->wow_intr_before_sleep);
+	sc->imask = sc->wow_intr_before_sleep;
+
+	wow_status = ath9k_hw_wow_wake_up(sc->sc_ah);
+
+	if (wow_status)
+		DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+			"Waking up due to WoW signal %s\n",
+			ath9k_hw_wow_event_to_string(wow_status));
+
+	if (sc->wow_got_bmiss_intr) {
+		/*
+		 * Some devices may not pick beacon miss
+		 * as the reason they woke up so we add that
+		 * here for that shortcoming
+		 */
+		wow_status |= AH_WOW_BEACON_MISS;
+		sc->wow_got_bmiss_intr = false;
+	}
+
+	DPRINTF(ah->ah_sc, ATH_DBG_ANY,
+		"WoW status: %d\n WoW reason: %s\n",
+		wow_status,
+		ath9k_hw_wow_event_to_string((wow_status & 0x0FFF)));
+}
+
 static int ath_pci_resume(struct pci_dev *pdev)
 {
 	struct ieee80211_hw *hw = pci_get_drvdata(pdev);
@@ -251,6 +335,9 @@ static int ath_pci_resume(struct pci_dev *pdev)
 		return err;
 	pci_restore_state(pdev);
 
+	if (sc->wow_enable)
+		ath9k_pci_wow_wake(sc);
+
 	/* Enable LED */
 	ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN,
 			    AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index 5260524..387bbe7 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -665,6 +665,11 @@
 #define AR_RC_HOSTIF         0x00000100
 
 #define AR_WA                		0x4004
+#define AR_WA_UNTIE_RESET_EN	(1 << 15)   /* Enable PCI Reset to POR (power-on-reset) */
+#define AR_WA_RESET_EN		(1 << 18)   /* Sw Control to enable PCI-Reset to POR (bit 15) */
+#define AR_WA_ANALOG_SHIFT	(1 << 20)
+#define AR_WA_POR_SHORT		(1 << 21)   /* PCI-E Phy reset control */
+
 #define AR9285_WA_DEFAULT 		0x004a05cb
 #define AR9280_WA_DEFAULT           	0x0040073f
 #define AR_WA_DEFAULT               	0x0000073f
@@ -1508,4 +1513,153 @@ enum {
 #define AR_KEYTABLE_MAC0(_n)    (AR_KEYTABLE(_n) + 24)
 #define AR_KEYTABLE_MAC1(_n)    (AR_KEYTABLE(_n) + 28)
 
+/* WoW - Wake On Wireless */
+
+#define AR_PMCTRL_AUX_PWR_DET		0x10000000  /* Puts Chip in L2 state */
+#define AR_PMCTRL_D3COLD_VAUX		0x00800000
+#define AR_PMCTRL_HOST_PME_EN		0x00400000    /* Send OOB WAKE_L on WoW event */
+#define AR_PMCTRL_WOW_PME_CLR		0x00200000    /* Clear WoW event */
+#define AR_PMCTRL_PWR_STATE_MASK	0x0F000000    /* Power State Mask */
+#define AR_PMCTRL_PWR_STATE_D1D3	0x0F000000    /* Activate D1 and D3 */
+#define AR_PMCTRL_PWR_STATE_D0		0x08000000    /* Activate D0 */
+#define AR_PMCTRL_PWR_PM_CTRL_ENA	0x00008000    /* Enable power management */
+
+#define AR_WOW_BEACON_TIMO_MAX		0xFFFFFFFF  /* Max. value for Beacon Timeout */
+
+/*
+ * MAC WoW Registers.
+ */
+#define AR_WOW_PATTERN_REG		0x825C
+#define AR_WOW_COUNT_REG		0x8260
+#define AR_WOW_BCN_EN_REG		0x8270
+#define AR_WOW_BCN_TIMO_REG		0x8274
+#define AR_WOW_KEEP_ALIVE_TIMO_REG	0x8278
+#define AR_WOW_KEEP_ALIVE_REG		0x827C
+#define AR_WOW_US_SCALAR_REG		0x8284
+#define AR_WOW_KEEP_ALIVE_DELAY_REG	0x8288
+#define AR_WOW_PATTERN_MATCH_REG	0x828C
+#define AR_WOW_PATTERN_OFF1_REG		0x8290 /* Pattern bytes 0 -> 3 */
+#define AR_WOW_PATTERN_OFF2_REG		0x8294 /* Pattern bytes 4 -> 7 */
+/* For AR9285 or Later version of chips */
+#define AR_WOW_EXACT_REG		0x829C
+#define AR_WOW_LENGTH1_REG		0x8360
+#define AR_WOW_LENGTH2_REG		0x8364
+/* Register to enable pattern match for less than 256 bytes packets */
+#define AR_WOW_PATTERN_MATCH_LT_256B_REG	0x8368
+
+/* AR_WOW_PATTERN_REG Values */
+#define AR_WOW_BACK_OFF_SHIFT(x)	((x & 0xf) << 27)    /* in usecs */
+#define AR_WOW_MAC_INTR_EN		0x00040000
+#define AR_WOW_MAGIC_EN			0x00010000
+#define AR_WOW_PATTERN_EN(x)		((x & 0xff) << 0)
+#define AR_WOW_PATTERN_FOUND_SHIFT	8
+#define AR_WOW_PATTERN_FOUND(x)		(x & (0xff << AR_WOW_PATTERN_FOUND_SHIFT))
+#define AR_WOW_PATTERN_FOUND_MASK	((0xff) << AR_WOW_PATTERN_FOUND_SHIFT)
+#define AR_WOW_MAGIC_PAT_FOUND		0x00020000
+#define AR_WOW_MAC_INTR			0x00080000
+#define AR_WOW_KEEP_ALIVE_FAIL		0x00100000
+#define AR_WOW_BEACON_FAIL		0x00200000
+
+#define AR_WOW_STATUS(x)	(x & (AR_WOW_PATTERN_FOUND_MASK | \
+				      AR_WOW_MAGIC_PAT_FOUND | \
+				      AR_WOW_KEEP_ALIVE_FAIL | \
+				      AR_WOW_BEACON_FAIL))
+#define AR_WOW_CLEAR_EVENTS(x)	(x & ~(AR_WOW_PATTERN_EN(0xff) | \
+				       AR_WOW_MAGIC_EN | \
+				       AR_WOW_MAC_INTR_EN | \
+				       AR_WOW_BEACON_FAIL | \
+				       AR_WOW_KEEP_ALIVE_FAIL))
+
+/* AR_WOW_COUNT_REG Values */
+#define AR_WOW_AIFS_CNT(x)		((x & 0xff) << 0)
+#define AR_WOW_SLOT_CNT(x)		((x & 0xff) << 8)
+#define AR_WOW_KEEP_ALIVE_CNT(x)	((x & 0xff) << 16)
+
+/* AR_WOW_BCN_EN_REG */
+#define AR_WOW_BEACON_FAIL_EN		0x00000001
+
+/* AR_WOW_BCN_TIMO_REG */
+#define AR_WOW_BEACON_TIMO		0x40000000  /* Valid if BCN_EN is set */
+
+/* AR_WOW_KEEP_ALIVE_TIMO_REG */
+#define AR_WOW_KEEP_ALIVE_TIMO		0x00007A12
+#define AR_WOW_KEEP_ALIVE_NEVER		0xFFFFFFFF
+
+/* AR_WOW_KEEP_ALIVE_REG */
+#define AR_WOW_KEEP_ALIVE_AUTO_DIS	0x00000001
+#define AR_WOW_KEEP_ALIVE_FAIL_DIS	0x00000002
+
+/* AR_WOW_KEEP_ALIVE_DELAY_REG */
+#define AR_WOW_KEEP_ALIVE_DELAY		0x000003E8 /* 1 msec */
+
+/*
+ * Keep it long for Beacon workaround - ensures no false alarm
+ */
+#define AR_WOW_BMISSTHRESHOLD 0x20
+
+/* AR_WOW_PATTERN_MATCH_REG */
+#define AR_WOW_PAT_END_OF_PKT(x)	((x & 0xf) << 0)
+#define AR_WOW_PAT_OFF_MATCH(x)		((x & 0xf) << 8)
+
+/*
+ * Default values for Wow Configuration for backoff, aifs, slot, keep-alive, etc
+ * to be programmed into various registers.
+ */
+#define AR_WOW_PAT_BACKOFF	0x00000004 /* AR_WOW_PATTERN_REG */
+#define AR_WOW_CNT_AIFS_CNT	0x00000022 /* AR_WOW_COUNT_REG */
+#define AR_WOW_CNT_SLOT_CNT	0x00000009 /* AR_WOW_COUNT_REG */
+/*
+ * Keepalive count applicable for AR9280 2.0 and above.
+ */
+#define AR_WOW_CNT_KA_CNT 0x00000008    /* AR_WOW_COUNT_REG */
+
+/* WoW - Transmit buffer for keep alive frames */
+#define AR_WOW_TRANSMIT_BUFFER	0xE000 /* E000 - EFFC */
+
+#define AR_WOW_KA_DESC_WORD2	0xE000
+#define AR_WOW_KA_DESC_WORD3	0xE004
+#define AR_WOW_KA_DESC_WORD4	0xE008
+#define AR_WOW_KA_DESC_WORD5	0xE00C
+#define AR_WOW_KA_DESC_WORD6	0xE010
+#define AR_WOW_KA_DESC_WORD7	0xE014
+#define AR_WOW_KA_DESC_WORD8	0xE018
+#define AR_WOW_KA_DESC_WORD9	0xE01C
+#define AR_WOW_KA_DESC_WORD10	0xE020
+#define AR_WOW_KA_DESC_WORD11	0xE024
+#define AR_WOW_KA_DESC_WORD12	0xE028
+#define AR_WOW_KA_DESC_WORD13	0xE02C
+
+#define AR_WOW_KA_DATA_WORD0	0xE030
+#define AR_WOW_KA_DATA_WORD1	0xE034
+#define AR_WOW_KA_DATA_WORD2	0xE038
+#define AR_WOW_KA_DATA_WORD3	0xE03C
+#define AR_WOW_KA_DATA_WORD4	0xE040
+#define AR_WOW_KA_DATA_WORD5	0xE044
+
+/* WoW Transmit Buffer for patterns */
+#define AR_WOW_TB_PATTERN0	0xE100
+#define AR_WOW_TB_PATTERN1	0xE200
+#define AR_WOW_TB_PATTERN2	0xE300
+#define AR_WOW_TB_PATTERN3	0xE400
+#define AR_WOW_TB_PATTERN4	0xE500
+#define AR_WOW_TB_PATTERN5	0xE600
+#define AR_WOW_TB_PATTERN6	0xE700
+#define AR_WOW_TB_PATTERN7	0xE800
+#define AR_WOW_TB_MASK0		0xEC00
+#define AR_WOW_TB_MASK1		0xEC20
+#define AR_WOW_TB_MASK2		0xEC40
+#define AR_WOW_TB_MASK3		0xEC60
+#define AR_WOW_TB_MASK4		0xEC80
+#define AR_WOW_TB_MASK5		0xECa0
+#define AR_WOW_TB_MASK6		0xECC0
+#define AR_WOW_TB_MASK7		0xECE0
+
+/* Currently Pattern 0-7 are supported - so bit 0-7 are set */
+#define AR_WOW_PATTERN_SUPPORTED	0xFF
+#define AR_WOW_LENGTH_MAX		0xFF
+#define AR_WOW_LENGTH1_SHIFT(_i)	((0x3 - ((_i) & 0x3)) << 0x3)
+#define AR_WOW_LENGTH1_MASK(_i)		(AR_WOW_LENGTH_MAX << AR_WOW_LENGTH1_SHIFT(_i))
+#define AR_WOW_LENGTH2_SHIFT(_i)	((0x7 - ((_i) & 0x7)) << 0x3)
+#define AR_WOW_LENGTH2_MASK(_i)		(AR_WOW_LENGTH_MAX << AR_WOW_LENGTH2_SHIFT(_i))
+
 #endif
diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c
new file mode 100644
index 0000000..11fee62
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/wow.c
@@ -0,0 +1,543 @@
+/*
+ * Copyright (c) 2008-2009 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "ath9k.h"
+#include "reg.h"
+
+#ifdef CONFIG_PM
+
+/*
+ * This routine is called to configure the SerDes register for the
+ * AR9280 2.0 and above chip during WOW sleep.
+ */
+static void
+ath9k_ar928xConfigSerDes_WowSleep(struct ath_hw *ah)
+{
+	unsigned int i;
+
+	/*
+	 * For WOW sleep, we reprogram the SerDes so that the PLL and CHK REQ
+	 * are both enabled. This uses more power but in certain cases this
+	 * is required as otherwise WOW sleep is unstable and chip may
+	 * disappears.
+	 */
+	for (i = 0; i < ah->iniPcieSerdesWow.ia_rows; i++)
+		REG_WRITE(ah,
+			  INI_RA(&ah->iniPcieSerdesWow, i, 0),
+			  INI_RA(&ah->iniPcieSerdesWow, i, 1));
+	udelay(1000);
+}
+
+static bool ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah)
+{
+	u32 frame_len = 28;
+	u32 tpc = 0x3f;
+	u32 antenna_mode = 1;
+	u32 transmit_rate;
+	u32 frame_type = 0x2; /* Frame Type -> Data */
+	u32 sub_type = 0x4; /* Subtype -> Null Data */
+	u32 to_ds = 1;
+	u32 duration_id = 0x3d;
+	u8 *StaMacAddr, *ApMacAddr;
+	u8 *addr1, *addr2, *addr3;
+	u32 ctl[12] = { 0 };
+	u32 data_word0 = 0, data_word1 = 0, data_word2 = 0,
+	data_word3 = 0, data_word4 = 0, data_word5 = 0;
+	u32 i;
+
+	StaMacAddr = (u8 *)ah->macaddr;
+	ApMacAddr = (u8 *)ah->ah_sc->curbssid;
+	addr2 = StaMacAddr;
+	addr1 = addr3 = ApMacAddr;
+
+	/*
+	 * XXX: we need a way to determine if the AP we're on
+	 * is using CCK only and if so use this:
+	 * transmit_rate = 0x1B; // CCK_1M
+	 * For now we just assume your AP supports OFDM
+	 */
+	transmit_rate = 0xB; /* OFDM_6M */
+
+	/* Set the Transmit Buffer. */
+	ctl[0] = (frame_len | (tpc << 16)) + (antenna_mode << 25);
+	ctl[1] = 0;
+	ctl[2] = 0x7 << 16; /* tx_tries0 */
+	ctl[3] = transmit_rate;
+	ctl[4] = 0;
+	ctl[7] = ah->txchainmask << 2;
+
+	for (i = 0; i < 12; i++)
+		REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);
+
+	data_word0 = (frame_type << 2) | (sub_type << 4) |
+		     (to_ds << 8) | (duration_id << 16);
+	data_word1 = (((u32)addr1[3] << 24) | ((u32)addr1[2] << 16) |
+		     ((u32)addr1[1]) << 8 | ((u32)addr1[0]));
+	data_word2 = (((u32)addr2[1] << 24) | ((u32)addr2[0] << 16) |
+		     ((u32)addr1[5]) << 8 | ((u32)addr1[4]));
+	data_word3 = (((u32)addr2[5] << 24) | ((u32)addr2[4] << 16) |
+		     ((u32)addr2[3]) << 8 | ((u32)addr2[2]));
+	data_word4 = (((u32)addr3[3] << 24) | ((u32)addr3[2] << 16) |
+		     ((u32)addr3[1]) << 8 | (u32)addr3[0]);
+	data_word5 = (((u32)addr3[5]) << 8 | ((u32)addr3[4]));
+
+	REG_WRITE(ah, AR_WOW_KA_DATA_WORD0, data_word0);
+	REG_WRITE(ah, AR_WOW_KA_DATA_WORD1, data_word1);
+	REG_WRITE(ah, AR_WOW_KA_DATA_WORD2, data_word2);
+	REG_WRITE(ah, AR_WOW_KA_DATA_WORD3, data_word3);
+	REG_WRITE(ah, AR_WOW_KA_DATA_WORD4, data_word4);
+	REG_WRITE(ah, AR_WOW_KA_DATA_WORD5, data_word5);
+
+	return true;
+}
+
+/* TBD: Should querying hw for hardware capability */
+#define MAX_PATTERN_SIZE	256
+#define MAX_PATTERN_MASK_SIZE	32
+
+/* Deducting the disassociate/deauthenticate packets */
+#define MAX_NUM_USER_PATTERN	6
+
+# if 0
+static void ath9k_wow_apply_pattern(struct ath_hw *ah,
+				    u8 *pAthPattern, u8 *pAthMask,
+				    int pattern_count, u32 athPatternLen)
+{
+	unsigned int i;
+	u32 reg_pat[] = {
+		AR_WOW_TB_PATTERN0,
+		AR_WOW_TB_PATTERN1,
+		AR_WOW_TB_PATTERN2,
+		AR_WOW_TB_PATTERN3,
+		AR_WOW_TB_PATTERN4,
+		AR_WOW_TB_PATTERN5,
+		AR_WOW_TB_PATTERN6,
+		AR_WOW_TB_PATTERN7
+	};
+	u32 reg_mask[] = {
+		AR_WOW_TB_MASK0,
+		AR_WOW_TB_MASK1,
+		AR_WOW_TB_MASK2,
+		AR_WOW_TB_MASK3,
+		AR_WOW_TB_MASK4,
+		AR_WOW_TB_MASK5,
+		AR_WOW_TB_MASK6,
+		AR_WOW_TB_MASK7
+	};
+	u32 pattern_val;
+	u32 mask_val;
+	u8 mask_bit = 0x1;
+	u8 pattern;
+
+	/* TBD: should check count by querying the hardware capability */
+	if (pattern_count >= MAX_NUM_USER_PATTERN)
+		return;
+
+	pattern = (u8)REG_READ(ah, AR_WOW_PATTERN_REG);
+	pattern = pattern | (mask_bit << pattern_count);
+	REG_WRITE(ah, AR_WOW_PATTERN_REG, pattern);
+
+	/* Set the registers for pattern */
+	for (i = 0; i < MAX_PATTERN_SIZE; i+=4) {
+		pattern_val = (((u32)pAthPattern[i]) |
+			      ((u32)pAthPattern[i+1] << 8) |
+			      ((u32)pAthPattern[i+2] << 16) |
+			      ((u32)pAthPattern[i+3] << 24));
+		REG_WRITE(ah, (reg_pat[pattern_count] + i), pattern_val);
+	}
+
+	/* Set the registers for mask */
+	for (i = 0; i < MAX_PATTERN_MASK_SIZE; i+=4) {
+		mask_val = (((u32)pAthMask[i]) |
+			   ((u32)pAthMask[i+1] << 8) |
+			   ((u32)pAthMask[i+2] << 16) |
+			   ((u32)pAthMask[i+3] << 24));
+		REG_WRITE(ah, (reg_mask[pattern_count] + i), mask_val);
+	}
+
+	if (AR_SREV_9285_10_OR_LATER(ah)) {
+		/* Set the pattern length to be matched */
+		u32 val;
+		if (pattern_count < 4) {
+			/* Pattern 0-3 uses AR_WOW_LENGTH1_REG register */
+			val = REG_READ(ah, AR_WOW_LENGTH1_REG);
+			val = ((val & (~AR_WOW_LENGTH1_MASK(pattern_count))) |
+			      ((athPatternLen & AR_WOW_LENGTH_MAX)
+				<< AR_WOW_LENGTH1_SHIFT(pattern_count)));
+			REG_WRITE(ah, AR_WOW_LENGTH1_REG, val);
+		} else {
+			/* Pattern 4-7 uses AR_WOW_LENGTH2_REG register */
+			val = REG_READ(ah, AR_WOW_LENGTH2_REG);
+			val = ((val & (~AR_WOW_LENGTH2_MASK(pattern_count))) |
+			      ((athPatternLen & AR_WOW_LENGTH_MAX)
+				<< AR_WOW_LENGTH2_SHIFT(pattern_count)));
+			REG_WRITE(ah, AR_WOW_LENGTH2_REG, val);
+		}
+	}
+
+	ah->ah_wowEventMask |=
+		(1 << (pattern_count + AR_WOW_PATTERN_FOUND_SHIFT));
+}
+#endif
+
+static bool ath9k_set_power_mode_wow_sleep(struct ath_hw *ah)
+{
+	REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);
+
+	REG_WRITE(ah, AR_CR, AR_CR_RXD); /* Set receive disable bit */
+	if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0, AH_WAIT_TIMEOUT)) {
+		DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGT,
+			"dma failed to stop in 10ms\n"
+			"AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n",
+			REG_READ(ah, AR_CR),
+			REG_READ(ah, AR_DIAG_SW));
+		return false;
+	} else {
+		REG_WRITE(ah, AR_RXDP, 0x0);
+
+		/* AR9280 2.0/2.1 WOW has sleep issue, do not set it to sleep */
+		if (AR_SREV_9280_20(ah))
+			return true;
+		else
+			REG_WRITE(ah, AR_RTC_FORCE_WAKE,
+				  AR_RTC_FORCE_WAKE_ON_INT);
+		return true;
+	}
+}
+
+int ath9k_hw_wow_enable(struct ath_hw *ah, u32 patternEnable)
+{
+	u32 init_val, val, rval = 0;
+	/* Send a Keep-Alive frame every 900 millisec */
+	const int ka_timo = 900;
+	/* Delay of 4 millisec between two KeepAlive's */
+	const int ka_delay = 4;
+	u32 wow_event_mask;
+	bool all_triggers_set = true;
+
+	/*
+	 * ah_wowEventMask is a mask to the AR_WOW_PATTERN_REG register to
+	 * indicate which WOW events that we have enabled. The WOW Events
+	 * are from the patternEnable in this function and pattern_count of
+	 * ath9k_wow_apply_pattern()
+	 */
+	wow_event_mask = ah->ah_wowEventMask;
+
+	/*
+	 * Untie Power-On-Reset from the PCI-E Reset. When we are in WOW sleep,
+	 * we do not want the Reset from the PCI-E to disturb our hw state.
+	 */
+	if (AR_SREV_9280_20_OR_LATER(ah) && ah->is_pciexpress) {
+		/*
+		 * We need to untie the internal POR (power-on-reset) to the
+		 * external PCI-E reset. We also need to tie the PCI-E Phy
+		 * reset to the PCI-E reset.
+		 */
+		u32 wa_reg_val;
+		if (AR_SREV_9285(ah))
+			wa_reg_val = AR9285_WA_DEFAULT;
+		else
+			wa_reg_val = AR9280_WA_DEFAULT;
+		wa_reg_val = wa_reg_val & ~(AR_WA_UNTIE_RESET_EN);
+		wa_reg_val = wa_reg_val | AR_WA_RESET_EN | AR_WA_POR_SHORT;
+		REG_WRITE(ah, AR_WA, wa_reg_val);
+
+		if (!AR_SREV_9285(ah) || AR_SREV_9285_12_OR_LATER(ah)) {
+			/*
+			 * For WOW sleep, we reprogram the SerDes so that the
+			 * PLL and CHK REQ are both enabled. This uses more
+			 * power but otherwise in certain cases, WOW sleep is
+			 * unusable and chip may disappears.
+			 */
+			ath9k_ar928xConfigSerDes_WowSleep(ah);
+		}
+	}
+
+	/*
+	 * Set the power states appropriately and enable pme.
+	 */
+	val = REG_READ(ah, AR_PCIE_PM_CTRL);
+	val |= AR_PMCTRL_HOST_PME_EN |
+	       AR_PMCTRL_PWR_PM_CTRL_ENA |
+	       AR_PMCTRL_AUX_PWR_DET;
+	val &= ~AR_PMCTRL_WOW_PME_CLR;
+	REG_WRITE(ah, AR_PCIE_PM_CTRL, val);
+
+	/*
+	 * Setup for:
+	 *     - beacon misses
+	 *     - magic pattern
+	 *     - keep alive timeout
+	 *     - pattern matching
+	 */
+
+	/*
+	 * Program some default values for keep-alives, beacon misses, etc.
+	 */
+	init_val = REG_READ(ah, AR_WOW_PATTERN_REG);
+	val = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF) | init_val;
+	REG_WRITE(ah, AR_WOW_PATTERN_REG, val);
+	rval = REG_READ(ah, AR_WOW_PATTERN_REG);
+
+	init_val = REG_READ(ah, AR_WOW_COUNT_REG);
+	val = AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) | \
+	      AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) | \
+	AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT);
+	REG_WRITE(ah, AR_WOW_COUNT_REG, val);
+	rval = REG_READ(ah, AR_WOW_COUNT_REG);
+
+
+	init_val = REG_READ(ah, AR_WOW_BCN_TIMO_REG);
+	if (patternEnable & AH_WOW_BEACON_MISS)
+		val = AR_WOW_BEACON_TIMO;
+	else
+		/* We are not using the beacon miss. Program a large value. */
+		val = AR_WOW_BEACON_TIMO_MAX;
+	REG_WRITE(ah, AR_WOW_BCN_TIMO_REG, val);
+	rval = REG_READ(ah, AR_WOW_BCN_TIMO_REG);
+	if ((patternEnable & AH_WOW_BEACON_MISS) &&
+	    !(rval & AR_WOW_BEACON_TIMO))
+		all_triggers_set = false;
+
+	init_val = REG_READ(ah, AR_WOW_KEEP_ALIVE_TIMO_REG);
+
+	/*
+	 * Keep Alive Timo in ms.
+	 */
+	if (patternEnable == 0)
+		val =  AR_WOW_KEEP_ALIVE_NEVER;
+	else
+		val =  ka_timo * 32;
+	REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO_REG, val);
+	rval = REG_READ(ah, AR_WOW_KEEP_ALIVE_TIMO_REG);
+
+	init_val = REG_READ(ah, AR_WOW_KEEP_ALIVE_DELAY_REG);
+	/*
+	 * Keep Alive delay in us.
+	 */
+	val = ka_delay * 1000;
+	REG_WRITE(ah, AR_WOW_KEEP_ALIVE_DELAY_REG, val);
+	rval = REG_READ(ah, AR_WOW_KEEP_ALIVE_DELAY_REG);
+
+	/*
+	 * Create KeepAlive Pattern to respond to beacons.
+	 */
+	ath9k_wow_create_keep_alive_pattern(ah);
+
+	/*
+	 * Configure Mac Wow Registers.
+	 */
+
+	val = REG_READ(ah, AR_WOW_KEEP_ALIVE_REG);
+	/*
+	 * Send keep alive timeouts anyway.
+	 */
+	val &= ~AR_WOW_KEEP_ALIVE_AUTO_DIS;
+
+	if (patternEnable & AH_WOW_LINK_CHANGE) {
+		val &= ~ AR_WOW_KEEP_ALIVE_FAIL_DIS;
+		wow_event_mask |= AR_WOW_KEEP_ALIVE_FAIL;
+	} else
+		val |=  AR_WOW_KEEP_ALIVE_FAIL_DIS;
+
+	REG_WRITE(ah, AR_WOW_KEEP_ALIVE_REG, val);
+	val = REG_READ(ah, AR_WOW_KEEP_ALIVE_REG);
+	if ((patternEnable & AH_WOW_LINK_CHANGE) &&
+	    (val & AR_WOW_KEEP_ALIVE_FAIL_DIS))
+		all_triggers_set = false;
+	val = REG_READ(ah, AR_WOW_BCN_EN_REG);
+
+	/*
+	 * We are relying on a bmiss failure. Ensure we have enough
+	 * threshold to prevent false positives.
+	 */
+	REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR,
+		      AR_WOW_BMISSTHRESHOLD);
+
+	/*
+	 * Beacon miss & user pattern events do not work on AR5416.
+	 * We enable beacon miss wow pattern only for AR9280...
+	 */
+	if (!AR_SREV_9280_10_OR_LATER(ah))
+		patternEnable &= ~AH_WOW_BEACON_MISS;
+
+	if (patternEnable & AH_WOW_BEACON_MISS) {
+		val |= AR_WOW_BEACON_FAIL_EN;
+		wow_event_mask |= AR_WOW_BEACON_FAIL;
+	} else
+		val &= ~AR_WOW_BEACON_FAIL_EN;
+
+	REG_WRITE(ah, AR_WOW_BCN_EN_REG, val);
+	val = REG_READ(ah, AR_WOW_BCN_EN_REG);
+	if ((patternEnable & AH_WOW_BEACON_MISS) &&
+	    !(val & AR_WOW_BEACON_FAIL_EN))
+		all_triggers_set = false;
+
+	/*
+	 * Enable the magic packet registers.
+	 */
+	val = REG_READ(ah, AR_WOW_PATTERN_REG);
+	if (patternEnable & AH_WOW_MAGIC_PATTERN_EN) {
+		val |= AR_WOW_MAGIC_EN;
+		wow_event_mask |= AR_WOW_MAGIC_PAT_FOUND;
+	} else
+		val &= ~AR_WOW_MAGIC_EN;
+
+	val |= AR_WOW_MAC_INTR_EN;
+	REG_WRITE(ah, AR_WOW_PATTERN_REG, val);
+	val = REG_READ(ah, AR_WOW_PATTERN_REG);
+
+	/* Lets be a little more verbose about this one */
+	if (patternEnable & AH_WOW_MAGIC_PATTERN_EN) {
+		if (val & AR_WOW_MAGIC_EN) {
+			DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGT,
+				"WoW: Magic pattern trigger set\n");
+		} else {
+			all_triggers_set = false;
+			DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGT,
+				"WoW: Unable to enable magic "
+				"pattern trigger\n");
+		}
+	}
+
+	/*
+	 * For AR9285 and later version of the chips
+	 * enable wow pattern match for packets less than
+	 * 256 bytes for all patterns.
+	 */
+	if (AR_SREV_9285_10_OR_LATER(ah))
+		REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B_REG,
+			  AR_WOW_PATTERN_SUPPORTED);
+
+	/*
+	 * Set the power states appropriately and enable pme.
+	 */
+	val = REG_READ(ah, AR_PCIE_PM_CTRL);
+	val |=  AR_PMCTRL_PWR_STATE_D1D3 |
+		AR_PMCTRL_HOST_PME_EN |
+		AR_PMCTRL_PWR_PM_CTRL_ENA;
+	REG_WRITE(ah, AR_PCIE_PM_CTRL, val);
+
+	ath9k_set_power_mode_wow_sleep(ah);
+
+	ah->ah_wowEventMask = wow_event_mask;
+
+	if (!all_triggers_set)
+		return -EIO;
+
+	return 0;
+}
+
+u32 ath9k_hw_wow_wake_up(struct ath_hw *ah)
+{
+	u32 wowStatus = 0;
+	u32 val = 0, rval;
+
+	/*
+	 * Read the WOW Status register to know the wakeup reason.
+	 */
+	rval = REG_READ(ah, AR_WOW_PATTERN_REG);
+	val = AR_WOW_STATUS(rval);
+
+	/*
+	 * Mask only the WOW events that we have enabled. Sometimes, we have
+	 * spurious WOW events from the AR_WOW_PATTERN_REG register. This mask
+	 * will clean it up.
+	 */
+	val &= ah->ah_wowEventMask;
+
+	if (val) {
+		if (val & AR_WOW_MAGIC_PAT_FOUND)
+			wowStatus |= AH_WOW_MAGIC_PATTERN_EN;
+		if (AR_WOW_PATTERN_FOUND(val))
+			wowStatus |= AH_WOW_USER_PATTERN_EN;
+		if (val & AR_WOW_KEEP_ALIVE_FAIL)
+			wowStatus |= AH_WOW_LINK_CHANGE;
+		if (val & AR_WOW_BEACON_FAIL)
+			wowStatus |= AH_WOW_BEACON_MISS;
+	}
+
+	/*
+	 * Set and clear WOW_PME_CLEAR registers for the chip to generate next
+	 * wow signal. Disable D3 before accessing other registers ?
+	 */
+	val = REG_READ(ah, AR_PCIE_PM_CTRL);
+	/* Do we have to check the bit value 0x01000000 (7-10) ?? */
+	val &= ~AR_PMCTRL_PWR_STATE_D1D3;
+	val |= AR_PMCTRL_WOW_PME_CLR;
+	REG_WRITE(ah, AR_PCIE_PM_CTRL, val);
+
+	/*
+	 * Clear all events.
+	 */
+	REG_WRITE(ah, AR_WOW_PATTERN_REG,
+		  AR_WOW_CLEAR_EVENTS(REG_READ(ah, AR_WOW_PATTERN_REG)));
+
+	/*
+	 * Tie reset register.
+	 * NB: Not tieing it back might have some repurcussions.
+	 */
+	if (AR_SREV_9280_10_OR_LATER(ah)) {
+		REG_WRITE(ah, AR_WA, REG_READ(ah, AR_WA) |
+				     AR_WA_UNTIE_RESET_EN |
+				     AR_WA_POR_SHORT |
+				     AR_WA_RESET_EN);
+	}
+
+	/* Restore the Beacon Threshold to init value */
+	REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);
+
+	/*
+	 * Restore the way the PCI-E Reset, Power-On-Reset, external
+	 * PCIE_POR_SHORT pins are tied to its original value. Previously
+	 * just before WOW sleep, we untie the PCI-E Reset to our Chip's
+	 * Power On Reset so that any PCI-E reset from the bus will not
+	 * reset our chip.
+	 */
+	if (AR_SREV_9280_20_OR_LATER(ah) && ah->is_pciexpress)
+		ath9k_hw_configpcipowersave(ah, 0);
+
+	ah->ah_wowEventMask = 0;
+
+	return wowStatus;
+}
+
+void ath9k_wow_set_gpio_reset_low(struct ath_hw *ah)
+{
+    u32 val;
+
+    val = REG_READ(ah, AR_GPIO_OE_OUT);
+    val |= (1 << (2 * 2));
+    REG_WRITE(ah, AR_GPIO_OE_OUT, val);
+    val = REG_READ(ah, AR_GPIO_OE_OUT);
+    val = REG_READ(ah,AR_GPIO_IN_OUT );
+}
+
+const char *
+ath9k_hw_wow_event_to_string(u32 wow_event)
+{
+	if (wow_event & AH_WOW_MAGIC_PATTERN_EN)
+		return "Magic pattern";
+	if (wow_event & AH_WOW_USER_PATTERN_EN)
+		return "User pattern";
+	if (wow_event & AH_WOW_LINK_CHANGE)
+		return "Link change";
+	if (wow_event & AH_WOW_BEACON_MISS)
+		return "Beacon miss";
+	return "Uknown event";
+}
+
+#endif /* CONFIG_PM */
-- 
1.6.0.6


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

* Re: [RFC 4/5] mac80211: add a struct for info upon device stop
  2009-05-11  9:25 ` [RFC 4/5] mac80211: add a struct for info upon device stop Luis R. Rodriguez
@ 2009-05-11  9:53   ` Johannes Berg
  2009-05-11 18:33     ` Luis R. Rodriguez
  0 siblings, 1 reply; 16+ messages in thread
From: Johannes Berg @ 2009-05-11  9:53 UTC (permalink / raw)
  To: Luis R. Rodriguez; +Cc: linux-wireless

[-- Attachment #1: Type: text/plain, Size: 2240 bytes --]

On Mon, 2009-05-11 at 05:25 -0400, Luis R. Rodriguez wrote:

>  /**
> + * enum ieee80211_device_stop_reason - device stop reasons
> + *
> + * These are reasons why mac80211 would call the driver's stop()
> + * callback. Devices should probably not care other than when
> + * we call to stop during suspend, in these cases the device may
> + * want to leave the radio on for WoW events for example.
> + * @IEEE80211_DEV_STOP_INVALID_MAC: invalid mac address was detected for device
> + * @IEEE80211_DEV_STOP_NO_OPEN_DEV: we were not able to open any
> +	netdevice for the current wireless device during user initialization.
> + * @IEEE80211_DEV_STOP_DEV_CLOSE_REQUEST: user requested the device to be
> + *	closed.
> + * @IEEE80211_DEV_STOP_SUSPEND: we are going to suspend
> + */
> +enum ieee80211_device_stop_reasons {
> +	IEEE80211_DEV_STOP_INVALID_MAC,
> +	IEEE80211_DEV_STOP_NO_OPEN_DEV,
> +	IEEE80211_DEV_STOP_DEV_CLOSE_REQUEST,
> +	IEEE80211_DEV_STOP_SUSPEND,
> +};

> +struct ieee80211_device_stop_info {
> +       enum ieee80211_device_stop_reasons reason;
> +};

Hmm. You're creating a code-flow API rather than a do-what-I-want API, I
think it leaves the driver too much choice ;)

The way you're using this here is:

+#ifdef CONFIG_PM
+       if (sc->wow_enable &&
+           stop_info->reason == IEEE80211_DEV_STOP_SUSPEND) {

So for one, all the other reasons are unnecessary. Additionally, as you
said, you need to stay associated for some WoW modes, so mac80211 needs
to be aware of that when going into suspend. It might even need to be
aware of things like the computer waking up only to cycle keys.

Therefore, IMHO the stop info struct (I would drop _info from the name,
seems not very useful and makes the struct name very long) should
contain the WoW parameters so that devices can program those parameters
instead of turning off completely. At suspend time, mac80211 would fill
in those parameters, whereas it wouldn't do that at the other times the
device is stopped.

Of course, that means adding a WOW_CAPABLE HW flag, and API to mac80211
to program WOW, but that will gain us more uniformity. Question is
whether we want to use nl80211 or ethtool.

johannes


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

* Re: [RFC 3/5] mac80211: fix idle trigger upon resume
  2009-05-11  9:25 ` [RFC 3/5] mac80211: fix idle trigger upon resume Luis R. Rodriguez
@ 2009-05-11 10:01   ` Johannes Berg
  2009-05-11 18:34     ` Luis R. Rodriguez
  0 siblings, 1 reply; 16+ messages in thread
From: Johannes Berg @ 2009-05-11 10:01 UTC (permalink / raw)
  To: Luis R. Rodriguez; +Cc: linux-wireless

[-- Attachment #1: Type: text/plain, Size: 1222 bytes --]

On Mon, 2009-05-11 at 05:25 -0400, Luis R. Rodriguez wrote:
> When we suspend we stop the queues, then upon resume
> the new idle checks will immediately pick up we're
> idle and ask call our driver's config callback. At
> this point its pointless to to call this callback
> as we haven't yet come back from suspend. We avoid
> then making assumptions about being idle until we know
> we've come back from suspend. We do this by checking
> the reason stop on all our queues.
> 
> Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
> ---
>  net/mac80211/ieee80211_i.h |    2 ++
>  net/mac80211/iface.c       |    5 +++++
>  net/mac80211/util.c        |   39 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 46 insertions(+), 0 deletions(-)

> +EXPORT_SYMBOL(ieee80211_any_queues_stopped_by_reason);

You certainly should not export this symbol.

Also, __ieee80211_queues_stopped_by_reason is misnamed since it checks
only a single queue. I also think that we can do this much better by
keeping track of the suspend state in a new variable rather than looking
at all the queues; even just checking queue 0 would be sufficient, but I
think a new variable is warranted.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

* Re: [RFC 4/5] mac80211: add a struct for info upon device stop
  2009-05-11  9:53   ` Johannes Berg
@ 2009-05-11 18:33     ` Luis R. Rodriguez
  0 siblings, 0 replies; 16+ messages in thread
From: Luis R. Rodriguez @ 2009-05-11 18:33 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless

On Mon, May 11, 2009 at 2:53 AM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> On Mon, 2009-05-11 at 05:25 -0400, Luis R. Rodriguez wrote:
>
>> =C2=A0/**
>> + * enum ieee80211_device_stop_reason - device stop reasons
>> + *
>> + * These are reasons why mac80211 would call the driver's stop()
>> + * callback. Devices should probably not care other than when
>> + * we call to stop during suspend, in these cases the device may
>> + * want to leave the radio on for WoW events for example.
>> + * @IEEE80211_DEV_STOP_INVALID_MAC: invalid mac address was detecte=
d for device
>> + * @IEEE80211_DEV_STOP_NO_OPEN_DEV: we were not able to open any
>> + =C2=A0 =C2=A0 netdevice for the current wireless device during use=
r initialization.
>> + * @IEEE80211_DEV_STOP_DEV_CLOSE_REQUEST: user requested the device=
 to be
>> + * =C2=A0 closed.
>> + * @IEEE80211_DEV_STOP_SUSPEND: we are going to suspend
>> + */
>> +enum ieee80211_device_stop_reasons {
>> + =C2=A0 =C2=A0 IEEE80211_DEV_STOP_INVALID_MAC,
>> + =C2=A0 =C2=A0 IEEE80211_DEV_STOP_NO_OPEN_DEV,
>> + =C2=A0 =C2=A0 IEEE80211_DEV_STOP_DEV_CLOSE_REQUEST,
>> + =C2=A0 =C2=A0 IEEE80211_DEV_STOP_SUSPEND,
>> +};
>
>> +struct ieee80211_device_stop_info {
>> + =C2=A0 =C2=A0 =C2=A0 enum ieee80211_device_stop_reasons reason;
>> +};
>
> Hmm. You're creating a code-flow API rather than a do-what-I-want API=
, I
> think it leaves the driver too much choice ;)
>
> The way you're using this here is:
>
> +#ifdef CONFIG_PM
> + =C2=A0 =C2=A0 =C2=A0 if (sc->wow_enable &&
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 stop_info->reason =3D=3D IEEE802=
11_DEV_STOP_SUSPEND) {
>
> So for one, all the other reasons are unnecessary.

=46igured you'd want to nuke the rest, ok, then lets just have a bool f=
or suspend.

> Additionally, as you
> said, you need to stay associated for some WoW modes, so mac80211 nee=
ds
> to be aware of that when going into suspend. It might even need to be
> aware of things like the computer waking up only to cycle keys.
>
> Therefore, IMHO the stop info struct (I would drop _info from the nam=
e,
> seems not very useful and makes the struct name very long) should
> contain the WoW parameters so that devices can program those paramete=
rs
> instead of turning off completely.

Sure, so the reason I used a struct was so that we leave room for this
exact stuff to be added as you had recommended, I just wanted to get
WoW working before finishing the APIs but .. it seems we do need to
work with mac80211 anyway so I might as well just finish the WoW API
stuff..

> At suspend time, mac80211 would fill
> in those parameters, whereas it wouldn't do that at the other times t=
he
> device is stopped.

OK thanks.

>
> Of course, that means adding a WOW_CAPABLE HW flag, and API to mac802=
11
> to program WOW, but that will gain us more uniformity.

Sure well I was thinking of making this a cfg80211 thing.

> Question is
> whether we want to use nl80211 or ethtool.

I think we want to use nl80211 -- there are some things which are
wireless-specific like beacon miss triggers. Plus it just seems silly
to have to have drivers implement two ethtool ops just for WoW -- or
have mac80211 do that (or cfg80211).

I'll just get this properly implemented in cfg80211 then and send a new=
 RFC.

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

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

* Re: [RFC 3/5] mac80211: fix idle trigger upon resume
  2009-05-11 10:01   ` Johannes Berg
@ 2009-05-11 18:34     ` Luis R. Rodriguez
  2009-05-11 18:53       ` Johannes Berg
  0 siblings, 1 reply; 16+ messages in thread
From: Luis R. Rodriguez @ 2009-05-11 18:34 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless

On Mon, May 11, 2009 at 3:01 AM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> On Mon, 2009-05-11 at 05:25 -0400, Luis R. Rodriguez wrote:
>> When we suspend we stop the queues, then upon resume
>> the new idle checks will immediately pick up we're
>> idle and ask call our driver's config callback. At
>> this point its pointless to to call this callback
>> as we haven't yet come back from suspend. We avoid
>> then making assumptions about being idle until we know
>> we've come back from suspend. We do this by checking
>> the reason stop on all our queues.
>>
>> Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com>
>> ---
>> =C2=A0net/mac80211/ieee80211_i.h | =C2=A0 =C2=A02 ++
>> =C2=A0net/mac80211/iface.c =C2=A0 =C2=A0 =C2=A0 | =C2=A0 =C2=A05 +++=
++
>> =C2=A0net/mac80211/util.c =C2=A0 =C2=A0 =C2=A0 =C2=A0| =C2=A0 39 +++=
++++++++++++++++++++++++++++++++++++
>> =C2=A03 files changed, 46 insertions(+), 0 deletions(-)
>
>> +EXPORT_SYMBOL(ieee80211_any_queues_stopped_by_reason);
>
> You certainly should not export this symbol.
>
> Also, __ieee80211_queues_stopped_by_reason is misnamed since it check=
s
> only a single queue. I also think that we can do this much better by
> keeping track of the suspend state in a new variable rather than look=
ing
> at all the queues; even just checking queue 0 would be sufficient, bu=
t I
> think a new variable is warranted.

A global variable for going to suspend? Hm, do we have a system wide
thing for this instead?

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

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

* Re: [RFC 3/5] mac80211: fix idle trigger upon resume
  2009-05-11 18:34     ` Luis R. Rodriguez
@ 2009-05-11 18:53       ` Johannes Berg
  2009-05-11 19:09         ` Luis R. Rodriguez
  0 siblings, 1 reply; 16+ messages in thread
From: Johannes Berg @ 2009-05-11 18:53 UTC (permalink / raw)
  To: Luis R. Rodriguez; +Cc: linux-wireless

[-- Attachment #1: Type: text/plain, Size: 654 bytes --]

On Mon, 2009-05-11 at 11:34 -0700, Luis R. Rodriguez wrote:

> > Also, __ieee80211_queues_stopped_by_reason is misnamed since it checks
> > only a single queue. I also think that we can do this much better by
> > keeping track of the suspend state in a new variable rather than looking
> > at all the queues; even just checking queue 0 would be sufficient, but I
> > think a new variable is warranted.
> 
> A global variable for going to suspend? Hm, do we have a system wide
> thing for this instead?

No, and even then we couldn't use it I think since you can have
per-device suspend. I was just thinking of a local->variable.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

* Re: [RFC 3/5] mac80211: fix idle trigger upon resume
  2009-05-11 18:53       ` Johannes Berg
@ 2009-05-11 19:09         ` Luis R. Rodriguez
  2009-05-15  0:32           ` Luis R. Rodriguez
  0 siblings, 1 reply; 16+ messages in thread
From: Luis R. Rodriguez @ 2009-05-11 19:09 UTC (permalink / raw)
  To: Johannes Berg; +Cc: Luis Rodriguez, linux-wireless

On Mon, May 11, 2009 at 11:53:30AM -0700, Johannes Berg wrote:
> On Mon, 2009-05-11 at 11:34 -0700, Luis R. Rodriguez wrote:
> 
> > > Also, __ieee80211_queues_stopped_by_reason is misnamed since it checks
> > > only a single queue. I also think that we can do this much better by
> > > keeping track of the suspend state in a new variable rather than looking
> > > at all the queues; even just checking queue 0 would be sufficient, but I
> > > think a new variable is warranted.
> > 
> > A global variable for going to suspend? Hm, do we have a system wide
> > thing for this instead?
> 
> No, and even then we couldn't use it I think since you can have
> per-device suspend. I was just thinking of a local->variable.

OK thanks will add this.

  Luis

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

* Re: [RFC 3/5] mac80211: fix idle trigger upon resume
  2009-05-11 19:09         ` Luis R. Rodriguez
@ 2009-05-15  0:32           ` Luis R. Rodriguez
  2009-05-15  1:33             ` Luis R. Rodriguez
  0 siblings, 1 reply; 16+ messages in thread
From: Luis R. Rodriguez @ 2009-05-15  0:32 UTC (permalink / raw)
  To: Luis Rodriguez; +Cc: Johannes Berg, linux-wireless

On Mon, May 11, 2009 at 12:09:22PM -0700, Luis Rodriguez wrote:
> On Mon, May 11, 2009 at 11:53:30AM -0700, Johannes Berg wrote:
> > On Mon, 2009-05-11 at 11:34 -0700, Luis R. Rodriguez wrote:
> >
> > > > Also, __ieee80211_queues_stopped_by_reason is misnamed since it checks
> > > > only a single queue. I also think that we can do this much better by
> > > > keeping track of the suspend state in a new variable rather than looking
> > > > at all the queues; even just checking queue 0 would be sufficient, but I
> > > > think a new variable is warranted.
> > >
> > > A global variable for going to suspend? Hm, do we have a system wide
> > > thing for this instead?
> >
> > No, and even then we couldn't use it I think since you can have
> > per-device suspend. I was just thinking of a local->variable.
> 
> OK thanks will add this.

So I've added the WARN_ON() here as we agreed to investigate on irc. Turns out
we hit it several times as expected. We hit it while going to suspend
once, and then on resume 3 times.

[ 3170.261817] [drm:i915_get_vblank_counter] *ERROR* trying to get vblank count for disabled pipe 1
[ 3171.554210] PM: Syncing filesystems ... done.
[ 3171.559911] PM: Preparing system for mem sleep
[ 3171.559923] Freezing user space processes ... (elapsed 0.00 seconds) done.
[ 3171.560454] Freezing remaining freezable tasks ... (elapsed 0.00 seconds) done.
[ 3171.560510] PM: Entering mem sleep
[ 3171.560522] Suspending console(s) (use no_console_suspend to debug)
[ 3171.595622] ath9k 0000:16:00.0: PCI INT A disabled
[ 3171.608155] pci 0000:00:02.0: power state changed by ACPI to D3
[ 3171.888073] sd 0:0:0:0: [sda] Synchronizing SCSI cache
[ 3171.888237] sd 0:0:0:0: [sda] Stopping disk
[ 3173.348906] serial 00:0a: disabled
[ 3173.349469] ata_piix 0000:00:1f.2: PCI INT B disabled
[ 3173.364098] ehci_hcd 0000:00:1d.7: PCI INT D disabled
[ 3173.364184] ehci_hcd 0000:00:1d.7: PME# disabled
[ 3173.382790] ehci_hcd 0000:00:1d.7: power state changed by ACPI to D3
[ 3173.382810] uhci_hcd 0000:00:1d.2: PCI INT C disabled
[ 3173.382882] uhci_hcd 0000:00:1d.1: PCI INT B disabled
[ 3173.382950] uhci_hcd 0000:00:1d.0: PCI INT A disabled
[ 3173.383002] pciehp 0000:00:1c.3:pcie04: pciehp_suspend ENTRY
[ 3173.396326] HDA Intel 0000:00:1b.0: PCI INT B disabled
[ 3173.412104] ehci_hcd 0000:00:1a.7: PCI INT C disabled
[ 3173.412187] ehci_hcd 0000:00:1a.7: PME# disabled
[ 3173.430396] ehci_hcd 0000:00:1a.7: power state changed by ACPI to D3
[ 3173.430415] uhci_hcd 0000:00:1a.1: PCI INT B disabled
[ 3173.430486] uhci_hcd 0000:00:1a.0: PCI INT A disabled
[ 3173.433137] e1000e 0000:00:19.0: PCI INT A disabled
[ 3173.433145] e1000e 0000:00:19.0: PME# enabled
[ 3173.433151] e1000e 0000:00:19.0: wake-up capability enabled by ACPI
[ 3173.448119] ACPI handle has no context!
[ 3173.464117] PM: suspend devices took 1.908 seconds
[ 3173.524081] ------------[ cut here ]------------
[ 3173.524085] WARNING: at net/mac80211/iface.c:935 warn_slowpath_null+0x1c/0x20()
[ 3173.524087] Hardware name: 7660A14
[ 3173.524088] Modules linked in: nls_cp437 ntfs vfat msdos fat ext2 aes_generic ath9k rfkill af_packet i915 drm sco bridge stp llc rfcomm bnep l2cap bluetooth ipv6 acpi_cpufreq cpufreq_powersave cpufreq_ondemand cpufreq_stats freq_table cpufreq_userspace cpufreq_conservative sbs container pci_slot sbshc snd_hda_codec_analog arc4 ecb snd_hda_intel snd_hda_codec snd_pcm snd_seq mac80211 snd_timer snd_seq_device led_class joydev ath usbhid snd serio_raw hid ac soundcore intel_agp battery cfg80211 video wmi snd_page_alloc pcspkr button processor psmouse evdev ext3 jbd mbcache sg sr_mod sd_mod cdrom crc_t10dif ata_piix ata_generic pata_acpi ehci_hcd uhci_hcd libata scsi_mod usbcore thermal fan fuse e1000e [last unloaded: ath5k]
[ 3173.524146] Pid: 5567, comm: phy1 Not tainted 2.6.30-rc5-wl #89
[ 3173.524148] Call Trace:
[ 3173.524154]  [<c04edd84>] ? printk+0x18/0x1c
[ 3173.524157]  [<c02315eb>] warn_slowpath_fmt+0x7b/0xd0
[ 3173.524161]  [<c022d00f>] ? update_curr+0x21f/0x230
[ 3173.524164]  [<c022d116>] ? dequeue_entity+0x16/0x2c0
[ 3173.524167]  [<c022d428>] ? dequeue_task_fair+0x68/0x70
[ 3173.524171]  [<c021f00a>] ? dequeue_task+0x10a/0x160
[ 3173.524174]  [<c023165c>] warn_slowpath_null+0x1c/0x20
[ 3173.524191]  [<f85cb06b>] __ieee80211_recalc_idle+0x14b/0x160 [mac80211]
[ 3173.524205]  [<f85cb0a7>] ieee80211_recalc_idle+0x27/0x50 [mac80211]
[ 3173.524219]  [<f85caa8f>] ieee80211_sta_work+0xdf/0x570 [mac80211]
[ 3173.524223]  [<c023b571>] ? add_timer+0x11/0x20
[ 3173.524226]  [<c0242d5b>] ? queue_delayed_work_on+0x9b/0xd0
[ 3173.524236]  [<c02423c3>] worker_thread+0x143/0x210
[ 3173.524239]  [<c021fa28>] ? __wake_up_common+0x48/0x70
[ 3173.524255]  [<f85ca9b0>] ? ieee80211_sta_work+0x0/0x570 [mac80211]
[ 3173.524259]  [<c0246230>] ? autoremove_wake_function+0x0/0x50
[ 3173.524266]  [<c0242280>] ? worker_thread+0x0/0x210
[ 3173.524270]  [<c0245ec6>] kthread+0x46/0x80
[ 3173.524272]  [<c0245e80>] ? kthread+0x0/0x80
[ 3173.524276]  [<c0203a8f>] kernel_thread_helper+0x7/0x18
[ 3173.524278] ---[ end trace 0c9ec377fc490a14 ]---
[ 3173.608088] ACPI: Preparing to enter system sleep state S3
[ 3174.200263] Disabling non-boot CPUs ...
[ 3174.304021] CPU 1 is now offline
[ 3174.304025] SMP alternatives: switching to UP code
[ 3174.309720] CPU0 attaching NULL sched-domain.
[ 3174.309723] CPU1 attaching NULL sched-domain.
[ 3174.309729] CPU0 attaching NULL sched-domain.
[ 3174.309871] CPU1 is down
[ 3174.309927] Extended CMOS year: 2000
[ 3174.309927] Back to C!
[ 3174.309927] Extended CMOS year: 2000
[ 3174.309927] Enabling non-boot CPUs ...
[ 3174.309927] SMP alternatives: switching to SMP code
[ 3174.315029] Booting processor 1 APIC 0x1 ip 0x6000
[ 3174.309581] Initializing CPU#1
[ 3174.309581] Calibrating delay using timer specific routine.. 3591.00 BogoMIPS (lpj=7182017)
[ 3174.309581] CPU: L1 I cache: 32K, L1 D cache: 32K
[ 3174.309581] CPU: L2 cache: 2048K
[ 3174.309581] CPU: Physical Processor ID: 0
[ 3174.309581] CPU: Processor Core ID: 1
[ 3174.404425] CPU1: Intel(R) Core(TM)2 Duo CPU     T7100  @ 1.80GHz stepping 0d
[ 3174.404499] CPU0 attaching NULL sched-domain.
[ 3174.405022] Switched to high resolution mode on CPU 1
[ 3174.420023] CPU0 attaching sched-domain:
[ 3174.420026]  domain 0: span 0-1 level MC
[ 3174.420028]   groups: 0 1
[ 3174.420032] CPU1 attaching sched-domain:
[ 3174.420034]  domain 0: span 0-1 level MC
[ 3174.420037]   groups: 1 0
[ 3174.421029] CPU1 is up
[ 3174.421032] ACPI: Waking up from system sleep state S3
[ 3175.524029] ------------[ cut here ]------------
[ 3175.524032] WARNING: at net/mac80211/iface.c:935 warn_slowpath_null+0x1c/0x20()
[ 3175.524034] Hardware name: 7660A14
[ 3175.524036] Modules linked in: nls_cp437 ntfs vfat msdos fat ext2 aes_generic ath9k rfkill af_packet i915 drm sco bridge stp llc rfcomm bnep l2cap bluetooth ipv6 acpi_cpufreq cpufreq_powersave cpufreq_ondemand cpufreq_stats freq_table cpufreq_userspace cpufreq_conservative sbs container pci_slot sbshc snd_hda_codec_analog arc4 ecb snd_hda_intel snd_hda_codec snd_pcm snd_seq mac80211 snd_timer snd_seq_device led_class joydev ath usbhid snd serio_raw hid ac soundcore intel_agp battery cfg80211 video wmi snd_page_alloc pcspkr button processor psmouse evdev ext3 jbd mbcache sg sr_mod sd_mod cdrom crc_t10dif ata_piix ata_generic pata_acpi ehci_hcd uhci_hcd libata scsi_mod usbcore thermal fan fuse e1000e [last unloaded: ath5k]
[ 3175.524092] Pid: 5567, comm: phy1 Tainted: G        W  2.6.30-rc5-wl #89
[ 3175.524094] Call Trace:
[ 3175.524100]  [<c04edd84>] ? printk+0x18/0x1c
[ 3175.524103]  [<c02315eb>] warn_slowpath_fmt+0x7b/0xd0
[ 3175.524107]  [<c022d00f>] ? update_curr+0x21f/0x230
[ 3175.524110]  [<c022d116>] ? dequeue_entity+0x16/0x2c0
[ 3175.524114]  [<c022d428>] ? dequeue_task_fair+0x68/0x70
[ 3175.524117]  [<c021f00a>] ? dequeue_task+0x10a/0x160
[ 3175.524121]  [<c023165c>] warn_slowpath_null+0x1c/0x20
[ 3175.524138]  [<f85cb06b>] __ieee80211_recalc_idle+0x14b/0x160 [mac80211]
[ 3175.524152]  [<f85cb0a7>] ieee80211_recalc_idle+0x27/0x50 [mac80211]
[ 3175.524165]  [<f85caa8f>] ieee80211_sta_work+0xdf/0x570 [mac80211]
[ 3175.524169]  [<c023b571>] ? add_timer+0x11/0x20
[ 3175.524172]  [<c0242d5b>] ? queue_delayed_work_on+0x9b/0xd0
[ 3175.524182]  [<c02423c3>] worker_thread+0x143/0x210
[ 3175.524185]  [<c021fa28>] ? __wake_up_common+0x48/0x70
[ 3175.524200]  [<f85ca9b0>] ? ieee80211_sta_work+0x0/0x570 [mac80211]
[ 3175.524204]  [<c0246230>] ? autoremove_wake_function+0x0/0x50
[ 3175.524211]  [<c0242280>] ? worker_thread+0x0/0x210
[ 3175.524214]  [<c0245ec6>] kthread+0x46/0x80
[ 3175.524217]  [<c0245e80>] ? kthread+0x0/0x80
[ 3175.524221]  [<c0203a8f>] kernel_thread_helper+0x7/0x18
[ 3175.524224] ---[ end trace 0c9ec377fc490a15 ]---
[ 3175.524228] wlan2: beacon loss from AP 00:0b:85:5b:8d:6c - sending probe request
[ 3175.700200] pci 0000:00:02.0: restoring config space at offset 0x1 (was 0x900007, writing 0x900403)
[ 3175.700230] pci 0000:00:02.1: restoring config space at offset 0x1 (was 0x900000, writing 0x900007)
[ 3175.700243] pci 0000:00:03.0: restoring config space at offset 0xf (was 0x100, writing 0x10a)
[ 3175.700257] pci 0000:00:03.0: restoring config space at offset 0x1 (was 0x180006, writing 0x100006)
[ 3175.700272] pci 0000:00:03.2: restoring config space at offset 0xf (was 0x300, writing 0x30b)
[ 3175.700286] pci 0000:00:03.2: restoring config space at offset 0x1 (was 0xb00004, writing 0xb00001)
[ 3175.700301] serial 0000:00:03.3: restoring config space at offset 0xf (was 0x200, writing 0x20b)
[ 3175.700459] uhci_hcd 0000:00:1a.0: restoring config space at offset 0x1 (was 0x2800005, writing 0x2800001)
[ 3175.900092] uhci_hcd 0000:00:1a.1: power state changed by ACPI to D0
[ 3175.900143] uhci_hcd 0000:00:1a.1: restoring config space at offset 0x1 (was 0x2800005, writing 0x2800001)
[ 3175.900212] ehci_hcd 0000:00:1a.7: restoring config space at offset 0x1 (was 0x2900106, writing 0x2900102)
[ 3175.900308] HDA Intel 0000:00:1b.0: restoring config space at offset 0x1 (was 0x100106, writing 0x100102)
[ 3175.900402] pcieport-driver 0000:00:1c.0: restoring config space at offset 0x7 (was 0x20002020, writing 0x2020)
[ 3175.900422] pcieport-driver 0000:00:1c.0: restoring config space at offset 0x1 (was 0x100107, writing 0x100507)
[ 3175.900570] pcieport-driver 0000:00:1c.1: restoring config space at offset 0x1 (was 0x100107, writing 0x100507)
[ 3175.900704] pcieport-driver 0000:00:1c.2: restoring config space at offset 0x7 (was 0x20004040, writing 0x4040)
[ 3175.900733] pcieport-driver 0000:00:1c.2: restoring config space at offset 0x1 (was 0x100107, writing 0x100507)
[ 3175.900864] pcieport-driver 0000:00:1c.3: restoring config space at offset 0x7 (was 0x20005050, writing 0x5050)
[ 3175.900891] pcieport-driver 0000:00:1c.3: restoring config space at offset 0x1 (was 0x100107, writing 0x100507)
[ 3175.901016] pcieport-driver 0000:00:1c.4: restoring config space at offset 0x7 (was 0x20006060, writing 0x6060)
[ 3175.901036] pcieport-driver 0000:00:1c.4: restoring config space at offset 0x1 (was 0x100107, writing 0x100507)
[ 3175.932093] uhci_hcd 0000:00:1d.0: power state changed by ACPI to D0
[ 3175.932143] uhci_hcd 0000:00:1d.0: restoring config space at offset 0x1 (was 0x2800005, writing 0x2800001)
[ 3175.932201] uhci_hcd 0000:00:1d.1: restoring config space at offset 0x1 (was 0x2800005, writing 0x2800001)
[ 3175.964093] uhci_hcd 0000:00:1d.2: power state changed by ACPI to D0
[ 3175.964143] uhci_hcd 0000:00:1d.2: restoring config space at offset 0x1 (was 0x2800005, writing 0x2800001)
[ 3175.964222] ehci_hcd 0000:00:1d.7: restoring config space at offset 0x1 (was 0x2900106, writing 0x2900102)
[ 3175.964307] pci 0000:00:1e.0: restoring config space at offset 0x1 (was 0x100005, writing 0x100007)
[ 3175.964473] ata_piix 0000:00:1f.2: restoring config space at offset 0x1 (was 0x2b00005, writing 0x2b80005)
[ 3175.964611] pci 0000:03:00.0: restoring config space at offset 0x1 (was 0x100107, writing 0x100103)
[ 3175.964868] ath9k 0000:16:00.0: restoring config space at offset 0xf (was 0xffffffff, writing 0x110)
[ 3175.964878] ath9k 0000:16:00.0: restoring config space at offset 0xe (was 0xffffffff, writing 0x0)
[ 3175.964889] ath9k 0000:16:00.0: restoring config space at offset 0xd (was 0xffffffff, writing 0x40)
[ 3175.964899] ath9k 0000:16:00.0: restoring config space at offset 0xc (was 0xffffffff, writing 0x0)
[ 3175.964908] ath9k 0000:16:00.0: restoring config space at offset 0xb (was 0xffffffff, writing 0x1072168c)
[ 3175.964918] ath9k 0000:16:00.0: restoring config space at offset 0xa (was 0xffffffff, writing 0x0)
[ 3175.964928] ath9k 0000:16:00.0: restoring config space at offset 0x9 (was 0xffffffff, writing 0x0)
[ 3175.964937] ath9k 0000:16:00.0: restoring config space at offset 0x8 (was 0xffffffff, writing 0x0)
[ 3175.964947] ath9k 0000:16:00.0: restoring config space at offset 0x7 (was 0xffffffff, writing 0x0)
[ 3175.964957] ath9k 0000:16:00.0: restoring config space at offset 0x6 (was 0xffffffff, writing 0x0)
[ 3175.964966] ath9k 0000:16:00.0: restoring config space at offset 0x5 (was 0xffffffff, writing 0x0)
[ 3175.964974] ath9k 0000:16:00.0: restoring config space at offset 0x4 (was 0xffffffff, writing 0x40000000)
[ 3175.964985] ath9k 0000:16:00.0: restoring config space at offset 0x3 (was 0xffffffff, writing 0xa810)
[ 3175.964995] ath9k 0000:16:00.0: restoring config space at offset 0x2 (was 0xffffffff, writing 0x2800001)
[ 3175.965002] ath9k 0000:16:00.0: restoring config space at offset 0x1 (was 0xffffffff, writing 0x2b00006)
[ 3175.965011] ath9k 0000:16:00.0: restoring config space at offset 0x0 (was 0xffffffff, writing 0x23168c)
[ 3176.938085] pci 0000:00:02.0: PME# disabled
[ 3176.938091] pci 0000:00:02.1: PME# disabled
[ 3176.938095] pci 0000:00:03.0: PME# disabled
[ 3176.938098] pci 0000:00:03.2: PME# disabled
[ 3176.938236] e1000e 0000:00:19.0: PCI INT A -> GSI 20 (level, low) -> IRQ 20
[ 3176.938238] e1000e 0000:00:19.0: pci_enable_pcie_error_reporting failed 0xfffffffb
[ 3176.938248] e1000e 0000:00:19.0: setting latency timer to 64
[ 3176.938255] e1000e 0000:00:19.0: wake-up capability disabled by ACPI
[ 3176.938260] e1000e 0000:00:19.0: PME# disabled
[ 3176.938262] e1000e 0000:00:19.0: wake-up capability disabled by ACPI
[ 3176.938268] e1000e 0000:00:19.0: PME# disabled
[ 3176.938356] e1000e 0000:00:19.0: irq 29 for MSI/MSI-X
[ 3177.218415] uhci_hcd 0000:00:1a.0: PCI INT A -> GSI 20 (level, low) -> IRQ 20
[ 3177.218427] uhci_hcd 0000:00:1a.0: setting latency timer to 64
[ 3177.218460] usb usb1: root hub lost power or was reset
[ 3177.218541] uhci_hcd 0000:00:1a.1: PCI INT B -> GSI 21 (level, low) -> IRQ 21
[ 3177.218549] uhci_hcd 0000:00:1a.1: setting latency timer to 64
[ 3177.218581] usb usb2: root hub lost power or was reset
[ 3177.218673] ehci_hcd 0000:00:1a.7: PME# disabled
[ 3177.218678] ehci_hcd 0000:00:1a.7: PCI INT C -> GSI 22 (level, low) -> IRQ 22
[ 3177.218689] ehci_hcd 0000:00:1a.7: setting latency timer to 64
[ 3177.218702] ehci_hcd 0000:00:1a.7: PME# disabled
[ 3177.218812] HDA Intel 0000:00:1b.0: PCI INT B -> GSI 17 (level, low) -> IRQ 17
[ 3177.218823] HDA Intel 0000:00:1b.0: setting latency timer to 64
[ 3177.218851] pciehp 0000:00:1c.3:pcie04: pciehp_resume ENTRY
[ 3177.218911] uhci_hcd 0000:00:1d.0: PCI INT A -> GSI 16 (level, low) -> IRQ 16
[ 3177.218922] uhci_hcd 0000:00:1d.0: setting latency timer to 64
[ 3177.218954] usb usb3: root hub lost power or was reset
[ 3177.219020] uhci_hcd 0000:00:1d.1: PCI INT B -> GSI 17 (level, low) -> IRQ 17
[ 3177.219033] uhci_hcd 0000:00:1d.1: setting latency timer to 64
[ 3177.219059] usb usb5: root hub lost power or was reset
[ 3177.219134] uhci_hcd 0000:00:1d.2: PCI INT C -> GSI 18 (level, low) -> IRQ 18
[ 3177.219142] uhci_hcd 0000:00:1d.2: setting latency timer to 64
[ 3177.219171] usb usb7: root hub lost power or was reset
[ 3177.219274] ehci_hcd 0000:00:1d.7: PME# disabled
[ 3177.219280] ehci_hcd 0000:00:1d.7: PCI INT D -> GSI 19 (level, low) -> IRQ 19
[ 3177.219291] ehci_hcd 0000:00:1d.7: setting latency timer to 64
[ 3177.219302] ehci_hcd 0000:00:1d.7: PME# disabled
[ 3177.219319] pci 0000:00:1e.0: setting latency timer to 64
[ 3177.219379] ata_piix 0000:00:1f.2: restoring config space at offset 0x1 (was 0x2b00005, writing 0x2b80005)
[ 3177.219403] ata_piix 0000:00:1f.2: PCI INT B -> GSI 16 (level, low) -> IRQ 16
[ 3177.219413] ata_piix 0000:00:1f.2: setting latency timer to 64
[ 3177.221121] pci 0000:03:00.0: PME# disabled
[ 3177.385008] ata2.00: ACPI cmd ef/03:42:00:00:00:a0 filtered out
[ 3177.385011] ata2.00: ACPI cmd ef/03:0c:00:00:00:a0 filtered out
[ 3177.385284] ata2.00: ACPI cmd e3/00:1f:00:00:00:a0 succeeded
[ 3177.385561] ata2.00: ACPI cmd e3/00:02:00:00:00:a0 succeeded
[ 3177.401186] ata1.00: ACPI cmd ef/02:00:00:00:00:a0 succeeded
[ 3177.401189] ata1.00: ACPI cmd f5/00:00:00:00:00:a0 filtered out
[ 3177.401192] ata1.00: ACPI cmd ef/03:45:00:00:00:a0 filtered out
[ 3177.401195] ata1.00: ACPI cmd ef/03:0c:00:00:00:a0 filtered out
[ 3177.401575] ata1.00: ACPI cmd ef/5f:00:00:00:00:a0 succeeded
[ 3177.401577] ata1.00: ACPI cmd ef/10:03:00:00:00:a0 filtered out
[ 3177.408783] ata2.00: configured for UDMA/33
[ 3177.424691] ata1.00: configured for UDMA/133
[ 3177.448684] ata1.00: configured for UDMA/133
[ 3177.448686] ata1: EH complete
[ 3177.524079] ------------[ cut here ]------------
[ 3177.524082] WARNING: at net/mac80211/iface.c:935 warn_slowpath_null+0x1c/0x20()
[ 3177.524083] Hardware name: 7660A14
[ 3177.524085] Modules linked in: nls_cp437 ntfs vfat msdos fat ext2 aes_generic ath9k rfkill af_packet i915 drm sco bridge stp llc rfcomm bnep l2cap bluetooth ipv6 acpi_cpufreq cpufreq_powersave cpufreq_ondemand cpufreq_stats freq_table cpufreq_userspace cpufreq_conservative sbs container pci_slot sbshc snd_hda_codec_analog arc4 ecb snd_hda_intel snd_hda_codec snd_pcm snd_seq mac80211 snd_timer snd_seq_device led_class joydev ath usbhid snd serio_raw hid ac soundcore intel_agp battery cfg80211 video wmi snd_page_alloc pcspkr button processor psmouse evdev ext3 jbd mbcache sg sr_mod sd_mod cdrom crc_t10dif ata_piix ata_generic pata_acpi ehci_hcd uhci_hcd libata scsi_mod usbcore thermal fan fuse e1000e [last unloaded: ath5k]
[ 3177.524144] Pid: 5567, comm: phy1 Tainted: G        W  2.6.30-rc5-wl #89
[ 3177.524145] Call Trace:
[ 3177.524151]  [<c04edd84>] ? printk+0x18/0x1c
[ 3177.524154]  [<c02315eb>] warn_slowpath_fmt+0x7b/0xd0
[ 3177.524157]  [<c022d00f>] ? update_curr+0x21f/0x230
[ 3177.524160]  [<c022d116>] ? dequeue_entity+0x16/0x2c0
[ 3177.524164]  [<c02219a7>] ? set_next_entity+0xa7/0x190
[ 3177.524167]  [<c023165c>] warn_slowpath_null+0x1c/0x20
[ 3177.524183]  [<f85cb06b>] __ieee80211_recalc_idle+0x14b/0x160 [mac80211]
[ 3177.524196]  [<f85cb0a7>] ieee80211_recalc_idle+0x27/0x50 [mac80211]
[ 3177.524208]  [<f85caa8f>] ieee80211_sta_work+0xdf/0x570 [mac80211]
[ 3177.524211]  [<c023b571>] ? add_timer+0x11/0x20
[ 3177.524214]  [<c0242d5b>] ? queue_delayed_work_on+0x9b/0xd0
[ 3177.524223]  [<c02423c3>] worker_thread+0x143/0x210
[ 3177.524226]  [<c021fa28>] ? __wake_up_common+0x48/0x70
[ 3177.524239]  [<f85ca9b0>] ? ieee80211_sta_work+0x0/0x570 [mac80211]
[ 3177.524243]  [<c0246230>] ? autoremove_wake_function+0x0/0x50
[ 3177.524250]  [<c0242280>] ? worker_thread+0x0/0x210
[ 3177.524252]  [<c0245ec6>] kthread+0x46/0x80
[ 3177.524255]  [<c0245e80>] ? kthread+0x0/0x80
[ 3177.524258]  [<c0203a8f>] kernel_thread_helper+0x7/0x18
[ 3177.524260] ---[ end trace 0c9ec377fc490a16 ]---
[ 3177.524264] wlan2: no probe response from AP 00:0b:85:5b:8d:6c - disassociating
[ 3177.524327] ------------[ cut here ]------------
[ 3177.524329] WARNING: at net/mac80211/iface.c:935 warn_slowpath_null+0x1c/0x20()
[ 3177.524330] Hardware name: 7660A14
[ 3177.524331] Modules linked in: nls_cp437 ntfs vfat msdos fat ext2 aes_generic ath9k rfkill af_packet i915 drm sco bridge stp llc rfcomm bnep l2cap bluetooth ipv6 acpi_cpufreq cpufreq_powersave cpufreq_ondemand cpufreq_stats freq_table cpufreq_userspace cpufreq_conservative sbs container pci_slot sbshc snd_hda_codec_analog arc4 ecb snd_hda_intel snd_hda_codec snd_pcm snd_seq mac80211 snd_timer snd_seq_device led_class joydev ath usbhid snd serio_raw hid ac soundcore intel_agp battery cfg80211 video wmi snd_page_alloc pcspkr button processor psmouse evdev ext3 jbd mbcache sg sr_mod sd_mod cdrom crc_t10dif ata_piix ata_generic pata_acpi ehci_hcd uhci_hcd libata scsi_mod usbcore thermal fan fuse e1000e [last unloaded: ath5k]
[ 3177.524373] Pid: 5567, comm: phy1 Tainted: G        W  2.6.30-rc5-wl #89
[ 3177.524375] Call Trace:
[ 3177.524377]  [<c04edd84>] ? printk+0x18/0x1c
[ 3177.524380]  [<c02315eb>] warn_slowpath_fmt+0x7b/0xd0
[ 3177.524390]  [<f81808fa>] ? ath_txq_update+0xba/0xf0 [ath9k]
[ 3177.524394]  [<c04670bc>] ? skb_dequeue+0x4c/0x70
[ 3177.524403]  [<f8178d35>] ? ath9k_conf_tx+0x105/0x160 [ath9k]
[ 3177.524406]  [<c023165c>] warn_slowpath_null+0x1c/0x20
[ 3177.524420]  [<f85cb06b>] __ieee80211_recalc_idle+0x14b/0x160 [mac80211]
[ 3177.524432]  [<f85cb0a7>] ieee80211_recalc_idle+0x27/0x50 [mac80211]
[ 3177.524445]  [<f85c79e1>] ieee80211_set_disassoc+0x181/0x2a0 [mac80211]
[ 3177.524457]  [<f85c874c>] ieee80211_associated+0x13c/0x180 [mac80211]
[ 3177.524469]  [<f85cacf4>] ieee80211_sta_work+0x344/0x570 [mac80211]
[ 3177.524472]  [<c023b571>] ? add_timer+0x11/0x20
[ 3177.524474]  [<c0242d5b>] ? queue_delayed_work_on+0x9b/0xd0
[ 3177.524482]  [<c02423c3>] worker_thread+0x143/0x210
[ 3177.524485]  [<c021fa28>] ? __wake_up_common+0x48/0x70
[ 3177.524499]  [<f85ca9b0>] ? ieee80211_sta_work+0x0/0x570 [mac80211]
[ 3177.524502]  [<c0246230>] ? autoremove_wake_function+0x0/0x50
[ 3177.524509]  [<c0242280>] ? worker_thread+0x0/0x210
[ 3177.524511]  [<c0245ec6>] kthread+0x46/0x80
[ 3177.524514]  [<c0245e80>] ? kthread+0x0/0x80
[ 3177.524517]  [<c0203a8f>] kernel_thread_helper+0x7/0x18
[ 3177.524519] ---[ end trace 0c9ec377fc490a17 ]---
[ 3177.524524] phy1: Removed STA 00:0b:85:5b:8d:6c
[ 3177.536245] phy1: Destroyed STA 00:0b:85:5b:8d:6c
[ 3177.932085] pci 0000:15:00.1: PME# disabled
[ 3177.932837] serial 00:0a: activated
[ 3178.460099] sd 0:0:0:0: [sda] Starting disk
[ 3178.692063] usb 1-2: reset full speed USB device using uhci_hcd and address 2
[ 3178.992999] pci 0000:00:02.0: setting latency timer to 64
[ 3178.993982] ath9k 0000:16:00.0: enabling device (0000 -> 0002)
[ 3178.993990] ath9k 0000:16:00.0: PCI INT A -> GSI 16 (level, low) -> IRQ 16
[ 3178.994012] ath9k 0000:16:00.0: restoring config space at offset 0xf (was 0x100, writing 0x110)
[ 3178.994046] ath9k 0000:16:00.0: restoring config space at offset 0x4 (was 0x0, writing 0x40000000)
[ 3178.994052] ath9k 0000:16:00.0: restoring config space at offset 0x3 (was 0x0, writing 0xa810)
[ 3178.994063] ath9k 0000:16:00.0: restoring config space at offset 0x1 (was 0x2b00002, writing 0x2b00006)
[ 3179.028361] PM: resume devices took 3.064 seconds
[ 3179.028505] PM: Finishing wakeup.
[ 3179.028507] Restarting tasks ... done.
[ 3181.108801] phy1: device now idle
[ 3181.108814] phy1: device no longer idle - scanning
[ 3183.081870] wlan2: direct probe to AP 00:0b:85:5b:8d:63 try 1
[ 3183.082906] wlan2 direct probe responded
[ 3183.082912] wlan2: authenticate with AP 00:0b:85:5b:8d:63
[ 3183.084726] wlan2: authenticated
[ 3183.084731] wlan2: associate with AP 00:0b:85:5b:8d:63
[ 3183.089011] wlan2: RX ReassocResp from 00:0b:85:5b:8d:63 (capab=0x11 status=0 aid=194)
[ 3183.089024] wlan2: associated
[ 3183.089044] phy1: Allocated STA 00:0b:85:5b:8d:63
[ 3183.089061] phy1: Inserted STA 00:0b:85:5b:8d:63

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

* Re: [RFC 3/5] mac80211: fix idle trigger upon resume
  2009-05-15  0:32           ` Luis R. Rodriguez
@ 2009-05-15  1:33             ` Luis R. Rodriguez
  2009-05-15  2:18               ` Luis R. Rodriguez
  0 siblings, 1 reply; 16+ messages in thread
From: Luis R. Rodriguez @ 2009-05-15  1:33 UTC (permalink / raw)
  To: Luis Rodriguez; +Cc: Johannes Berg, linux-wireless

On Thu, May 14, 2009 at 5:32 PM, Luis R. Rodriguez
<lrodriguez@atheros.com> wrote:
> On Mon, May 11, 2009 at 12:09:22PM -0700, Luis Rodriguez wrote:
>> On Mon, May 11, 2009 at 11:53:30AM -0700, Johannes Berg wrote:
>> > On Mon, 2009-05-11 at 11:34 -0700, Luis R. Rodriguez wrote:
>> >
>> > > > Also, __ieee80211_queues_stopped_by_reason is misnamed since it checks
>> > > > only a single queue. I also think that we can do this much better by
>> > > > keeping track of the suspend state in a new variable rather than looking
>> > > > at all the queues; even just checking queue 0 would be sufficient, but I
>> > > > think a new variable is warranted.
>> > >
>> > > A global variable for going to suspend? Hm, do we have a system wide
>> > > thing for this instead?
>> >
>> > No, and even then we couldn't use it I think since you can have
>> > per-device suspend. I was just thinking of a local->variable.
>>
>> OK thanks will add this.
>
> So I've added the WARN_ON() here as we agreed to investigate on irc. Turns out
> we hit it several times as expected. We hit it while going to suspend
> once, and then on resume 3 times.

The trace doesn't help much except for acknowledging the issue I was
pointing out. The workqueue is run because we flush it, twice, during
suspend. The idle recalc is run because we call it within
ieee80211_sta_work(). If we want we can move the check for
local->suspended to ieee80211_sta_work() but then we'd have to set
local->suspended early on during suspend before the first flush and
that doesn't seem right. So I think the patch as I have it is fine
unless I'm missing something.

  Luis

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

* Re: [RFC 3/5] mac80211: fix idle trigger upon resume
  2009-05-15  1:33             ` Luis R. Rodriguez
@ 2009-05-15  2:18               ` Luis R. Rodriguez
  2009-05-15  8:01                 ` Johannes Berg
  0 siblings, 1 reply; 16+ messages in thread
From: Luis R. Rodriguez @ 2009-05-15  2:18 UTC (permalink / raw)
  To: Luis Rodriguez; +Cc: Johannes Berg, linux-wireless

On Thu, May 14, 2009 at 6:33 PM, Luis R. Rodriguez
<lrodriguez@atheros.com> wrote:
> On Thu, May 14, 2009 at 5:32 PM, Luis R. Rodriguez
> <lrodriguez@atheros.com> wrote:
>> On Mon, May 11, 2009 at 12:09:22PM -0700, Luis Rodriguez wrote:
>>> On Mon, May 11, 2009 at 11:53:30AM -0700, Johannes Berg wrote:
>>> > On Mon, 2009-05-11 at 11:34 -0700, Luis R. Rodriguez wrote:
>>> >
>>> > > > Also, __ieee80211_queues_stopped_by_reason is misnamed since it checks
>>> > > > only a single queue. I also think that we can do this much better by
>>> > > > keeping track of the suspend state in a new variable rather than looking
>>> > > > at all the queues; even just checking queue 0 would be sufficient, but I
>>> > > > think a new variable is warranted.
>>> > >
>>> > > A global variable for going to suspend? Hm, do we have a system wide
>>> > > thing for this instead?
>>> >
>>> > No, and even then we couldn't use it I think since you can have
>>> > per-device suspend. I was just thinking of a local->variable.
>>>
>>> OK thanks will add this.
>>
>> So I've added the WARN_ON() here as we agreed to investigate on irc. Turns out
>> we hit it several times as expected. We hit it while going to suspend
>> once, and then on resume 3 times.
>
> The trace doesn't help much except for acknowledging the issue I was
> pointing out. The workqueue is run because we flush it, twice, during
> suspend. The idle recalc is run because we call it within
> ieee80211_sta_work(). If we want we can move the check for
> local->suspended to ieee80211_sta_work() but then we'd have to set
> local->suspended early on during suspend before the first flush and
> that doesn't seem right. So I think the patch as I have it is fine
> unless I'm missing something.

Nevermind -- the last trace does show its called from disassoc -- and
we I don't think we should disassoc until we've come back from
suspend.

  Luis

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

* Re: [RFC 3/5] mac80211: fix idle trigger upon resume
  2009-05-15  2:18               ` Luis R. Rodriguez
@ 2009-05-15  8:01                 ` Johannes Berg
  0 siblings, 0 replies; 16+ messages in thread
From: Johannes Berg @ 2009-05-15  8:01 UTC (permalink / raw)
  To: Luis R. Rodriguez; +Cc: linux-wireless

[-- Attachment #1: Type: text/plain, Size: 557 bytes --]

On Thu, 2009-05-14 at 19:18 -0700, Luis R. Rodriguez wrote:

> >> So I've added the WARN_ON() here as we agreed to investigate on irc. Turns out
> >> we hit it several times as expected. We hit it while going to suspend
> >> once, and then on resume 3 times.

> Nevermind -- the last trace does show its called from disassoc -- and
> we I don't think we should disassoc until we've come back from
> suspend.

Yeah that bit is odd -- but like I said I think it's just the fact that
we don't cancel any of our timers or sync our work.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

end of thread, other threads:[~2009-05-15  8:01 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-05-11  9:24 [RFC 0/5] mac80211 suspend cleanups/helpers Luis R. Rodriguez
2009-05-11  9:25 ` [RFC 1/5] ath9k: do not stop the queues in driver stop Luis R. Rodriguez
2009-05-11  9:25 ` [RFC 2/5] adm8211: remove uneeded code during suspend/resume Luis R. Rodriguez
2009-05-11  9:25 ` [RFC 3/5] mac80211: fix idle trigger upon resume Luis R. Rodriguez
2009-05-11 10:01   ` Johannes Berg
2009-05-11 18:34     ` Luis R. Rodriguez
2009-05-11 18:53       ` Johannes Berg
2009-05-11 19:09         ` Luis R. Rodriguez
2009-05-15  0:32           ` Luis R. Rodriguez
2009-05-15  1:33             ` Luis R. Rodriguez
2009-05-15  2:18               ` Luis R. Rodriguez
2009-05-15  8:01                 ` Johannes Berg
2009-05-11  9:25 ` [RFC 4/5] mac80211: add a struct for info upon device stop Luis R. Rodriguez
2009-05-11  9:53   ` Johannes Berg
2009-05-11 18:33     ` Luis R. Rodriguez
2009-05-11  9:25 ` [RFC 5/5] ath9k: Add Wake-on-Wireless-LAN support Luis R. Rodriguez

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.