From cd0a297fda5d53c14498719da32df5e359356a05 Mon Sep 17 00:00:00 2001 From: Dmitry Tarnyagin Date: Sun, 15 May 2011 14:19:19 +0200 Subject: cw1200: Fix for buffered multicasts in AP-PS mode. Refactoring of multicast handling: * When multicast is coming, driver sets aid0 bit in TIM IE and puts multicas in the queue with "AFTER_DTIM" link id. * When WSM indicates DTIM beacon, driver verifies if aid0 indicating beacon was sent and sends buffered multicasts. * Driver clears aid0 bit in the TIM IE when no more multicasts are available. + A stilistic change: 1 << shift is replaced by BIT(shift) Change-Id: I15b134bf847913a907f00293ae99d7a71bbc7343 Signed-off-by: Dmitry Tarnyagin Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/27306 Reviewed-by: Bartosz MARKOWSKI Tested-by: Bartosz MARKOWSKI Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/33488 Reviewed-by: Philippe LANGLAIS --- drivers/staging/cw1200/ap.c | 70 ++++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 30 deletions(-) (limited to 'drivers/staging/cw1200/ap.c') diff --git a/drivers/staging/cw1200/ap.c b/drivers/staging/cw1200/ap.c index c6e5b78ab66..fc23ff74100 100755 --- a/drivers/staging/cw1200/ap.c +++ b/drivers/staging/cw1200/ap.c @@ -51,7 +51,7 @@ int cw1200_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, memcpy(map_link.mac_addr, sta->addr, ETH_ALEN); if (!WARN_ON(wsm_map_link(priv, &map_link))) { sta_priv->link_id = map_link.link_id; - priv->link_id_map |= 1 << map_link.link_id; + priv->link_id_map |= BIT(map_link.link_id); ap_printk(KERN_DEBUG "[AP] STA added, link_id: %d\n", map_link.link_id); } @@ -73,7 +73,7 @@ int cw1200_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ap_printk(KERN_DEBUG "[AP] STA removed, link_id: %d\n", sta_priv->link_id); reset.link_id = sta_priv->link_id; - priv->link_id_map &= ~(1 << sta_priv->link_id); + priv->link_id_map &= ~BIT(sta_priv->link_id); sta_priv->link_id = 0; WARN_ON(wsm_reset(priv, &reset)); } @@ -87,7 +87,7 @@ void cw1200_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif, struct cw1200_common *priv = dev->priv; struct cw1200_sta_priv *sta_priv = (struct cw1200_sta_priv *)&sta->drv_priv; - u32 bit = 1 << sta_priv->link_id; + u32 bit = BIT(sta_priv->link_id); switch (notify_cmd) { case STA_NOTIFY_SLEEP: @@ -100,7 +100,7 @@ void cw1200_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif, } } -static int cw1200_set_tim_impl(struct cw1200_common *priv, bool multicast) +static int cw1200_set_tim_impl(struct cw1200_common *priv) { struct wsm_template_frame frame = { .frame_type = WSM_FRAME_TYPE_BEACON, @@ -120,7 +120,7 @@ static int cw1200_set_tim_impl(struct cw1200_common *priv, bool multicast) frame.skb->data[tim_offset + 2] = 0; /* Set/reset aid0 bit */ - if (multicast) + if (priv->aid0_bit_set) frame.skb->data[tim_offset + 4] |= 1; else frame.skb->data[tim_offset + 4] &= ~1; @@ -137,7 +137,7 @@ void cw1200_set_tim_work(struct work_struct *work) { struct cw1200_common *priv = container_of(work, struct cw1200_common, set_tim_work); - (void)cw1200_set_tim_impl(priv, !priv->suspend_multicast); + (void)cw1200_set_tim_impl(priv); } int cw1200_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta, @@ -429,10 +429,16 @@ void cw1200_multicast_start_work(struct work_struct *work) struct cw1200_common *priv = container_of(work, struct cw1200_common, multicast_start_work); - (void)cw1200_set_tim_impl(priv, true); - priv->suspend_multicast = false; - wsm_unlock_tx(priv); - cw1200_bh_wakeup(priv); + bool store_timestamp = !priv->aid0_bit_set; + + priv->aid0_bit_set = true; + cw1200_set_tim_impl(priv); + if (store_timestamp) { + unsigned long now = jiffies; + if (unlikely(!now)) + ++now; + priv->aid0_bit_timestamp = now; + } } void cw1200_multicast_stop_work(struct work_struct *work) @@ -440,11 +446,12 @@ void cw1200_multicast_stop_work(struct work_struct *work) struct cw1200_common *priv = container_of(work, struct cw1200_common, multicast_stop_work); - /* Flush to make sure DTIM beacon and frames are sent. */ - wsm_flush_tx(priv); - priv->suspend_multicast = true; - (void)cw1200_set_tim_impl(priv, false); + /* Flush to make sure frames are sent. */ + wsm_lock_tx(priv); wsm_unlock_tx(priv); + + priv->aid0_bit_set = false; + cw1200_set_tim_impl(priv); } int cw1200_ampdu_action(struct ieee80211_hw *hw, @@ -465,9 +472,8 @@ int cw1200_ampdu_action(struct ieee80211_hw *hw, void cw1200_suspend_resume(struct cw1200_common *priv, struct wsm_suspend_resume *arg) { - int queue = 1 << wsm_queue_id_to_linux(arg->queue); - u32 unicast = 1 << arg->link_id; - u32 after_dtim = 1 << CW1200_LINK_ID_AFTER_DTIM; + int queue = BIT(wsm_queue_id_to_linux(arg->queue)); + u32 unicast = BIT(arg->link_id); u32 wakeup_required = 0; u32 set = 0; u32 clear; @@ -475,7 +481,7 @@ void cw1200_suspend_resume(struct cw1200_common *priv, int i; if (!arg->link_id) /* For all links */ - unicast = (1 << (CW1200_MAX_STA_IN_AP_MODE + 1)) - 2; + unicast = BIT(CW1200_MAX_STA_IN_AP_MODE + 1) - 2; ap_printk(KERN_DEBUG "[AP] %s: %s\n", arg->stop ? "stop" : "start", @@ -483,20 +489,24 @@ void cw1200_suspend_resume(struct cw1200_common *priv, if (arg->multicast) { if (arg->stop) { - wsm_lock_tx_async(priv); queue_work(priv->workqueue, &priv->multicast_stop_work); } else { - /* Handle only if there is data to be sent */ - for (i = 0; i < 4; ++i) { - if (cw1200_queue_get_num_queued( - &priv->tx_queue[i], - after_dtim)) { - wsm_lock_tx_async(priv); - queue_work(priv->workqueue, - &priv->multicast_start_work); - break; - } + /* Handle only if there is data to be sent + * and aid0 is set in the beacon. */ + unsigned long timestamp = + priv->aid0_bit_timestamp; + /* 20ms grace interval is used to make sure + * the beacon was actually sent by hardware. */ + static const unsigned long grace_interval = + HZ * 20 / 1000; + + if (timestamp && + jiffies - timestamp > grace_interval) { + + priv->aid0_bit_timestamp = 0; + priv->suspend_multicast = false; + cw1200_bh_wakeup(priv); } } } else { @@ -511,7 +521,7 @@ void cw1200_suspend_resume(struct cw1200_common *priv, queue = 0x0F; for (i = 0; i < 4; ++i) { - if (!(queue & (1 << i))) + if (!(queue & BIT(i))) continue; tx_suspend_mask = priv->tx_suspend_mask[i]; -- cgit v1.2.3