From 5db1c07ced19b2eec3a149a3c624d88e02e246ae Mon Sep 17 00:00:00 2001
From: Luciano Coelho <coelho@ti.com>
Date: Tue, 3 May 2011 21:40:08 +0300
Subject: [PATCH 1/4] mac80211: don't start the dynamic ps timer if not
 associated

When we are disconnecting, we set PS off, but this happens before we
send the deauth/disassoc request.  When the deauth/disassoc frames are
sent, we trigger the dynamic ps timer, which then times out and turns
PS back on.  Thus, PS remains on after disconnecting, causing problems
when associating again.

This can be fixed by preventing the timer to start when we're not
associated anymore.

Signed-off-by: Luciano Coelho <coelho@ti.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
---
 net/mac80211/tx.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index ce4596ed1268..bd1224fd216a 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -237,6 +237,10 @@ ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx)
 				     &local->dynamic_ps_disable_work);
 	}
 
+	/* Don't restart the timer if we're not disassociated */
+	if (!ifmgd->associated)
+		return TX_CONTINUE;
+
 	mod_timer(&local->dynamic_ps_timer, jiffies +
 		  msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
 

From 99aa55b66e3553e6f7212ec1104e0fac06cc558e Mon Sep 17 00:00:00 2001
From: Mohammed Shafi Shajakhan <mshajakhan@atheros.com>
Date: Fri, 6 May 2011 20:43:11 +0530
Subject: [PATCH 2/4] ath9k: Fix a warning due to a queued work during S3 state

during suspend/S3 state drv_flush is called from mac80211 irrespective of
interface count. In ath9k we queue a work in ath9k_flush which we expect
to be cancelled in the drv_stop call back. during suspend process mac80211
calls drv_stop only when the interface count(local->count) is non-zero.
unfortunately when the network manager is enabled, drv_flush is called
while drv_stop is not called as local->count reaches '0'.
	So fix this by simply checking for the device presence in the
drv_flush call back in the driver before queueing work or anything else.
this patch fixes the following WARNING

	Call Trace:
	[<c014c6e2>] warn_slowpath_common+0x72/0xa0
	[<fc133f99>] ? ieee80211_can_queue_work+0x39/0x50 [mac80211]
	[<fc133f99>] ? ieee80211_can_queue_work+0x39/0x50 [mac80211]
	[<c014c75b>] warn_slowpath_fmt+0x2b/0x30
	[<fc133f99>] ieee80211_can_queue_work+0x39/0x50 [mac80211]
	[<fc134ed1>] ieee80211_queue_delayed_work+0x21/0x50 [mac80211]
	[<fc1e5b22>] ath_tx_complete_poll_work+0xb2/0x100 [ath9k]
	[<c016399e>] run_workqueue+0x8e/0x150
	[<fc1e5a70>] ? ath_tx_complete_poll_work+0x0/0x100 [ath9k]
	[<c0163ae4>] worker_thread+0x84/0xe0
	[<c0167a60>] ? autoremove_wake_function+0x0/0x50
	[<c0163a60>] ? worker_thread+0x0/0xe0
	[<c01677d4>] kthread+0x74/0x80
	[<c0167760>] ? kthread+0x0/0x80
	[<c0104087>] kernel_thread_helper+0x7/0x10
---[ end trace 2aff81010df9215b ]---

Signed-off-by: Rajkumar Manoharan <rmanoharan@atheros.com>
Signed-off-by: Mohammed Shafi Shajakhan <mshajakhan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
---
 drivers/net/wireless/ath/ath9k/main.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 17d04ff8d678..1482fa650833 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -2141,6 +2141,8 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
 static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
 {
 	struct ath_softc *sc = hw->priv;
+	struct ath_hw *ah = sc->sc_ah;
+	struct ath_common *common = ath9k_hw_common(ah);
 	int timeout = 200; /* ms */
 	int i, j;
 
@@ -2149,6 +2151,12 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
 
 	cancel_delayed_work_sync(&sc->tx_complete_work);
 
+	if (sc->sc_flags & SC_OP_INVALID) {
+		ath_dbg(common, ATH_DBG_ANY, "Device not present\n");
+		mutex_unlock(&sc->mutex);
+		return;
+	}
+
 	if (drop)
 		timeout = 1;
 

From eb85de3f84868ca85703a23617b4079ce79a801e Mon Sep 17 00:00:00 2001
From: Stanislaw Gruszka <sgruszka@redhat.com>
Date: Sat, 7 May 2011 17:46:21 +0200
Subject: [PATCH 3/4] iwlegacy: fix IBSS mode crashes

We should not switch to non-IBSS channels when working in IBSS mode,
otherwise there are microcode errors, and after some time system
crashes.

This bug is only observable when software scan is used in IBSS mode,
so should be considered as regression after:

commit 0263aa45293838b514b8af674a03faf040991a90
Author: Stanislaw Gruszka <sgruszka@redhat.com>
Date:   Tue Mar 29 11:24:21 2011 +0200

    iwl3945: disable hw scan by default

However IBSS mode check, which this patch add again, was removed by

commit b2f30e8bdd8ef5f3b5a7ef9146509585a15347d3
Author: Johannes Berg <johannes.berg@intel.com>
Date:   Thu Jan 21 07:32:20 2010 -0800

    iwlwifi: remove IBSS channel sanity check

That commit claim that mac80211 will not use non-IBSS channel in IBSS
mode, what definitely is not true. Bug probably should be fixed in
mac80211, but that will require more work, so better to apply that patch
temporally, and provide proper mac80211 fix latter.

Resolves:
https://bugzilla.kernel.org/show_bug.cgi?id=34452

Reported-and-tested-by: Mikko Rapeli <mikko.rapeli@iki.fi>
Cc: stable@kernel.org # 2.6.38.5+
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
---
 drivers/net/wireless/iwlegacy/iwl-core.c | 7 +++++++
 drivers/net/wireless/iwlegacy/iwl-dev.h  | 6 ++++++
 2 files changed, 13 insertions(+)

diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c
index 2b08efb3b658..dcbb2ef27f22 100644
--- a/drivers/net/wireless/iwlegacy/iwl-core.c
+++ b/drivers/net/wireless/iwlegacy/iwl-core.c
@@ -2155,6 +2155,13 @@ int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed)
 			goto set_ch_out;
 		}
 
