summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>2011-08-04 17:58:27 +0200
committerPhilippe LANGLAIS <philippe.langlais@stericsson.com>2011-10-13 09:57:33 +0200
commit304826f516664d04811b7e0c921a6d05a1cffd07 (patch)
tree9a92ec20270e8641fae88e487abf9fc13afefc71
parentd1a2ea58a2231b046a92dbf4745bf0214f9ea058 (diff)
cw1200: Fix for driver hang at join timeout (scan in progress)
Join timout might interfere with scan activity. Firmware hangs if unjoin (reset) request is triggered when scan is in progress. The patchs delays unjoin request up to completion of the scan. Change-Id: I17fa573ee52aab843e69e4344ae5b66e94b5b4db Signed-off-by: Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/28298 Reviewed-by: Bartosz MARKOWSKI <bartosz.markowski@tieto.com> Tested-by: Bartosz MARKOWSKI <bartosz.markowski@tieto.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/33498 Reviewed-by: Philippe LANGLAIS <philippe.langlais@stericsson.com>
-rw-r--r--drivers/staging/cw1200/cw1200.h1
-rw-r--r--drivers/staging/cw1200/scan.c68
-rw-r--r--drivers/staging/cw1200/sta.c7
3 files changed, 46 insertions, 30 deletions
diff --git a/drivers/staging/cw1200/cw1200.h b/drivers/staging/cw1200/cw1200.h
index 64bae8b03c0..13c3b2d3751 100644
--- a/drivers/staging/cw1200/cw1200.h
+++ b/drivers/staging/cw1200/cw1200.h
@@ -154,6 +154,7 @@ struct cw1200_common {
struct delayed_work join_timeout;
struct work_struct unjoin_work;
int join_dtim_period;
+ bool delayed_unjoin;
/* TX/RX and security */
s8 wep_default_key_id;
diff --git a/drivers/staging/cw1200/scan.c b/drivers/staging/cw1200/scan.c
index 17706e58549..3c80c571ea7 100644
--- a/drivers/staging/cw1200/scan.c
+++ b/drivers/staging/cw1200/scan.c
@@ -13,6 +13,8 @@
#include "cw1200.h"
#include "scan.h"
+static void cw1200_scan_restart_delayed(struct cw1200_common *priv);
+
static int cw1200_scan_start(struct cw1200_common *priv, struct wsm_scan *scan)
{
int ret, i;
@@ -28,6 +30,7 @@ static int cw1200_scan_start(struct cw1200_common *priv, struct wsm_scan *scan)
if (unlikely(ret)) {
atomic_set(&priv->scan.in_progress, 0);
cancel_delayed_work_sync(&priv->scan.timeout);
+ cw1200_scan_restart_delayed(priv);
}
return ret;
}
@@ -48,7 +51,7 @@ int cw1200_hw_scan(struct ieee80211_hw *hw,
if (req->n_ssids == 1 && !req->ssids[0].ssid_len)
req->n_ssids = 0;
- printk(KERN_DEBUG "[SCAN] Scan request for %d SSIDs.\n",
+ wiphy_dbg(hw->wiphy, "[SCAN] Scan request for %d SSIDs.\n",
req->n_ssids);
if (req->n_ssids > WSM_SCAN_MAX_NUM_OF_SSIDS)
@@ -143,25 +146,14 @@ void cw1200_scan_work(struct work_struct *work)
wsm_set_pm(priv, &priv->powersave_mode);
if (priv->scan.req)
- printk(KERN_DEBUG "[SCAN] Scan completed.\n");
+ wiphy_dbg(priv->hw->wiphy,
+ "[SCAN] Scan completed.\n");
else
- printk(KERN_DEBUG "[SCAN] Scan canceled.\n");
+ wiphy_dbg(priv->hw->wiphy,
+ "[SCAN] Scan canceled.\n");
priv->scan.req = NULL;
-
- if (priv->delayed_link_loss) {
- priv->delayed_link_loss = 0;
- /* Restart beacon loss timer and requeue
- BSS loss work. */
- printk(KERN_DEBUG "[CQM] Requeue BSS loss in %d " \
- "beacons.\n",
- priv->cqm_beacon_loss_count);
- cancel_delayed_work_sync(&priv->bss_loss_work);
- queue_delayed_work(priv->workqueue,
- &priv->bss_loss_work,
- priv->cqm_beacon_loss_count * HZ / 10);
- }
-
+ cw1200_scan_restart_delayed(priv);
wsm_unlock_tx(priv);
mutex_unlock(&priv->conf_mutex);
ieee80211_scan_completed(priv->hw, priv->scan.status ? 1 : 0);
@@ -231,22 +223,38 @@ fail:
return;
}
+static void cw1200_scan_restart_delayed(struct cw1200_common *priv)
+{
+ if (priv->delayed_link_loss) {
+ int tmo = priv->cqm_beacon_loss_count;
+
+ if (priv->scan.direct_probe)
+ tmo = 0;
+
+ priv->delayed_link_loss = 0;
+ /* Restart beacon loss timer and requeue
+ BSS loss work. */
+ wiphy_dbg(priv->hw->wiphy,
+ "[CQM] Requeue BSS loss in %d "
+ "beacons.\n", tmo);
+ cancel_delayed_work_sync(&priv->bss_loss_work);
+ queue_delayed_work(priv->workqueue,
+ &priv->bss_loss_work,
+ tmo * HZ / 10);
+ }
+ if (priv->delayed_unjoin) {
+ priv->delayed_unjoin = false;
+ if (queue_work(priv->workqueue, &priv->unjoin_work) <= 0)
+ wsm_unlock_tx(priv);
+ }
+}
+
static void cw1200_scan_complete(struct cw1200_common *priv)
{
if (priv->scan.direct_probe) {
- printk(KERN_DEBUG "[SCAN] Direct probe complete.\n");
+ wiphy_dbg(priv->hw->wiphy, "[SCAN] Direct probe complete.\n");
+ cw1200_scan_restart_delayed(priv);
priv->scan.direct_probe = 0;
-
- if (priv->delayed_link_loss) {
- priv->delayed_link_loss = 0;
- /* Requeue BSS loss work now. Direct probe does not
- * affect BSS loss subscription. */
- printk(KERN_DEBUG "[CQM] Requeue BSS loss now.\n");
- cancel_delayed_work_sync(&priv->bss_loss_work);
- queue_delayed_work(priv->workqueue,
- &priv->bss_loss_work, 0);
- }
-
up(&priv->scan.lock);
wsm_unlock_tx(priv);
} else {
@@ -310,7 +318,7 @@ void cw1200_probe_work(struct work_struct *work)
size_t ies_len;
int ret;
- printk(KERN_DEBUG "[SCAN] Direct probe work.\n");
+ wiphy_dbg(priv->hw->wiphy, "[SCAN] Direct probe work.\n");
if (!priv->channel) {
dev_kfree_skb(priv->scan.probe_skb);
diff --git a/drivers/staging/cw1200/sta.c b/drivers/staging/cw1200/sta.c
index 86a05dcaca2..8c813282021 100644
--- a/drivers/staging/cw1200/sta.c
+++ b/drivers/staging/cw1200/sta.c
@@ -1064,6 +1064,13 @@ void cw1200_unjoin_work(struct work_struct *work)
};
mutex_lock(&priv->conf_mutex);
+ if (unlikely(atomic_read(&priv->scan.in_progress))) {
+ BUG_ON(priv->delayed_unjoin);
+ priv->delayed_unjoin = true;
+ mutex_unlock(&priv->conf_mutex);
+ return;
+ }
+
BUG_ON(priv->join_status &&
priv->join_status != CW1200_JOIN_STATUS_STA);
if (priv->join_status == CW1200_JOIN_STATUS_STA) {