From 166254636dcdbc6e103ca3c18236b982e5195447 Mon Sep 17 00:00:00 2001 From: Dmitry Tarnyagin Date: Tue, 27 Sep 2011 15:17:59 +0200 Subject: cw1200: cw1200_flush() blocked execution on SoftAP stop cw1200_flush() was called when beacon had not been available. In presence of PS-enabled STAs in the air that leaded to a timeout in delivering of frames to these STAs. Fix forces clearing of the frame queue if beacon is not available. ST-Ericsson ID: 360712 ST-Ericsson ID: 359675 Change-Id: I678fbd6b31d853108ece82e4da62a02c21fa211e Signed-off-by: Dmitry Tarnyagin Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/32220 Reviewed-by: Bartosz MARKOWSKI Tested-by: Bartosz MARKOWSKI Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/33534 Reviewed-by: Philippe LANGLAIS --- drivers/staging/cw1200/ap.c | 7 ++- drivers/staging/cw1200/sta.c | 118 ++++++++++++++++++++++-------------------- drivers/staging/cw1200/txrx.c | 7 ++- 3 files changed, 71 insertions(+), 61 deletions(-) diff --git a/drivers/staging/cw1200/ap.c b/drivers/staging/cw1200/ap.c index c4b68a42ccd..0e0947a4482 100755 --- a/drivers/staging/cw1200/ap.c +++ b/drivers/staging/cw1200/ap.c @@ -134,8 +134,11 @@ static int cw1200_set_tim_impl(struct cw1200_common *priv, bool aid0_bit_set) skb = ieee80211_beacon_get_tim(priv->hw, priv->vif, &tim_offset, &tim_length); - if (WARN_ON(!skb)) - return -ENOMEM; + if (!skb) { + if (!__cw1200_flush(priv, true)); + wsm_unlock_tx(priv); + return -ENOENT; + } if (tim_offset && tim_length >= 6) { /* Ignore DTIM count from mac80211: diff --git a/drivers/staging/cw1200/sta.c b/drivers/staging/cw1200/sta.c index 4aa320d76d9..ecfdc7562f3 100644 --- a/drivers/staging/cw1200/sta.c +++ b/drivers/staging/cw1200/sta.c @@ -101,10 +101,6 @@ void cw1200_stop(struct ieee80211_hw *dev) LIST_HEAD(list); int i; - struct wsm_reset reset = { - .reset_statistics = true, - }; - wsm_lock_tx(priv); while (down_trylock(&priv->scan.lock)) { @@ -114,51 +110,18 @@ void cw1200_stop(struct ieee80211_hw *dev) } up(&priv->scan.lock); - mutex_lock(&priv->conf_mutex); - cw1200_free_keys(priv); - priv->mode = NL80211_IFTYPE_UNSPECIFIED; - priv->listening = false; - mutex_unlock(&priv->conf_mutex); - cancel_delayed_work_sync(&priv->scan.probe_work); cancel_delayed_work_sync(&priv->scan.timeout); cancel_delayed_work_sync(&priv->join_timeout); cancel_delayed_work_sync(&priv->bss_loss_work); cancel_delayed_work_sync(&priv->connection_loss_work); cancel_delayed_work_sync(&priv->link_id_gc_work); - - if (timer_pending(&priv->mcast_timeout)) - del_timer_sync(&priv->mcast_timeout); - - mutex_lock(&priv->conf_mutex); - switch (priv->join_status) { - case CW1200_JOIN_STATUS_STA: - wsm_lock_tx(priv); - if (queue_work(priv->workqueue, &priv->unjoin_work) <= 0) - wsm_unlock_tx(priv); - break; - case CW1200_JOIN_STATUS_AP: - /* If you see this warning please change the code to iterate - * through the map and reset each link separately. */ - WARN_ON(priv->link_id_map); - priv->sta_asleep_mask = 0; - priv->enable_beacon = false; - priv->tx_multicast = false; - priv->aid0_bit_set = false; - priv->buffered_multicasts = false; - priv->pspoll_mask = 0; - wsm_reset(priv, &reset); - break; - case CW1200_JOIN_STATUS_MONITOR: - cw1200_update_listening(priv, false); - break; - default: - break; - } - mutex_unlock(&priv->conf_mutex); - flush_workqueue(priv->workqueue); + del_timer_sync(&priv->mcast_timeout); + mutex_lock(&priv->conf_mutex); + priv->mode = NL80211_IFTYPE_UNSPECIFIED; + priv->listening = false; priv->softled_state = 0; /* cw1200_set_leds(priv); */ @@ -170,7 +133,6 @@ void cw1200_stop(struct ieee80211_hw *dev) priv->delayed_link_loss = 0; - priv->link_id_map = 0; priv->join_status = CW1200_JOIN_STATUS_PASSIVE; for (i = 0; i < 4; i++) @@ -230,23 +192,56 @@ void cw1200_remove_interface(struct ieee80211_hw *dev, struct ieee80211_vif *vif) { struct cw1200_common *priv = dev->priv; - struct wsm_reset reset = { .reset_statistics = true, }; + int i; mutex_lock(&priv->conf_mutex); - + wsm_lock_tx(priv); + switch (priv->join_status) { + case CW1200_JOIN_STATUS_STA: + wsm_lock_tx(priv); + if (queue_work(priv->workqueue, &priv->unjoin_work) <= 0) + wsm_unlock_tx(priv); + break; + case CW1200_JOIN_STATUS_AP: + for (i = 0; priv->link_id_map; ++i) { + if (priv->link_id_map & BIT(i)) { + reset.link_id = i; + wsm_reset(priv, &reset); + priv->link_id_map &= ~BIT(i); + } + } + memset(priv->link_id_db, 0, + sizeof(priv->link_id_db)); + memset(priv->tx_suspend_mask, 0, + sizeof(priv->tx_suspend_mask)); + priv->sta_asleep_mask = 0; + priv->enable_beacon = false; + priv->tx_multicast = false; + priv->aid0_bit_set = false; + priv->buffered_multicasts = false; + priv->pspoll_mask = 0; + reset.link_id = 0; + wsm_reset(priv, &reset); + break; + case CW1200_JOIN_STATUS_MONITOR: + cw1200_update_listening(priv, false); + break; + default: + break; + } priv->vif = NULL; priv->mode = NL80211_IFTYPE_MONITOR; memset(priv->mac_addr, 0, ETH_ALEN); memset(priv->bssid, 0, ETH_ALEN); - wsm_lock_tx(priv); - WARN_ON(wsm_reset(priv, &reset)); cw1200_free_keys(priv); cw1200_setup_mac(priv); priv->listening = false; priv->join_status = CW1200_JOIN_STATUS_PASSIVE; + if (!__cw1200_flush(priv, true)) + wsm_unlock_tx(priv); wsm_unlock_tx(priv); mutex_unlock(&priv->conf_mutex); @@ -385,6 +380,7 @@ int cw1200_config(struct ieee80211_hw *dev, u32 changed) .power_mode = wsm_power_mode_quiescent, .disableMoreFlagUsage = true, }; + wsm_lock_tx(priv); /* Disable p2p-dev mode forced by TX request */ if ((priv->join_status == CW1200_JOIN_STATUS_MONITOR) && @@ -760,29 +756,27 @@ int __cw1200_flush(struct cw1200_common *priv, bool drop) { int i, ret; - if (drop) { - for (i = 0; i < 4; ++i) - cw1200_queue_clear(&priv->tx_queue[i]); - } - for (;;) { - /* TODO: correct flush handlin is required when dev_stop. + /* TODO: correct flush handling is required when dev_stop. * Temporary workaround: 2s */ - ret = wait_event_timeout( + if (drop) { + for (i = 0; i < 4; ++i) + cw1200_queue_clear(&priv->tx_queue[i]); + } else { + ret = wait_event_timeout( priv->tx_queue_stats.wait_link_id_empty, cw1200_queue_stats_is_empty( &priv->tx_queue_stats, -1), 2 * HZ); + } - if (unlikely(ret <= 0)) { - if (!ret) - ret = -ETIMEDOUT; + if (!drop && unlikely(ret <= 0)) { + ret = -ETIMEDOUT; break; } else { ret = 0; } - ret = 0; wsm_lock_tx(priv); if (unlikely(!cw1200_queue_stats_is_empty( @@ -800,6 +794,16 @@ void cw1200_flush(struct ieee80211_hw *hw, bool drop) { struct cw1200_common *priv = hw->priv; + switch (priv->mode) { + case NL80211_IFTYPE_MONITOR: + drop = true; + break; + case NL80211_IFTYPE_AP: + if (!priv->enable_beacon) + drop = true; + break; + } + if (!WARN_ON(__cw1200_flush(priv, drop))) wsm_unlock_tx(priv); diff --git a/drivers/staging/cw1200/txrx.c b/drivers/staging/cw1200/txrx.c index ef871325eee..92a5bf377b6 100644 --- a/drivers/staging/cw1200/txrx.c +++ b/drivers/staging/cw1200/txrx.c @@ -764,8 +764,11 @@ void cw1200_tx_confirm_cb(struct cw1200_common *priv, .multicast = !arg->link_id, }; cw1200_suspend_resume(priv, &suspend); - wiphy_warn(priv->hw->wiphy, "Requeue (try %d).\n", - cw1200_queue_get_generation(arg->packetID) + 1); + wiphy_warn(priv->hw->wiphy, "Requeue for link_id %d (try %d)." + " STAs asleep: 0x%.8X\n", + arg->link_id, + cw1200_queue_get_generation(arg->packetID) + 1, + priv->sta_asleep_mask); WARN_ON(cw1200_queue_requeue(queue, arg->packetID)); } else if (!WARN_ON(cw1200_queue_get_skb( -- cgit v1.2.3