[PATCH 58/99] cw1200: Fixes for multicast delivery in AP/UAPSD mode.

Dmitry Tarnyagin dmitry.tarnyagin at stericsson.com
Wed Feb 29 14:15:05 UTC 2012


* Powersave state of UAPSD STA must be explicitly forced to "PS",
  mac80211 stack provides no PS notification for these STAs.
* Mcast timeout was wrongly triggered due to wrongly used
  mod_timer call.
* tx_multicast flag was not reset in case of successful mcast
  delivery.
* FW may requeue a multicast frame. To deliver the frame, driver
  should start a new multicast session: set AID0 and wait for
  suspend/resume indication.
* Due to a race with requeue a multicast-stop work could override
  a started multicast sequence in progress.

ST-Ericsson ID: 361427

Change-Id: I42cfa14f5814c0e6a20b03e9fdf0d38e80288c3d
Signed-off-by: Dmitry Tarnyagin <dmitry.tarnyagin at stericsson.com>
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/39979
Reviewed-by: Bartosz MARKOWSKI <bartosz.markowski at tieto.com>
Tested-by: Bartosz MARKOWSKI <bartosz.markowski at tieto.com>
---
 drivers/staging/cw1200/ap.c   |    9 ++++++++-
 drivers/staging/cw1200/txrx.c |    9 +++++++++
 drivers/staging/cw1200/wsm.c  |    4 +++-
 3 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/cw1200/ap.c b/drivers/staging/cw1200/ap.c
index f58ccb1..ff8d36c 100755
--- a/drivers/staging/cw1200/ap.c
+++ b/drivers/staging/cw1200/ap.c
@@ -59,6 +59,8 @@ int cw1200_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 
 	entry = &priv->link_id_db[sta_priv->link_id - 1];
 	spin_lock_bh(&priv->ps_state_lock);
+	if (sta->uapsd_queues)
+		priv->sta_asleep_mask |= BIT(sta_priv->link_id);
 	entry->status = CW1200_LINK_HARD;
 	while ((skb = skb_dequeue(&entry->rx_queue)))
 		ieee80211_rx_irqsafe(priv->hw, skb);
@@ -617,11 +619,13 @@ void cw1200_multicast_start_work(struct work_struct *work)
 	long tmo = priv->join_dtim_period *
 			(priv->beacon_int + 20) * HZ / 1024;
 
+	cancel_work_sync(&priv->multicast_stop_work);
+
 	if (!priv->aid0_bit_set) {
 		wsm_lock_tx(priv);
 		cw1200_set_tim_impl(priv, true);
 		priv->aid0_bit_set = true;
-		mod_timer(&priv->mcast_timeout, tmo);
+		mod_timer(&priv->mcast_timeout, jiffies + tmo);
 		wsm_unlock_tx(priv);
 	}
 }
@@ -632,6 +636,7 @@ void cw1200_multicast_stop_work(struct work_struct *work)
 		container_of(work, struct cw1200_common, multicast_stop_work);
 
 	if (priv->aid0_bit_set) {
+		del_timer_sync(&priv->mcast_timeout);
 		wsm_lock_tx(priv);
 		priv->aid0_bit_set = false;
 		cw1200_set_tim_impl(priv, false);
@@ -644,6 +649,8 @@ void cw1200_mcast_timeout(unsigned long arg)
 	struct cw1200_common *priv =
 		(struct cw1200_common *)arg;
 
+	wiphy_warn(priv->hw->wiphy,
+		"Multicast delivery timeout.\n");
 	spin_lock_bh(&priv->ps_state_lock);
 	priv->tx_multicast = priv->aid0_bit_set &&
 			priv->buffered_multicasts;
diff --git a/drivers/staging/cw1200/txrx.c b/drivers/staging/cw1200/txrx.c
index 0d535f7..9569fd5 100644
--- a/drivers/staging/cw1200/txrx.c
+++ b/drivers/staging/cw1200/txrx.c
@@ -892,6 +892,15 @@ void cw1200_tx_confirm_cb(struct cw1200_common *priv,
 			priv->sta_asleep_mask);
 		WARN_ON(cw1200_queue_requeue(queue,
 				arg->packetID));
+		spin_lock_bh(&priv->ps_state_lock);
+		if (!arg->link_id) {
+			priv->buffered_multicasts = true;
+			if (priv->sta_asleep_mask) {
+				queue_work(priv->workqueue,
+					&priv->multicast_start_work);
+			}
+		}
+		spin_unlock_bh(&priv->ps_state_lock);
 	} else if (!WARN_ON(cw1200_queue_get_skb(
 			queue, arg->packetID, &skb, &txpriv))) {
 		struct ieee80211_tx_info *tx = IEEE80211_SKB_CB(skb);
diff --git a/drivers/staging/cw1200/wsm.c b/drivers/staging/cw1200/wsm.c
index b1a2a9e..d3a23b4 100644
--- a/drivers/staging/cw1200/wsm.c
+++ b/drivers/staging/cw1200/wsm.c
@@ -1638,9 +1638,11 @@ int wsm_get_tx(struct cw1200_common *priv, u8 **data,
 					(priv->tx_multicast ||
 					 !priv->sta_asleep_mask)) {
 				priv->buffered_multicasts = false;
-				if (priv->tx_multicast)
+				if (priv->tx_multicast) {
+					priv->tx_multicast = false;
 					queue_work(priv->workqueue,
 						&priv->multicast_stop_work);
+				}
 			}
 
 			spin_unlock_bh(&priv->ps_state_lock);
-- 
1.7.8.3



More information about the kernel mailing list