diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-scan.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-scan.c | 103 |
1 files changed, 55 insertions, 48 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 5b420b43af5c..efc750d2fc5c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c | |||
@@ -38,8 +38,11 @@ | |||
38 | /* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after | 38 | /* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after |
39 | * sending probe req. This should be set long enough to hear probe responses | 39 | * sending probe req. This should be set long enough to hear probe responses |
40 | * from more than one AP. */ | 40 | * from more than one AP. */ |
41 | #define IWL_ACTIVE_DWELL_TIME_24 (20) /* all times in msec */ | 41 | #define IWL_ACTIVE_DWELL_TIME_24 (30) /* all times in msec */ |
42 | #define IWL_ACTIVE_DWELL_TIME_52 (10) | 42 | #define IWL_ACTIVE_DWELL_TIME_52 (20) |
43 | |||
44 | #define IWL_ACTIVE_DWELL_FACTOR_24GHZ (3) | ||
45 | #define IWL_ACTIVE_DWELL_FACTOR_52GHZ (2) | ||
43 | 46 | ||
44 | /* For faster active scanning, scan will move to the next channel if fewer than | 47 | /* For faster active scanning, scan will move to the next channel if fewer than |
45 | * PLCP_QUIET_THRESH packets are heard on this channel within | 48 | * PLCP_QUIET_THRESH packets are heard on this channel within |
@@ -48,7 +51,7 @@ | |||
48 | * no other traffic). | 51 | * no other traffic). |
49 | * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */ | 52 | * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */ |
50 | #define IWL_PLCP_QUIET_THRESH __constant_cpu_to_le16(1) /* packets */ | 53 | #define IWL_PLCP_QUIET_THRESH __constant_cpu_to_le16(1) /* packets */ |
51 | #define IWL_ACTIVE_QUIET_TIME __constant_cpu_to_le16(5) /* msec */ | 54 | #define IWL_ACTIVE_QUIET_TIME __constant_cpu_to_le16(10) /* msec */ |
52 | 55 | ||
53 | /* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel. | 56 | /* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel. |
54 | * Must be set longer than active dwell time. | 57 | * Must be set longer than active dwell time. |
@@ -58,10 +61,15 @@ | |||
58 | #define IWL_PASSIVE_DWELL_BASE (100) | 61 | #define IWL_PASSIVE_DWELL_BASE (100) |
59 | #define IWL_CHANNEL_TUNE_TIME 5 | 62 | #define IWL_CHANNEL_TUNE_TIME 5 |
60 | 63 | ||
64 | #define IWL_SCAN_PROBE_MASK(n) cpu_to_le32((BIT(n) | (BIT(n) - BIT(1)))) | ||
65 | |||
66 | |||
61 | static int scan_tx_ant[3] = { | 67 | static int scan_tx_ant[3] = { |
62 | RATE_MCS_ANT_A_MSK, RATE_MCS_ANT_B_MSK, RATE_MCS_ANT_C_MSK | 68 | RATE_MCS_ANT_A_MSK, RATE_MCS_ANT_B_MSK, RATE_MCS_ANT_C_MSK |
63 | }; | 69 | }; |
64 | 70 | ||
71 | |||
72 | |||
65 | static int iwl_is_empty_essid(const char *essid, int essid_len) | 73 | static int iwl_is_empty_essid(const char *essid, int essid_len) |
66 | { | 74 | { |
67 | /* Single white space is for Linksys APs */ | 75 | /* Single white space is for Linksys APs */ |
@@ -226,8 +234,9 @@ static void iwl_rx_scan_start_notif(struct iwl_priv *priv, | |||
226 | "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n", | 234 | "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n", |
227 | notif->channel, | 235 | notif->channel, |
228 | notif->band ? "bg" : "a", | 236 | notif->band ? "bg" : "a", |
229 | notif->tsf_high, | 237 | le32_to_cpu(notif->tsf_high), |
230 | notif->tsf_low, notif->status, notif->beacon_timer); | 238 | le32_to_cpu(notif->tsf_low), |
239 | notif->status, notif->beacon_timer); | ||
231 | } | 240 | } |
232 | 241 | ||
233 | /* Service SCAN_RESULTS_NOTIFICATION (0x83) */ | 242 | /* Service SCAN_RESULTS_NOTIFICATION (0x83) */ |
@@ -332,19 +341,21 @@ void iwl_setup_rx_scan_handlers(struct iwl_priv *priv) | |||
332 | EXPORT_SYMBOL(iwl_setup_rx_scan_handlers); | 341 | EXPORT_SYMBOL(iwl_setup_rx_scan_handlers); |
333 | 342 | ||
334 | static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, | 343 | static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, |
335 | enum ieee80211_band band) | 344 | enum ieee80211_band band, |
345 | u8 n_probes) | ||
336 | { | 346 | { |
337 | if (band == IEEE80211_BAND_5GHZ) | 347 | if (band == IEEE80211_BAND_5GHZ) |
338 | return IWL_ACTIVE_DWELL_TIME_52; | 348 | return IWL_ACTIVE_DWELL_TIME_52 + |
349 | IWL_ACTIVE_DWELL_FACTOR_52GHZ * (n_probes + 1); | ||
339 | else | 350 | else |
340 | return IWL_ACTIVE_DWELL_TIME_24; | 351 | return IWL_ACTIVE_DWELL_TIME_24 + |
352 | IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1); | ||
341 | } | 353 | } |
342 | 354 | ||
343 | static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, | 355 | static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, |
344 | enum ieee80211_band band) | 356 | enum ieee80211_band band) |
345 | { | 357 | { |
346 | u16 active = iwl_get_active_dwell_time(priv, band); | 358 | u16 passive = (band == IEEE80211_BAND_2GHZ) ? |
347 | u16 passive = (band != IEEE80211_BAND_5GHZ) ? | ||
348 | IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 : | 359 | IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 : |
349 | IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52; | 360 | IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52; |
350 | 361 | ||
@@ -358,15 +369,12 @@ static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, | |||
358 | passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2; | 369 | passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2; |
359 | } | 370 | } |
360 | 371 | ||
361 | if (passive <= active) | ||
362 | passive = active + 1; | ||
363 | |||
364 | return passive; | 372 | return passive; |
365 | } | 373 | } |
366 | 374 | ||
367 | static int iwl_get_channels_for_scan(struct iwl_priv *priv, | 375 | static int iwl_get_channels_for_scan(struct iwl_priv *priv, |
368 | enum ieee80211_band band, | 376 | enum ieee80211_band band, |
369 | u8 is_active, u8 direct_mask, | 377 | u8 is_active, u8 n_probes, |
370 | struct iwl_scan_channel *scan_ch) | 378 | struct iwl_scan_channel *scan_ch) |
371 | { | 379 | { |
372 | const struct ieee80211_channel *channels = NULL; | 380 | const struct ieee80211_channel *channels = NULL; |
@@ -375,6 +383,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, | |||
375 | u16 passive_dwell = 0; | 383 | u16 passive_dwell = 0; |
376 | u16 active_dwell = 0; | 384 | u16 active_dwell = 0; |
377 | int added, i; | 385 | int added, i; |
386 | u16 channel; | ||
378 | 387 | ||
379 | sband = iwl_get_hw_mode(priv, band); | 388 | sband = iwl_get_hw_mode(priv, band); |
380 | if (!sband) | 389 | if (!sband) |
@@ -382,31 +391,35 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, | |||
382 | 391 | ||
383 | channels = sband->channels; | 392 | channels = sband->channels; |
384 | 393 | ||
385 | active_dwell = iwl_get_active_dwell_time(priv, band); | 394 | active_dwell = iwl_get_active_dwell_time(priv, band, n_probes); |
386 | passive_dwell = iwl_get_passive_dwell_time(priv, band); | 395 | passive_dwell = iwl_get_passive_dwell_time(priv, band); |
387 | 396 | ||
397 | if (passive_dwell <= active_dwell) | ||
398 | passive_dwell = active_dwell + 1; | ||
399 | |||
388 | for (i = 0, added = 0; i < sband->n_channels; i++) { | 400 | for (i = 0, added = 0; i < sband->n_channels; i++) { |
389 | if (channels[i].flags & IEEE80211_CHAN_DISABLED) | 401 | if (channels[i].flags & IEEE80211_CHAN_DISABLED) |
390 | continue; | 402 | continue; |
391 | 403 | ||
392 | scan_ch->channel = | 404 | channel = |
393 | ieee80211_frequency_to_channel(channels[i].center_freq); | 405 | ieee80211_frequency_to_channel(channels[i].center_freq); |
406 | scan_ch->channel = cpu_to_le16(channel); | ||
394 | 407 | ||
395 | ch_info = iwl_get_channel_info(priv, band, scan_ch->channel); | 408 | ch_info = iwl_get_channel_info(priv, band, channel); |
396 | if (!is_channel_valid(ch_info)) { | 409 | if (!is_channel_valid(ch_info)) { |
397 | IWL_DEBUG_SCAN("Channel %d is INVALID for this band.\n", | 410 | IWL_DEBUG_SCAN("Channel %d is INVALID for this band.\n", |
398 | scan_ch->channel); | 411 | channel); |
399 | continue; | 412 | continue; |
400 | } | 413 | } |
401 | 414 | ||
402 | if (!is_active || is_channel_passive(ch_info) || | 415 | if (!is_active || is_channel_passive(ch_info) || |
403 | (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) | 416 | (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) |
404 | scan_ch->type = 0; | 417 | scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE; |
405 | else | 418 | else |
406 | scan_ch->type = 1; | 419 | scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE; |
407 | 420 | ||
408 | if (scan_ch->type & 1) | 421 | if ((scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) && n_probes) |
409 | scan_ch->type |= (direct_mask << 1); | 422 | scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes); |
410 | 423 | ||
411 | scan_ch->active_dwell = cpu_to_le16(active_dwell); | 424 | scan_ch->active_dwell = cpu_to_le16(active_dwell); |
412 | scan_ch->passive_dwell = cpu_to_le16(passive_dwell); | 425 | scan_ch->passive_dwell = cpu_to_le16(passive_dwell); |
@@ -414,20 +427,20 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, | |||
414 | /* Set txpower levels to defaults */ | 427 | /* Set txpower levels to defaults */ |
415 | scan_ch->dsp_atten = 110; | 428 | scan_ch->dsp_atten = 110; |
416 | 429 | ||
430 | /* NOTE: if we were doing 6Mb OFDM for scans we'd use | ||
431 | * power level: | ||
432 | * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3; | ||
433 | */ | ||
417 | if (band == IEEE80211_BAND_5GHZ) | 434 | if (band == IEEE80211_BAND_5GHZ) |
418 | scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3; | 435 | scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3; |
419 | else { | 436 | else |
420 | scan_ch->tx_gain = ((1 << 5) | (5 << 3)); | 437 | scan_ch->tx_gain = ((1 << 5) | (5 << 3)); |
421 | /* NOTE: if we were doing 6Mb OFDM for scans we'd use | ||
422 | * power level: | ||
423 | * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3; | ||
424 | */ | ||
425 | } | ||
426 | 438 | ||
427 | IWL_DEBUG_SCAN("Scanning %d [%s %d]\n", | 439 | IWL_DEBUG_SCAN("Scanning ch=%d prob=0x%X [%s %d]\n", |
428 | scan_ch->channel, | 440 | channel, le32_to_cpu(scan_ch->type), |
429 | (scan_ch->type & 1) ? "ACTIVE" : "PASSIVE", | 441 | (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ? |
430 | (scan_ch->type & 1) ? | 442 | "ACTIVE" : "PASSIVE", |
443 | (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ? | ||
431 | active_dwell : passive_dwell); | 444 | active_dwell : passive_dwell); |
432 | 445 | ||
433 | scan_ch++; | 446 | scan_ch++; |
@@ -673,7 +686,7 @@ static u32 iwl_scan_tx_ant(struct iwl_priv *priv, enum ieee80211_band band) | |||
673 | break; | 686 | break; |
674 | } | 687 | } |
675 | } | 688 | } |
676 | 689 | IWL_DEBUG_SCAN("select TX ANT = %c\n", 'A' + ind); | |
677 | return scan_tx_ant[ind]; | 690 | return scan_tx_ant[ind]; |
678 | } | 691 | } |
679 | 692 | ||
@@ -693,7 +706,7 @@ static void iwl_bg_request_scan(struct work_struct *data) | |||
693 | u32 tx_ant; | 706 | u32 tx_ant; |
694 | u16 cmd_len; | 707 | u16 cmd_len; |
695 | enum ieee80211_band band; | 708 | enum ieee80211_band band; |
696 | u8 direct_mask; | 709 | u8 n_probes = 2; |
697 | u8 rx_chain = 0x7; /* bitmap: ABC chains */ | 710 | u8 rx_chain = 0x7; /* bitmap: ABC chains */ |
698 | 711 | ||
699 | conf = ieee80211_get_hw_conf(priv->hw); | 712 | conf = ieee80211_get_hw_conf(priv->hw); |
@@ -793,17 +806,16 @@ static void iwl_bg_request_scan(struct work_struct *data) | |||
793 | scan->direct_scan[0].len = priv->direct_ssid_len; | 806 | scan->direct_scan[0].len = priv->direct_ssid_len; |
794 | memcpy(scan->direct_scan[0].ssid, | 807 | memcpy(scan->direct_scan[0].ssid, |
795 | priv->direct_ssid, priv->direct_ssid_len); | 808 | priv->direct_ssid, priv->direct_ssid_len); |
796 | direct_mask = 1; | 809 | n_probes++; |
797 | } else if (!iwl_is_associated(priv) && priv->essid_len) { | 810 | } else if (!iwl_is_associated(priv) && priv->essid_len) { |
798 | IWL_DEBUG_SCAN("Start direct scan for '%s' (not associated)\n", | 811 | IWL_DEBUG_SCAN("Start direct scan for '%s' (not associated)\n", |
799 | iwl_escape_essid(priv->essid, priv->essid_len)); | 812 | iwl_escape_essid(priv->essid, priv->essid_len)); |
800 | scan->direct_scan[0].id = WLAN_EID_SSID; | 813 | scan->direct_scan[0].id = WLAN_EID_SSID; |
801 | scan->direct_scan[0].len = priv->essid_len; | 814 | scan->direct_scan[0].len = priv->essid_len; |
802 | memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len); | 815 | memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len); |
803 | direct_mask = 1; | 816 | n_probes++; |
804 | } else { | 817 | } else { |
805 | IWL_DEBUG_SCAN("Start indirect scan.\n"); | 818 | IWL_DEBUG_SCAN("Start indirect scan.\n"); |
806 | direct_mask = 0; | ||
807 | } | 819 | } |
808 | 820 | ||
809 | scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; | 821 | scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; |
@@ -860,16 +872,11 @@ static void iwl_bg_request_scan(struct work_struct *data) | |||
860 | scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK | | 872 | scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK | |
861 | RXON_FILTER_BCON_AWARE_MSK); | 873 | RXON_FILTER_BCON_AWARE_MSK); |
862 | 874 | ||
863 | if (direct_mask) | 875 | scan->channel_count = |
864 | scan->channel_count = | 876 | iwl_get_channels_for_scan(priv, band, 1, /* active */ |
865 | iwl_get_channels_for_scan(priv, band, 1, /* active */ | 877 | n_probes, |
866 | direct_mask, | 878 | (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); |
867 | (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); | 879 | |
868 | else | ||
869 | scan->channel_count = | ||
870 | iwl_get_channels_for_scan(priv, band, 0, /* passive */ | ||
871 | direct_mask, | ||
872 | (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); | ||
873 | if (scan->channel_count == 0) { | 880 | if (scan->channel_count == 0) { |
874 | IWL_DEBUG_SCAN("channel count %d\n", scan->channel_count); | 881 | IWL_DEBUG_SCAN("channel count %d\n", scan->channel_count); |
875 | goto done; | 882 | goto done; |