From a69221ed6ed3da38bcd24dd96a21ac2ffb12582c Mon Sep 17 00:00:00 2001 From: Dmitry Tarnyagin Date: Wed, 29 Feb 2012 15:15:05 +0100 Subject: 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 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/39979 Reviewed-by: Bartosz MARKOWSKI Tested-by: Bartosz MARKOWSKI --- 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 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); -- cgit v1.2.3