summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>2011-09-27 15:17:59 +0200
committerPhilippe LANGLAIS <philippe.langlais@stericsson.com>2011-10-13 10:20:25 +0200
commit166254636dcdbc6e103ca3c18236b982e5195447 (patch)
tree994663432b905dbafc7dee7f56435d6c97bc804c
parent02e3a3c6eed7b493d997017ef93622faac49fd52 (diff)
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 <dmitry.tarnyagin@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/32220 Reviewed-by: Bartosz MARKOWSKI <bartosz.markowski@tieto.com> Tested-by: Bartosz MARKOWSKI <bartosz.markowski@tieto.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/33534 Reviewed-by: Philippe LANGLAIS <philippe.langlais@stericsson.com>
-rwxr-xr-xdrivers/staging/cw1200/ap.c7
-rw-r--r--drivers/staging/cw1200/sta.c118
-rw-r--r--drivers/staging/cw1200/txrx.c7
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(