diff mbox

[RFC,v2,1/2] mac80211: Fix a race on enabling power save.

Message ID 1297750589-15465-1-git-send-email-vnatarajan@atheros.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Vivek Natarajan Feb. 15, 2011, 6:16 a.m. UTC
None
diff mbox

Patch

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index f2ef15d..0933677 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -347,6 +347,7 @@  enum ieee80211_sta_flags {
 	IEEE80211_STA_UAPSD_ENABLED	= BIT(7),
 	IEEE80211_STA_NULLFUNC_ACKED	= BIT(8),
 	IEEE80211_STA_RESET_SIGNAL_AVE	= BIT(9),
+	IEEE80211_STA_PS_PENDING	= BIT(10),
 };
 
 struct ieee80211_if_managed {
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index d89e878..4c58769 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -738,16 +738,23 @@  void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
 		return;
 
 	if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
-	    (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)))
+	    (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED) ||
+	     !(ifmgd->flags & IEEE80211_STA_PS_PENDING))) {
+		ifmgd->flags |= IEEE80211_STA_PS_PENDING;
 		ieee80211_send_nullfunc(local, sdata, 1);
+	}
 
 	if (!((local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) &&
 	      (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) ||
-	    (ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)) {
+	    ((ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED) &&
+	      ifmgd->flags & IEEE80211_STA_PS_PENDING))  {
 		ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED;
+		ifmgd->flags &= ~IEEE80211_STA_PS_PENDING;
 		local->hw.conf.flags |= IEEE80211_CONF_PS;
 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
 	}
+	ieee80211_wake_queues_by_reason(&local->hw,
+					IEEE80211_QUEUE_STOP_REASON_PS);
 }
 
 void ieee80211_dynamic_ps_timer(unsigned long data)
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 010a559..51caa0d 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -315,7 +315,10 @@  void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 	    (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) &&
 	    !(info->flags & IEEE80211_TX_CTL_INJECTED) &&
 	    local->ps_sdata && !(local->scanning)) {
-		if (info->flags & IEEE80211_TX_STAT_ACK) {
+		if ((info->flags & IEEE80211_TX_STAT_ACK) &&
+		   (local->ps_sdata->u.mgd.flags & IEEE80211_STA_PS_PENDING)) {
+			ieee80211_stop_queues_by_reason(&local->hw,
+							IEEE80211_QUEUE_STOP_REASON_PS);
 			local->ps_sdata->u.mgd.flags |=
 					IEEE80211_STA_NULLFUNC_ACKED;
 			ieee80211_queue_work(&local->hw,
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 17ef4f4..9850284 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -185,6 +185,7 @@  ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx)
 {
 	struct ieee80211_local *local = tx->local;
 	struct ieee80211_if_managed *ifmgd;
+	struct ieee80211_hdr *hdr;
 
 	/* driver doesn't support power save */
 	if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
@@ -233,6 +234,13 @@  ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx)
 	    && skb_get_queue_mapping(tx->skb) == 0)
 		return TX_CONTINUE;
 
+	hdr = (struct ieee80211_hdr *)tx->skb->data;
+
+	if (!(ieee80211_is_nullfunc(hdr->frame_control) &&
+	     ieee80211_has_pm(hdr->frame_control)) &&
+	    (ifmgd->flags & IEEE80211_STA_PS_PENDING))
+		ifmgd->flags &= ~IEEE80211_STA_PS_PENDING;
+
 	if (local->hw.conf.flags & IEEE80211_CONF_PS) {
 		ieee80211_stop_queues_by_reason(&local->hw,
 						IEEE80211_QUEUE_STOP_REASON_PS);