summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>2012-02-29 15:15:05 +0100
committerPhilippe Langlais <philippe.langlais@stericsson.com>2012-05-22 11:06:44 +0200
commita69221ed6ed3da38bcd24dd96a21ac2ffb12582c (patch)
tree45f378d5f94d18431ac2d4ff4e4982c61f635493
parent1be9f1fb645f302f42eab10b6645e05f60751be6 (diff)
cw1200: Fixes for multicast delivery in AP/UAPSD mode.
* 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@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/39979 Reviewed-by: Bartosz MARKOWSKI <bartosz.markowski@tieto.com> Tested-by: Bartosz MARKOWSKI <bartosz.markowski@tieto.com>
-rwxr-xr-xdrivers/staging/cw1200/ap.c9
-rw-r--r--drivers/staging/cw1200/txrx.c9
-rw-r--r--drivers/staging/cw1200/wsm.c4
3 files changed, 20 insertions, 2 deletions
diff --git a/drivers/staging/cw1200/ap.c b/drivers/staging/cw1200/ap.c
index f58ccb13205..ff8d36cbedb 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 0d535f797a8..9569fd5849f 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 b1a2a9ecc6a..d3a23b44462 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);