diff options
author | Helmut Schaa <helmut.schaa@googlemail.com> | 2008-12-10 07:17:26 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-12-12 14:02:10 -0500 |
commit | 14a4dfe2ff8c353f59ae8324059ded1cfe22c7d9 (patch) | |
tree | 3301a6e2903012294d6e21dd96d04885f9a08cdb /drivers/net/wireless/ipw2x00/ipw2200.c | |
parent | d8004cb9267b15cd902eef01a75bb1ffa3995af8 (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.c | 28 |
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 | ||
6275 | static 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 | |||
6274 | static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct) | 6289 | static 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 |