diff options
author | Tomas Winkler <tomas.winkler@intel.com> | 2008-06-11 21:47:12 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-06-14 12:18:08 -0400 |
commit | f53696de6722a4aac00b76e25a5321c01e88a55f (patch) | |
tree | cd735b6fd5bfa7a5ba593eb591cfc6d62d26e7dd /drivers/net/wireless | |
parent | e7d326ac437e9e9425dcd79382f4e5f6ca31fb16 (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/wireless')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-commands.h | 14 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-dev.h | 33 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-scan.c | 178 |
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 | */ | ||
290 | struct 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 | ******************************************************************************/ |
270 | void iwl_init_scan_params(struct iwl_priv *priv); | ||
270 | int iwl_scan_cancel(struct iwl_priv *priv); | 271 | int iwl_scan_cancel(struct iwl_priv *priv); |
271 | int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms); | 272 | int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms); |
272 | const char *iwl_escape_essid(const char *essid, u8 essid_len); | 273 | const 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. */ | ||
167 | struct 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. */ | ||
176 | struct 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 | |||
189 | struct iwl_channel_info { | 165 | struct 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 | ||
224 | struct iwl4965_clip_group { | 192 | struct 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 | 61 | static int scan_tx_ant[3] = { | |
62 | RATE_MCS_ANT_A_MSK, RATE_MCS_ANT_B_MSK, RATE_MCS_ANT_C_MSK | ||
63 | }; | ||
62 | 64 | ||
63 | static int iwl_is_empty_essid(const char *essid, int essid_len) | 65 | static 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 | ||
436 | void 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 | |||
437 | int iwl_scan_initiate(struct iwl_priv *priv) | 444 | int 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 | ||
524 | static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband, | 531 | static 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 | |||
550 | static u16 iwl_fill_probe_req(struct iwl_priv *priv, | 558 | static 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 | ||
656 | static 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 | |||
658 | static void iwl_bg_request_scan(struct work_struct *data) | 673 | static 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; |