[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