aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ipw2x00/ipw2200.c
diff options
context:
space:
mode:
authorHelmut Schaa <helmut.schaa@googlemail.com>2008-12-10 07:17:26 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-12-12 14:02:10 -0500
commit14a4dfe2ff8c353f59ae8324059ded1cfe22c7d9 (patch)
tree3301a6e2903012294d6e21dd96d04885f9a08cdb /drivers/net/wireless/ipw2x00/ipw2200.c
parentd8004cb9267b15cd902eef01a75bb1ffa3995af8 (diff)
ipw2200: fix scanning while associated
This patch fixes sporadic firmware restarts when scanning while associated. The firmware will quietly cancel a scan (while associated) if the dwell time for a channel to be scanned is larger than the time it may stay away from the operating channel (because of DTIM catching). Unfortunately the driver is not notified about the canceled scan and therefore the scan watchdog timeout will be hit and the driver causes a firmware restart which results in disassociation. This mainly happens on passive channels which use a dwell time of 120 whereas a typical beacon interval is around 100. The patch changes the dwell time for passive channels to be slightly smaller than the actual beacon interval to work around the firmware issue. Furthermore the number of allowed beacon misses is increased from one to three as otherwise most scans (while associated) won't complete successfully. However scanning while associated will still fail in corner cases such as a beacon intervals below 30. Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ipw2x00/ipw2200.c')
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c28
1 files changed, 22 insertions, 6 deletions
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index 23728eb6110a..625f2cf99fa9 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -4345,7 +4345,8 @@ static void ipw_handle_missed_beacon(struct ipw_priv *priv,
4345 return; 4345 return;
4346 } 4346 }
4347 4347
4348 if (priv->status & STATUS_SCANNING) { 4348 if (priv->status & STATUS_SCANNING &&
4349 missed_count > IPW_MB_SCAN_CANCEL_THRESHOLD) {
4349 /* Stop scan to keep fw from getting 4350 /* Stop scan to keep fw from getting
4350 * stuck (only if we aren't roaming -- 4351 * stuck (only if we aren't roaming --
4351 * otherwise we'll never scan more than 2 or 3 4352 * otherwise we'll never scan more than 2 or 3
@@ -6271,6 +6272,20 @@ static void ipw_add_scan_channels(struct ipw_priv *priv,
6271 } 6272 }
6272} 6273}
6273 6274
6275static int ipw_passive_dwell_time(struct ipw_priv *priv)
6276{
6277 /* staying on passive channels longer than the DTIM interval during a
6278 * scan, while associated, causes the firmware to cancel the scan
6279 * without notification. Hence, don't stay on passive channels longer
6280 * than the beacon interval.
6281 */
6282 if (priv->status & STATUS_ASSOCIATED
6283 && priv->assoc_network->beacon_interval > 10)
6284 return priv->assoc_network->beacon_interval - 10;
6285 else
6286 return 120;
6287}
6288
6274static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct) 6289static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct)
6275{ 6290{
6276 struct ipw_scan_request_ext scan; 6291 struct ipw_scan_request_ext scan;
@@ -6314,16 +6329,16 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct)
6314 scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee)); 6329 scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee));
6315 6330
6316 if (type == IW_SCAN_TYPE_PASSIVE) { 6331 if (type == IW_SCAN_TYPE_PASSIVE) {
6317 IPW_DEBUG_WX("use passive scanning\n"); 6332 IPW_DEBUG_WX("use passive scanning\n");
6318 scan_type = IPW_SCAN_PASSIVE_FULL_DWELL_SCAN; 6333 scan_type = IPW_SCAN_PASSIVE_FULL_DWELL_SCAN;
6319 scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = 6334 scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] =
6320 cpu_to_le16(120); 6335 cpu_to_le16(ipw_passive_dwell_time(priv));
6321 ipw_add_scan_channels(priv, &scan, scan_type); 6336 ipw_add_scan_channels(priv, &scan, scan_type);
6322 goto send_request; 6337 goto send_request;
6323 } 6338 }
6324 6339
6325 /* Use active scan by default. */ 6340 /* Use active scan by default. */
6326 if (priv->config & CFG_SPEED_SCAN) 6341 if (priv->config & CFG_SPEED_SCAN)
6327 scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = 6342 scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
6328 cpu_to_le16(30); 6343 cpu_to_le16(30);
6329 else 6344 else
@@ -6333,7 +6348,8 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct)
6333 scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = 6348 scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] =
6334 cpu_to_le16(20); 6349 cpu_to_le16(20);
6335 6350
6336 scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120); 6351 scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] =
6352 cpu_to_le16(ipw_passive_dwell_time(priv));
6337 scan.dwell_time[IPW_SCAN_ACTIVE_DIRECT_SCAN] = cpu_to_le16(20); 6353 scan.dwell_time[IPW_SCAN_ACTIVE_DIRECT_SCAN] = cpu_to_le16(20);
6338 6354
6339#ifdef CONFIG_IPW2200_MONITOR 6355#ifdef CONFIG_IPW2200_MONITOR