+		if (priv->iw_mode == NL80211_IFTYPE_ADHOC &&
+		    !iwl_legacy_is_channel_ibss(ch_info)) {
+			IWL_DEBUG_MAC80211(priv, "leave - not IBSS channel\n");
+			ret = -EINVAL;
+			goto set_ch_out;
+		}
+
 		spin_lock_irqsave(&priv->lock, flags);
 
 		for_each_context(priv, ctx) {
diff --git a/drivers/net/wireless/iwlegacy/iwl-dev.h b/drivers/net/wireless/iwlegacy/iwl-dev.h
index 9ee849d669f3..f43ac1eb9014 100644
--- a/drivers/net/wireless/iwlegacy/iwl-dev.h
+++ b/drivers/net/wireless/iwlegacy/iwl-dev.h
@@ -1411,6 +1411,12 @@ iwl_legacy_is_channel_passive(const struct iwl_channel_info *ch)
 	return (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) ? 1 : 0;
 }
 
+static inline int
+iwl_legacy_is_channel_ibss(const struct iwl_channel_info *ch)
+{
+	return (ch->flags & EEPROM_CHANNEL_IBSS) ? 1 : 0;
+}
+
 static inline void
 __iwl_legacy_free_pages(struct iwl_priv *priv, struct page *page)
 {

From 2ae1b8b35faba31a59b153cbad07f9c15de99740 Mon Sep 17 00:00:00 2001
From: Paul Fox <pgf@laptop.org>
Date: Mon, 9 May 2011 10:40:42 +0100
Subject: [PATCH 4/4] libertas: fix cmdpendingq locking

We occasionally see list corruption using libertas.

While we haven't been able to diagnose this precisely, we have spotted
a possible cause: cmdpendingq is generally modified with driver_lock
held. However, there are a couple of points where this is not the case.

Fix up those operations to execute under the lock, it seems like
the correct thing to do and will hopefully improve the situation.

Signed-off-by: Paul Fox <pgf@laptop.org>
Signed-off-by: Daniel Drake <dsd@laptop.org>
Acked-by: Dan Williams <dcbw@redhat.com>
Cc: stable@kernel.org
Signed-off-by: John W. Linville <linville@tuxdriver.com>
---
 drivers/net/wireless/libertas/cmd.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 7e8a658b7670..f3ac62431a30 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -1339,8 +1339,8 @@ int lbs_execute_next_command(struct lbs_private *priv)
 				    cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {
 					lbs_deb_host(
 					       "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
-					list_del(&cmdnode->list);
 					spin_lock_irqsave(&priv->driver_lock, flags);
+					list_del(&cmdnode->list);
 					lbs_complete_command(priv, cmdnode, 0);
 					spin_unlock_irqrestore(&priv->driver_lock, flags);
 
@@ -1352,8 +1352,8 @@ int lbs_execute_next_command(struct lbs_private *priv)
 				    (priv->psstate == PS_STATE_PRE_SLEEP)) {
 					lbs_deb_host(
 					       "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
-					list_del(&cmdnode->list);
 					spin_lock_irqsave(&priv->driver_lock, flags);
+					list_del(&cmdnode->list);
 					lbs_complete_command(priv, cmdnode, 0);
 					spin_unlock_irqrestore(&priv->driver_lock, flags);
 					priv->needtowakeup = 1;
@@ -1366,7 +1366,9 @@ int lbs_execute_next_command(struct lbs_private *priv)
 				       "EXEC_NEXT_CMD: sending EXIT_PS\n");
 			}
 		}
+		spin_lock_irqsave(&priv->driver_lock, flags);
 		list_del(&cmdnode->list);
+		spin_unlock_irqrestore(&priv->driver_lock, flags);
 		lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
 			    le16_to_cpu(cmd->command));
 		lbs_submit_command(priv, cmdnode);