aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-scan.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-07-14 23:40:34 -0400
committerDavid S. Miller <davem@davemloft.net>2008-07-14 23:40:34 -0400
commitfc943b12e48f9341bce48c2fadf094cc721aab93 (patch)
tree8c3244d7f5fae4edbfe0a5103789b0bc5c64f478 /drivers/net/wireless/iwlwifi/iwl-scan.c
parent72d9794f444734af56ef12833b496326643e2964 (diff)
parent4c9adafff7d910f142fe44fae37ed12c6b99f20f (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-scan.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c103
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
61static int scan_tx_ant[3] = { 67static 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
65static int iwl_is_empty_essid(const char *essid, int essid_len) 73static 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)
332EXPORT_SYMBOL(iwl_setup_rx_scan_handlers); 341EXPORT_SYMBOL(iwl_setup_rx_scan_handlers);
333 342
334static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, 343static 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
343static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, 355static 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
367static int iwl_get_channels_for_scan(struct iwl_priv *priv, 375static 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;