aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorTomas Winkler <tomas.winkler@intel.com>2008-06-11 21:47:12 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-06-14 12:18:08 -0400
commitf53696de6722a4aac00b76e25a5321c01e88a55f (patch)
treecd735b6fd5bfa7a5ba593eb591cfc6d62d26e7dd /drivers/net
parente7d326ac437e9e9425dcd79382f4e5f6ca31fb16 (diff)
iwlwifi: cleans up scanning code
This patch 1. cleans up scanning code. 2. It adds round robin of TX antannas/chains. Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: Zhu Yi <yi.zhu@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h14
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h33
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c178
5 files changed, 107 insertions, 120 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 058e76415042..6613d323262a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -281,16 +281,7 @@ struct iwl_cmd_header {
281#define RATE_MCS_ANT_C_MSK 0x10000 281#define RATE_MCS_ANT_C_MSK 0x10000
282#define RATE_MCS_ANT_ABC_MSK 0x1C000 282#define RATE_MCS_ANT_ABC_MSK 0x1C000
283 283
284 284#define RATE_MCS_ANT_INIT_IND 1
285/**
286 * struct iwl4965_tx_power - txpower format used in REPLY_SCAN_CMD
287 *
288 * Scan uses only one transmitter, so only one analog/dsp gain pair is needed.
289 */
290struct iwl4965_tx_power {
291 u8 tx_gain; /* gain for analog radio */
292 u8 dsp_atten; /* gain for DSP */
293} __attribute__ ((packed));
294 285
295#define POWER_TABLE_NUM_ENTRIES 33 286#define POWER_TABLE_NUM_ENTRIES 33
296#define POWER_TABLE_NUM_HT_OFDM_ENTRIES 32 287#define POWER_TABLE_NUM_HT_OFDM_ENTRIES 32
@@ -2128,7 +2119,8 @@ struct iwl_scan_channel {
2128 */ 2119 */
2129 u8 type; 2120 u8 type;
2130 u8 channel; /* band is selected by iwl4965_scan_cmd "flags" field */ 2121 u8 channel; /* band is selected by iwl4965_scan_cmd "flags" field */
2131 struct iwl4965_tx_power tpc; 2122 u8 tx_gain; /* gain for analog radio */
2123 u8 dsp_atten; /* gain for DSP */
2132 __le16 active_dwell; /* in 1024-uSec TU (time units), typ 5-50 */ 2124 __le16 active_dwell; /* in 1024-uSec TU (time units), typ 5-50 */
2133 __le16 passive_dwell; /* in 1024-uSec TU (time units), typ 20-500 */ 2125 __le16 passive_dwell; /* in 1024-uSec TU (time units), typ 20-500 */
2134} __attribute__ ((packed)); 2126} __attribute__ ((packed));
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 7e20f46132d5..9794904b5bd9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -874,6 +874,7 @@ int iwl_init_drv(struct iwl_priv *priv)
874 874
875 /* Choose which receivers/antennas to use */ 875 /* Choose which receivers/antennas to use */
876 iwl_set_rxon_chain(priv); 876 iwl_set_rxon_chain(priv);
877 iwl_init_scan_params(priv);
877 878
878 if (priv->cfg->mod_params->enable_qos) 879 if (priv->cfg->mod_params->enable_qos)
879 priv->qos_data.qos_enable = 1; 880 priv->qos_data.qos_enable = 1;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 2eb08f3937f6..8d9fde61a365 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -267,6 +267,7 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags)
267/******************************************************************************* 267/*******************************************************************************
268 * Scanning 268 * Scanning
269 ******************************************************************************/ 269 ******************************************************************************/
270void iwl_init_scan_params(struct iwl_priv *priv);
270int iwl_scan_cancel(struct iwl_priv *priv); 271int iwl_scan_cancel(struct iwl_priv *priv);
271int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms); 272int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
272const char *iwl_escape_essid(const char *essid, u8 essid_len); 273const char *iwl_escape_essid(const char *essid, u8 essid_len);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 69765c975d38..ef7415928b74 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -157,35 +157,11 @@ struct iwl4965_channel_tgh_info {
157 s64 last_radar_time; 157 s64 last_radar_time;
158}; 158};
159 159
160/* current Tx power values to use, one for each rate for each channel.
161 * requested power is limited by:
162 * -- regulatory EEPROM limits for this channel
163 * -- hardware capabilities (clip-powers)
164 * -- spectrum management
165 * -- user preference (e.g. iwconfig)
166 * when requested power is set, base power index must also be set. */
167struct iwl4965_channel_power_info {
168 struct iwl4965_tx_power tpc; /* actual radio and DSP gain settings */
169 s8 power_table_index; /* actual (compenst'd) index into gain table */
170 s8 base_power_index; /* gain index for power at factory temp. */
171 s8 requested_power; /* power (dBm) requested for this chnl/rate */
172};
173
174/* current scan Tx power values to use, one for each scan rate for each
175 * channel. */
176struct iwl4965_scan_power_info {
177 struct iwl4965_tx_power tpc; /* actual radio and DSP gain settings */
178 s8 power_table_index; /* actual (compenst'd) index into gain table */
179 s8 requested_power; /* scan pwr (dBm) requested for chnl/rate */
180};
181
182/* 160/*
183 * One for each channel, holds all channel setup data 161 * One for each channel, holds all channel setup data
184 * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant 162 * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant
185 * with one another! 163 * with one another!
186 */ 164 */
187#define IWL4965_MAX_RATE (33)
188
189struct iwl_channel_info { 165struct iwl_channel_info {
190 struct iwl4965_channel_tgd_info tgd; 166 struct iwl4965_channel_tgd_info tgd;
191 struct iwl4965_channel_tgh_info tgh; 167 struct iwl4965_channel_tgh_info tgh;
@@ -204,11 +180,6 @@ struct iwl_channel_info {
204 u8 band_index; /* 0-4, maps channel to band1/2/3/4/5 */ 180 u8 band_index; /* 0-4, maps channel to band1/2/3/4/5 */
205 enum ieee80211_band band; 181 enum ieee80211_band band;
206 182
207 /* Radio/DSP gain settings for each "normal" data Tx rate.
208 * These include, in addition to RF and DSP gain, a few fields for
209 * remembering/modifying gain settings (indexes). */
210 struct iwl4965_channel_power_info power_info[IWL4965_MAX_RATE];
211
212 /* FAT channel info */ 183 /* FAT channel info */
213 s8 fat_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */ 184 s8 fat_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */
214 s8 fat_curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */ 185 s8 fat_curr_txpow; /* (dBm) regulatory/spectrum/user (not h/w) */
@@ -216,9 +187,6 @@ struct iwl_channel_info {
216 s8 fat_scan_power; /* (dBm) eeprom, direct scans, any rate */ 187 s8 fat_scan_power; /* (dBm) eeprom, direct scans, any rate */
217 u8 fat_flags; /* flags copied from EEPROM */ 188 u8 fat_flags; /* flags copied from EEPROM */
218 u8 fat_extension_channel; /* HT_IE_EXT_CHANNEL_* */ 189 u8 fat_extension_channel; /* HT_IE_EXT_CHANNEL_* */
219
220 /* Radio/DSP gain settings for each scan rate, for directed scans. */
221 struct iwl4965_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES];
222}; 190};
223 191
224struct iwl4965_clip_group { 192struct iwl4965_clip_group {
@@ -974,6 +942,7 @@ struct iwl_priv {
974 u8 direct_ssid_len; 942 u8 direct_ssid_len;
975 u8 direct_ssid[IW_ESSID_MAX_SIZE]; 943 u8 direct_ssid[IW_ESSID_MAX_SIZE];
976 struct iwl_scan_cmd *scan; 944 struct iwl_scan_cmd *scan;
945 u32 scan_tx_ant[IEEE80211_NUM_BANDS];
977 946
978 /* spinlock */ 947 /* spinlock */
979 spinlock_t lock; /* protect general shared data */ 948 spinlock_t lock; /* protect general shared data */
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index 7b9475b7f0f4..5ca181f7125d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -58,7 +58,9 @@
58#define IWL_PASSIVE_DWELL_BASE (100) 58#define IWL_PASSIVE_DWELL_BASE (100)
59#define IWL_CHANNEL_TUNE_TIME 5 59#define IWL_CHANNEL_TUNE_TIME 5
60 60
61 61static int scan_tx_ant[3] = {
62 RATE_MCS_ANT_A_MSK, RATE_MCS_ANT_B_MSK, RATE_MCS_ANT_C_MSK
63};
62 64
63static int iwl_is_empty_essid(const char *essid, int essid_len) 65static int iwl_is_empty_essid(const char *essid, int essid_len)
64{ 66{
@@ -385,8 +387,7 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
385 scan_ch->channel = 387 scan_ch->channel =
386 ieee80211_frequency_to_channel(channels[i].center_freq); 388 ieee80211_frequency_to_channel(channels[i].center_freq);
387 389
388 ch_info = iwl_get_channel_info(priv, band, 390 ch_info = iwl_get_channel_info(priv, band, scan_ch->channel);
389 scan_ch->channel);
390 if (!is_channel_valid(ch_info)) { 391 if (!is_channel_valid(ch_info)) {
391 IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n", 392 IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
392 scan_ch->channel); 393 scan_ch->channel);
@@ -395,9 +396,9 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
395 396
396 if (!is_active || is_channel_passive(ch_info) || 397 if (!is_active || is_channel_passive(ch_info) ||
397 (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) 398 (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN))
398 scan_ch->type = 0; /* passive */ 399 scan_ch->type = 0;
399 else 400 else
400 scan_ch->type = 1; /* active */ 401 scan_ch->type = 1;
401 402
402 if (scan_ch->type & 1) 403 if (scan_ch->type & 1)
403 scan_ch->type |= (direct_mask << 1); 404 scan_ch->type |= (direct_mask << 1);
@@ -406,17 +407,15 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
406 scan_ch->passive_dwell = cpu_to_le16(passive_dwell); 407 scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
407 408
408 /* Set txpower levels to defaults */ 409 /* Set txpower levels to defaults */
409 scan_ch->tpc.dsp_atten = 110; 410 scan_ch->dsp_atten = 110;
410 /* scan_pwr_info->tpc.dsp_atten; */
411 411
412 /*scan_pwr_info->tpc.tx_gain; */
413 if (band == IEEE80211_BAND_5GHZ) 412 if (band == IEEE80211_BAND_5GHZ)
414 scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3; 413 scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
415 else { 414 else {
416 scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3)); 415 scan_ch->tx_gain = ((1 << 5) | (5 << 3));
417 /* NOTE: if we were doing 6Mb OFDM for scans we'd use 416 /* NOTE: if we were doing 6Mb OFDM for scans we'd use
418 * power level: 417 * power level:
419 * scan_ch->tpc.tx_gain = ((1 << 5) | (2 << 3)) | 3; 418 * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
420 */ 419 */
421 } 420 }
422 421
@@ -434,6 +433,14 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
434 return added; 433 return added;
435} 434}
436 435
436void iwl_init_scan_params(struct iwl_priv *priv)
437{
438 if (!priv->scan_tx_ant[IEEE80211_BAND_5GHZ])
439 priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = RATE_MCS_ANT_INIT_IND;
440 if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ])
441 priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = RATE_MCS_ANT_INIT_IND;
442}
443
437int iwl_scan_initiate(struct iwl_priv *priv) 444int iwl_scan_initiate(struct iwl_priv *priv)
438{ 445{
439 if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { 446 if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
@@ -522,7 +529,7 @@ static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate,
522 529
523 530
524static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband, 531static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband,
525 u8 *pos, int *left) 532 u8 *pos, int *left)
526{ 533{
527 struct ieee80211_ht_cap *ht_cap; 534 struct ieee80211_ht_cap *ht_cap;
528 535
@@ -547,10 +554,11 @@ static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband,
547/** 554/**
548 * iwl_fill_probe_req - fill in all required fields and IE for probe request 555 * iwl_fill_probe_req - fill in all required fields and IE for probe request
549 */ 556 */
557
550static u16 iwl_fill_probe_req(struct iwl_priv *priv, 558static u16 iwl_fill_probe_req(struct iwl_priv *priv,
551 enum ieee80211_band band, 559 enum ieee80211_band band,
552 struct ieee80211_mgmt *frame, 560 struct ieee80211_mgmt *frame,
553 int left, int is_direct) 561 int left)
554{ 562{
555 int len = 0; 563 int len = 0;
556 u8 *pos = NULL; 564 u8 *pos = NULL;
@@ -558,12 +566,12 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
558 const struct ieee80211_supported_band *sband = 566 const struct ieee80211_supported_band *sband =
559 iwl_get_hw_mode(priv, band); 567 iwl_get_hw_mode(priv, band);
560 568
569
561 /* Make sure there is enough space for the probe request, 570 /* Make sure there is enough space for the probe request,
562 * two mandatory IEs and the data */ 571 * two mandatory IEs and the data */
563 left -= 24; 572 left -= 24;
564 if (left < 0) 573 if (left < 0)
565 return 0; 574 return 0;
566 len += 24;
567 575
568 frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); 576 frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
569 memcpy(frame->da, iwl_bcast_addr, ETH_ALEN); 577 memcpy(frame->da, iwl_bcast_addr, ETH_ALEN);
@@ -571,38 +579,25 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
571 memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN); 579 memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN);
572 frame->seq_ctrl = 0; 580 frame->seq_ctrl = 0;
573 581
574 /* fill in our indirect SSID IE */ 582 len += 24;
583
575 /* ...next IE... */ 584 /* ...next IE... */
585 pos = &frame->u.probe_req.variable[0];
576 586
587 /* fill in our indirect SSID IE */
577 left -= 2; 588 left -= 2;
578 if (left < 0) 589 if (left < 0)
579 return 0; 590 return 0;
580 len += 2;
581 pos = &(frame->u.probe_req.variable[0]);
582 *pos++ = WLAN_EID_SSID; 591 *pos++ = WLAN_EID_SSID;
583 *pos++ = 0; 592 *pos++ = 0;
584 593
585 /* fill in our direct SSID IE... */ 594 len += 2;
586 if (is_direct) {
587 /* ...next IE... */
588 left -= 2 + priv->essid_len;
589 if (left < 0)
590 return 0;
591 /* ... fill it in... */
592 *pos++ = WLAN_EID_SSID;
593 *pos++ = priv->essid_len;
594 memcpy(pos, priv->essid, priv->essid_len);
595 pos += priv->essid_len;
596 len += 2 + priv->essid_len;
597 }
598 595
599 /* fill in supported rate */ 596 /* fill in supported rate */
600 /* ...next IE... */
601 left -= 2; 597 left -= 2;
602 if (left < 0) 598 if (left < 0)
603 return 0; 599 return 0;
604 600
605 /* ... fill it in... */
606 *pos++ = WLAN_EID_SUPP_RATES; 601 *pos++ = WLAN_EID_SUPP_RATES;
607 *pos = 0; 602 *pos = 0;
608 603
@@ -614,15 +609,16 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
614 609
615 cck_rates = IWL_CCK_RATES_MASK & active_rates; 610 cck_rates = IWL_CCK_RATES_MASK & active_rates;
616 ret_rates = iwl_supported_rate_to_ie(pos, cck_rates, 611 ret_rates = iwl_supported_rate_to_ie(pos, cck_rates,
617 active_rate_basic, &left); 612 active_rate_basic, &left);
618 active_rates &= ~ret_rates; 613 active_rates &= ~ret_rates;
619 614
620 ret_rates = iwl_supported_rate_to_ie(pos, active_rates, 615 ret_rates = iwl_supported_rate_to_ie(pos, active_rates,
621 active_rate_basic, &left); 616 active_rate_basic, &left);
622 active_rates &= ~ret_rates; 617 active_rates &= ~ret_rates;
623 618
624 len += 2 + *pos; 619 len += 2 + *pos;
625 pos += (*pos) + 1; 620 pos += (*pos) + 1;
621
626 if (active_rates == 0) 622 if (active_rates == 0)
627 goto fill_end; 623 goto fill_end;
628 624
@@ -634,27 +630,46 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv,
634 /* ... fill it in... */ 630 /* ... fill it in... */
635 *pos++ = WLAN_EID_EXT_SUPP_RATES; 631 *pos++ = WLAN_EID_EXT_SUPP_RATES;
636 *pos = 0; 632 *pos = 0;
637 iwl_supported_rate_to_ie(pos, active_rates, 633 iwl_supported_rate_to_ie(pos, active_rates, active_rate_basic, &left);
638 active_rate_basic, &left); 634 if (*pos > 0) {
639 if (*pos > 0)
640 len += 2 + *pos; 635 len += 2 + *pos;
636 pos += (*pos) + 1;
637 } else {
638 pos--;
639 }
641 640
642 fill_end: 641 fill_end:
643 /* fill in HT IE */ 642
644 left -= 2; 643 left -= 2;
645 if (left < 0) 644 if (left < 0)
646 return 0; 645 return 0;
647 646
648 *pos++ = WLAN_EID_HT_CAPABILITY; 647 *pos++ = WLAN_EID_HT_CAPABILITY;
649 *pos = 0; 648 *pos = 0;
650
651 iwl_ht_cap_to_ie(sband, pos, &left); 649 iwl_ht_cap_to_ie(sband, pos, &left);
652
653 if (*pos > 0) 650 if (*pos > 0)
654 len += 2 + *pos; 651 len += 2 + *pos;
652
655 return (u16)len; 653 return (u16)len;
656} 654}
657 655
656static u32 iwl_scan_tx_ant(struct iwl_priv *priv, enum ieee80211_band band)
657{
658 int i, ind;
659
660 ind = priv->scan_tx_ant[band];
661 for (i = 0; i < priv->hw_params.tx_chains_num; i++) {
662 ind = (ind+1) >= priv->hw_params.tx_chains_num ? 0 : ind+1;
663 if (priv->hw_params.valid_tx_ant & (1 << ind)) {
664 priv->scan_tx_ant[band] = ind;
665 break;
666 }
667 }
668
669 return scan_tx_ant[ind];
670}
671
672
658static void iwl_bg_request_scan(struct work_struct *data) 673static void iwl_bg_request_scan(struct work_struct *data)
659{ 674{
660 struct iwl_priv *priv = 675 struct iwl_priv *priv =
@@ -666,10 +681,12 @@ static void iwl_bg_request_scan(struct work_struct *data)
666 }; 681 };
667 struct iwl_scan_cmd *scan; 682 struct iwl_scan_cmd *scan;
668 struct ieee80211_conf *conf = NULL; 683 struct ieee80211_conf *conf = NULL;
684 int ret = 0;
685 u32 tx_ant;
669 u16 cmd_len; 686 u16 cmd_len;
670 enum ieee80211_band band; 687 enum ieee80211_band band;
671 u8 direct_mask; 688 u8 direct_mask;
672 int ret = 0; 689 u8 rx_chain = 0x7; /* bitmap: ABC chains */
673 690
674 conf = ieee80211_get_hw_conf(priv->hw); 691 conf = ieee80211_get_hw_conf(priv->hw);
675 692
@@ -761,25 +778,23 @@ static void iwl_bg_request_scan(struct work_struct *data)
761 778
762 /* We should add the ability for user to lock to PASSIVE ONLY */ 779 /* We should add the ability for user to lock to PASSIVE ONLY */
763 if (priv->one_direct_scan) { 780 if (priv->one_direct_scan) {
764 IWL_DEBUG_SCAN 781 IWL_DEBUG_SCAN("Start direct scan for '%s'\n",
765 ("Kicking off one direct scan for '%s'\n", 782 iwl_escape_essid(priv->direct_ssid,
766 iwl_escape_essid(priv->direct_ssid, 783 priv->direct_ssid_len));
767 priv->direct_ssid_len));
768 scan->direct_scan[0].id = WLAN_EID_SSID; 784 scan->direct_scan[0].id = WLAN_EID_SSID;
769 scan->direct_scan[0].len = priv->direct_ssid_len; 785 scan->direct_scan[0].len = priv->direct_ssid_len;
770 memcpy(scan->direct_scan[0].ssid, 786 memcpy(scan->direct_scan[0].ssid,
771 priv->direct_ssid, priv->direct_ssid_len); 787 priv->direct_ssid, priv->direct_ssid_len);
772 direct_mask = 1; 788 direct_mask = 1;
773 } else if (!iwl_is_associated(priv) && priv->essid_len) { 789 } else if (!iwl_is_associated(priv) && priv->essid_len) {
774 IWL_DEBUG_SCAN 790 IWL_DEBUG_SCAN("Start direct scan for '%s' (not associated)\n",
775 ("Kicking off one direct scan for '%s' when not associated\n", 791 iwl_escape_essid(priv->essid, priv->essid_len));
776 iwl_escape_essid(priv->essid, priv->essid_len));
777 scan->direct_scan[0].id = WLAN_EID_SSID; 792 scan->direct_scan[0].id = WLAN_EID_SSID;
778 scan->direct_scan[0].len = priv->essid_len; 793 scan->direct_scan[0].len = priv->essid_len;
779 memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len); 794 memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
780 direct_mask = 1; 795 direct_mask = 1;
781 } else { 796 } else {
782 IWL_DEBUG_SCAN("Kicking off one indirect scan.\n"); 797 IWL_DEBUG_SCAN("Start indirect scan.\n");
783 direct_mask = 0; 798 direct_mask = 0;
784 } 799 }
785 800
@@ -790,64 +805,73 @@ static void iwl_bg_request_scan(struct work_struct *data)
790 805
791 switch (priv->scan_bands) { 806 switch (priv->scan_bands) {
792 case 2: 807 case 2:
808 band = IEEE80211_BAND_2GHZ;
793 scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; 809 scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
794 scan->tx_cmd.rate_n_flags = 810 tx_ant = iwl_scan_tx_ant(priv, band);
811 if (priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK)
812 scan->tx_cmd.rate_n_flags =
813 iwl_hw_set_rate_n_flags(IWL_RATE_6M_PLCP,
814 tx_ant);
815 else
816 scan->tx_cmd.rate_n_flags =
795 iwl_hw_set_rate_n_flags(IWL_RATE_1M_PLCP, 817 iwl_hw_set_rate_n_flags(IWL_RATE_1M_PLCP,
796 RATE_MCS_ANT_B_MSK| 818 tx_ant |
797 RATE_MCS_CCK_MSK); 819 RATE_MCS_CCK_MSK);
798
799 scan->good_CRC_th = 0; 820 scan->good_CRC_th = 0;
800 band = IEEE80211_BAND_2GHZ;
801 break; 821 break;
802 822
803 case 1: 823 case 1:
824 band = IEEE80211_BAND_5GHZ;
825 tx_ant = iwl_scan_tx_ant(priv, band);
804 scan->tx_cmd.rate_n_flags = 826 scan->tx_cmd.rate_n_flags =
805 iwl_hw_set_rate_n_flags(IWL_RATE_6M_PLCP, 827 iwl_hw_set_rate_n_flags(IWL_RATE_6M_PLCP,
806 RATE_MCS_ANT_B_MSK); 828 tx_ant);
807 scan->good_CRC_th = IWL_GOOD_CRC_TH; 829 scan->good_CRC_th = IWL_GOOD_CRC_TH;
808 band = IEEE80211_BAND_5GHZ;
809 break;
810 830
831 /* Force use of chains B and C (0x6) for scan Rx for 4965
832 * Avoid A (0x1) because of its off-channel reception on A-band.
833 * MIMO is not used here, but value is required */
834 if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)
835 rx_chain = 0x6;
836
837 break;
811 default: 838 default:
812 IWL_WARNING("Invalid scan band count\n"); 839 IWL_WARNING("Invalid scan band count\n");
813 goto done; 840 goto done;
814 } 841 }
815 842
816 /* We don't build a direct scan probe request; the uCode will do 843 scan->rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK |
817 * that based on the direct_mask added to each channel entry */ 844 cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) |
845 (rx_chain << RXON_RX_CHAIN_FORCE_SEL_POS) |
846 (0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS));
847
818 cmd_len = iwl_fill_probe_req(priv, band, 848 cmd_len = iwl_fill_probe_req(priv, band,
819 (struct ieee80211_mgmt *)scan->data, 849 (struct ieee80211_mgmt *)scan->data,
820 IWL_MAX_SCAN_SIZE - sizeof(*scan), 0); 850 IWL_MAX_SCAN_SIZE - sizeof(*scan));
821 851
822 scan->tx_cmd.len = cpu_to_le16(cmd_len); 852 scan->tx_cmd.len = cpu_to_le16(cmd_len);
823 /* select Rx chains */
824
825 /* Force use of chains B and C (0x6) for scan Rx.
826 * Avoid A (0x1) because of its off-channel reception on A-band.
827 * MIMO is not used here, but value is required to make uCode happy. */
828 scan->rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK |
829 cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) |
830 (0x6 << RXON_RX_CHAIN_FORCE_SEL_POS) |
831 (0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS));
832 853
833 if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) 854 if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR)
834 scan->filter_flags = RXON_FILTER_PROMISC_MSK; 855 scan->filter_flags = RXON_FILTER_PROMISC_MSK;
835 856
857 scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
858 RXON_FILTER_BCON_AWARE_MSK);
859
836 if (direct_mask) 860 if (direct_mask)
837 scan->channel_count = 861 scan->channel_count =
838 iwl_get_channels_for_scan( 862 iwl_get_channels_for_scan(priv, band, 1, /* active */
839 priv, band, 1, /* active */ 863 direct_mask,
840 direct_mask,
841 (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); 864 (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
842 else 865 else
843 scan->channel_count = 866 scan->channel_count =
844 iwl_get_channels_for_scan( 867 iwl_get_channels_for_scan(priv, band, 0, /* passive */
845 priv, band, 0, /* passive */ 868 direct_mask,
846 direct_mask,
847 (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); 869 (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
870 if (scan->channel_count == 0) {
871 IWL_DEBUG_SCAN("channel count %d\n", scan->channel_count);
872 goto done;
873 }
848 874
849 scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
850 RXON_FILTER_BCON_AWARE_MSK);
851 cmd.len += le16_to_cpu(scan->tx_cmd.len) + 875 cmd.len += le16_to_cpu(scan->tx_cmd.len) +
852 scan->channel_count * sizeof(struct iwl_scan_channel); 876 scan->channel_count * sizeof(struct iwl_scan_channel);
853 cmd.data = scan; 877 cmd.data = scan;