aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-09-22 18:15:00 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-09-27 14:34:09 -0400
commit84b1bec6d716fc8c289e2530cab109a6e097455b (patch)
tree91659c23350ca7d93fa383ba9ea439d360140b8b
parenta2fa2462f05115722beb2443d081a72f4f4450ea (diff)
iwlagn: fix scan complete processing
When we cancel a scan, the completion runs only from the workqueue. This can cause the remain-on-channel scan to fail when another one was just canceled, because we're still aborting it. To fix this, run the completion inline with the lock still held before returning from iwl_scan_cancel_timeout(). Also, to avoid the scan complete work from completing a new scan prematurely, add a new STATUS_SCAN_COMPLETE bit. Reported-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Tested-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c36
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-shared.h1
2 files changed, 33 insertions, 4 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index e50338b47593..c5c95d5319b1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -118,6 +118,11 @@ static void iwl_process_scan_complete(struct iwl_priv *priv)
118{ 118{
119 bool aborted; 119 bool aborted;
120 120
121 lockdep_assert_held(&priv->shrd->mutex);
122
123 if (!test_and_clear_bit(STATUS_SCAN_COMPLETE, &priv->shrd->status))
124 return;
125
121 IWL_DEBUG_SCAN(priv, "Completed scan.\n"); 126 IWL_DEBUG_SCAN(priv, "Completed scan.\n");
122 127
123 cancel_delayed_work(&priv->scan_check); 128 cancel_delayed_work(&priv->scan_check);
@@ -181,6 +186,7 @@ void iwl_force_scan_end(struct iwl_priv *priv)
181 clear_bit(STATUS_SCANNING, &priv->shrd->status); 186 clear_bit(STATUS_SCANNING, &priv->shrd->status);
182 clear_bit(STATUS_SCAN_HW, &priv->shrd->status); 187 clear_bit(STATUS_SCAN_HW, &priv->shrd->status);
183 clear_bit(STATUS_SCAN_ABORTING, &priv->shrd->status); 188 clear_bit(STATUS_SCAN_ABORTING, &priv->shrd->status);
189 clear_bit(STATUS_SCAN_COMPLETE, &priv->shrd->status);
184 iwl_complete_scan(priv, true); 190 iwl_complete_scan(priv, true);
185} 191}
186 192
@@ -235,9 +241,24 @@ void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
235 241
236 while (time_before_eq(jiffies, timeout)) { 242 while (time_before_eq(jiffies, timeout)) {
237 if (!test_bit(STATUS_SCAN_HW, &priv->shrd->status)) 243 if (!test_bit(STATUS_SCAN_HW, &priv->shrd->status))
238 break; 244 goto finished;
239 msleep(20); 245 msleep(20);
240 } 246 }
247
248 return;
249
250 finished:
251 /*
252 * Now STATUS_SCAN_HW is clear. This means that the
253 * device finished, but the background work is going
254 * to execute at best as soon as we release the mutex.
255 * Since we need to be able to issue a new scan right
256 * after this function returns, run the complete here.
257 * The STATUS_SCAN_COMPLETE bit will then be cleared
258 * and prevent the background work from "completing"
259 * a possible new scan.
260 */
261 iwl_process_scan_complete(priv);
241} 262}
242 263
243/* Service response to REPLY_SCAN_CMD (0x80) */ 264/* Service response to REPLY_SCAN_CMD (0x80) */
@@ -321,13 +342,20 @@ static int iwl_rx_scan_complete_notif(struct iwl_priv *priv,
321 scan_notif->tsf_low, 342 scan_notif->tsf_low,
322 scan_notif->tsf_high, scan_notif->status); 343 scan_notif->tsf_high, scan_notif->status);
323 344
324 /* The HW is no longer scanning */
325 clear_bit(STATUS_SCAN_HW, &priv->shrd->status);
326
327 IWL_DEBUG_SCAN(priv, "Scan on %sGHz took %dms\n", 345 IWL_DEBUG_SCAN(priv, "Scan on %sGHz took %dms\n",
328 (priv->scan_band == IEEE80211_BAND_2GHZ) ? "2.4" : "5.2", 346 (priv->scan_band == IEEE80211_BAND_2GHZ) ? "2.4" : "5.2",
329 jiffies_to_msecs(jiffies - priv->scan_start)); 347 jiffies_to_msecs(jiffies - priv->scan_start));
330 348
349 /*
350 * When aborting, we run the scan completed background work inline
351 * and the background work must then do nothing. The SCAN_COMPLETE
352 * bit helps implement that logic and thus needs to be set before
353 * queueing the work. Also, since the scan abort waits for SCAN_HW
354 * to clear, we need to set SCAN_COMPLETE before clearing SCAN_HW
355 * to avoid a race there.
356 */
357 set_bit(STATUS_SCAN_COMPLETE, &priv->shrd->status);
358 clear_bit(STATUS_SCAN_HW, &priv->shrd->status);
331 queue_work(priv->shrd->workqueue, &priv->scan_completed); 359 queue_work(priv->shrd->workqueue, &priv->scan_completed);
332 360
333 if (priv->iw_mode != NL80211_IFTYPE_ADHOC && 361 if (priv->iw_mode != NL80211_IFTYPE_ADHOC &&
diff --git a/drivers/net/wireless/iwlwifi/iwl-shared.h b/drivers/net/wireless/iwlwifi/iwl-shared.h
index 7abafe16de9a..8747bbdf8983 100644
--- a/drivers/net/wireless/iwlwifi/iwl-shared.h
+++ b/drivers/net/wireless/iwlwifi/iwl-shared.h
@@ -489,6 +489,7 @@ static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv,
489#define STATUS_FW_ERROR 17 489#define STATUS_FW_ERROR 17
490#define STATUS_DEVICE_ENABLED 18 490#define STATUS_DEVICE_ENABLED 18
491#define STATUS_CHANNEL_SWITCH_PENDING 19 491#define STATUS_CHANNEL_SWITCH_PENDING 19
492#define STATUS_SCAN_COMPLETE 20
492 493
493static inline int iwl_is_ready(struct iwl_shared *shrd) 494static inline int iwl_is_ready(struct iwl_shared *shrd)
494{ 495{