diff options
author | Wey-Yi Guy <wey-yi.w.guy@intel.com> | 2009-05-22 14:01:49 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-05-22 14:06:05 -0400 |
commit | a2b0f02e4795bfde5f11720a10af8923cb98b654 (patch) | |
tree | 1d2cad3ff20f43ba51aace00a8c2c627fe013581 /drivers/net/wireless | |
parent | a9c146b369cd8facbbbec7d8b31440f6eaa43e03 (diff) |
iwlwifi: support "pure 40MHz" in RXON command
Fix the bug when using 11n "pure 40MHz" mode cause uCode
crashing by adding support for "pure 40MHz" in RX_ON command flag.
the "mode" field (bits 25:26) has value of 0-3
0 = 20 MHz only
1 = 40MHz only
2 = Mixed
3 = Reserved
Control Channel ID (bit 22) is valid only in Mixed mode.
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@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-4965.c | 12 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-commands.h | 14 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 84 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-scan.c | 5 |
4 files changed, 72 insertions, 43 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 4be7bd29ef6d..7df41163ded2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c | |||
@@ -293,10 +293,12 @@ restart: | |||
293 | queue_work(priv->workqueue, &priv->restart); | 293 | queue_work(priv->workqueue, &priv->restart); |
294 | } | 294 | } |
295 | 295 | ||
296 | static int is_fat_channel(__le32 rxon_flags) | 296 | static bool is_fat_channel(__le32 rxon_flags) |
297 | { | 297 | { |
298 | return (rxon_flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) || | 298 | int chan_mod = le32_to_cpu(rxon_flags & RXON_FLG_CHANNEL_MODE_MSK) |
299 | (rxon_flags & RXON_FLG_CHANNEL_MODE_MIXED_MSK); | 299 | >> RXON_FLG_CHANNEL_MODE_POS; |
300 | return ((chan_mod == CHANNEL_MODE_PURE_40) || | ||
301 | (chan_mod == CHANNEL_MODE_MIXED)); | ||
300 | } | 302 | } |
301 | 303 | ||
302 | /* | 304 | /* |
@@ -1490,7 +1492,7 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv) | |||
1490 | struct iwl4965_txpowertable_cmd cmd = { 0 }; | 1492 | struct iwl4965_txpowertable_cmd cmd = { 0 }; |
1491 | int ret; | 1493 | int ret; |
1492 | u8 band = 0; | 1494 | u8 band = 0; |
1493 | u8 is_fat = 0; | 1495 | bool is_fat = false; |
1494 | u8 ctrl_chan_high = 0; | 1496 | u8 ctrl_chan_high = 0; |
1495 | 1497 | ||
1496 | if (test_bit(STATUS_SCANNING, &priv->status)) { | 1498 | if (test_bit(STATUS_SCANNING, &priv->status)) { |
@@ -1568,7 +1570,7 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) | |||
1568 | { | 1570 | { |
1569 | int rc; | 1571 | int rc; |
1570 | u8 band = 0; | 1572 | u8 band = 0; |
1571 | u8 is_fat = 0; | 1573 | bool is_fat = false; |
1572 | u8 ctrl_chan_high = 0; | 1574 | u8 ctrl_chan_high = 0; |
1573 | struct iwl4965_channel_switch_cmd cmd = { 0 }; | 1575 | struct iwl4965_channel_switch_cmd cmd = { 0 }; |
1574 | const struct iwl_channel_info *ch_info; | 1576 | const struct iwl_channel_info *ch_info; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 7b84d5246b36..e581dc323f0a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h | |||
@@ -614,8 +614,18 @@ enum { | |||
614 | 614 | ||
615 | #define RXON_FLG_CHANNEL_MODE_POS (25) | 615 | #define RXON_FLG_CHANNEL_MODE_POS (25) |
616 | #define RXON_FLG_CHANNEL_MODE_MSK cpu_to_le32(0x3 << 25) | 616 | #define RXON_FLG_CHANNEL_MODE_MSK cpu_to_le32(0x3 << 25) |
617 | #define RXON_FLG_CHANNEL_MODE_PURE_40_MSK cpu_to_le32(0x1 << 25) | 617 | |
618 | #define RXON_FLG_CHANNEL_MODE_MIXED_MSK cpu_to_le32(0x2 << 25) | 618 | /* channel mode */ |
619 | enum { | ||
620 | CHANNEL_MODE_LEGACY = 0, | ||
621 | CHANNEL_MODE_PURE_40 = 1, | ||
622 | CHANNEL_MODE_MIXED = 2, | ||
623 | CHANNEL_MODE_RESERVED = 3, | ||
624 | }; | ||
625 | #define RXON_FLG_CHANNEL_MODE_LEGACY cpu_to_le32(CHANNEL_MODE_LEGACY << RXON_FLG_CHANNEL_MODE_POS) | ||
626 | #define RXON_FLG_CHANNEL_MODE_PURE_40 cpu_to_le32(CHANNEL_MODE_PURE_40 << RXON_FLG_CHANNEL_MODE_POS) | ||
627 | #define RXON_FLG_CHANNEL_MODE_MIXED cpu_to_le32(CHANNEL_MODE_MIXED << RXON_FLG_CHANNEL_MODE_POS) | ||
628 | |||
619 | /* CTS to self (if spec allows) flag */ | 629 | /* CTS to self (if spec allows) flag */ |
620 | #define RXON_FLG_SELF_CTS_EN cpu_to_le32(0x1<<30) | 630 | #define RXON_FLG_SELF_CTS_EN cpu_to_le32(0x1<<30) |
621 | 631 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index c7cbb2e80903..a15f7955845b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -617,19 +617,23 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, | |||
617 | struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config; | 617 | struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config; |
618 | 618 | ||
619 | if ((!iwl_ht_conf->is_ht) || | 619 | if ((!iwl_ht_conf->is_ht) || |
620 | (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) || | 620 | (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ)) |
621 | (iwl_ht_conf->extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE)) | ||
622 | return 0; | 621 | return 0; |
623 | 622 | ||
623 | /* We do not check for IEEE80211_HT_CAP_SUP_WIDTH_20_40 | ||
624 | * the bit will not set if it is pure 40MHz case | ||
625 | */ | ||
624 | if (sta_ht_inf) { | 626 | if (sta_ht_inf) { |
625 | if ((!sta_ht_inf->ht_supported) || | 627 | if (!sta_ht_inf->ht_supported) |
626 | (!(sta_ht_inf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))) | ||
627 | return 0; | 628 | return 0; |
628 | } | 629 | } |
629 | 630 | ||
630 | return iwl_is_channel_extension(priv, priv->band, | 631 | if (iwl_ht_conf->ht_protection & IEEE80211_HT_OP_MODE_PROTECTION_20MHZ) |
631 | le16_to_cpu(priv->staging_rxon.channel), | 632 | return 1; |
632 | iwl_ht_conf->extension_chan_offset); | 633 | else |
634 | return iwl_is_channel_extension(priv, priv->band, | ||
635 | le16_to_cpu(priv->staging_rxon.channel), | ||
636 | iwl_ht_conf->extension_chan_offset); | ||
633 | } | 637 | } |
634 | EXPORT_SYMBOL(iwl_is_fat_tx_allowed); | 638 | EXPORT_SYMBOL(iwl_is_fat_tx_allowed); |
635 | 639 | ||
@@ -799,42 +803,51 @@ EXPORT_SYMBOL(iwl_rate_get_lowest_plcp); | |||
799 | void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) | 803 | void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) |
800 | { | 804 | { |
801 | struct iwl_rxon_cmd *rxon = &priv->staging_rxon; | 805 | struct iwl_rxon_cmd *rxon = &priv->staging_rxon; |
802 | u32 val; | ||
803 | 806 | ||
804 | if (!ht_info->is_ht) { | 807 | if (!ht_info->is_ht) { |
805 | rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | | 808 | rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | |
806 | RXON_FLG_CHANNEL_MODE_PURE_40_MSK | | ||
807 | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | | 809 | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK | |
808 | RXON_FLG_FAT_PROT_MSK | | 810 | RXON_FLG_FAT_PROT_MSK | |
809 | RXON_FLG_HT_PROT_MSK); | 811 | RXON_FLG_HT_PROT_MSK); |
810 | return; | 812 | return; |
811 | } | 813 | } |
812 | 814 | ||
813 | /* Set up channel bandwidth: 20 MHz only, or 20/40 mixed if fat ok */ | 815 | /* FIXME: if the definition of ht_protection changed, the "translation" |
814 | if (iwl_is_fat_tx_allowed(priv, NULL)) | 816 | * will be needed for rxon->flags |
815 | rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED_MSK; | 817 | */ |
816 | else | 818 | rxon->flags |= cpu_to_le32(ht_info->ht_protection << RXON_FLG_HT_OPERATING_MODE_POS); |
817 | rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | | 819 | |
818 | RXON_FLG_CHANNEL_MODE_PURE_40_MSK); | 820 | /* Set up channel bandwidth: |
819 | 821 | * 20 MHz only, 20/40 mixed or pure 40 if fat ok */ | |
820 | /* Note: control channel is opposite of extension channel */ | 822 | /* clear the HT channel mode before set the mode */ |
821 | switch (ht_info->extension_chan_offset) { | 823 | rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MSK | |
822 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: | 824 | RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); |
823 | rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); | 825 | if (iwl_is_fat_tx_allowed(priv, NULL)) { |
824 | break; | 826 | /* pure 40 fat */ |
825 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | 827 | if (rxon->flags & RXON_FLG_FAT_PROT_MSK) |
826 | rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; | 828 | rxon->flags |= RXON_FLG_CHANNEL_MODE_PURE_40; |
827 | break; | 829 | else { |
828 | case IEEE80211_HT_PARAM_CHA_SEC_NONE: | 830 | /* Note: control channel is opposite of extension channel */ |
829 | default: | 831 | switch (ht_info->extension_chan_offset) { |
830 | rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK; | 832 | case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: |
831 | break; | 833 | rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); |
834 | rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED; | ||
835 | break; | ||
836 | case IEEE80211_HT_PARAM_CHA_SEC_BELOW: | ||
837 | rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; | ||
838 | rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED; | ||
839 | break; | ||
840 | case IEEE80211_HT_PARAM_CHA_SEC_NONE: | ||
841 | default: | ||
842 | /* channel location only valid if in Mixed mode */ | ||
843 | IWL_ERR(priv, "invalid extension channel offset\n"); | ||
844 | break; | ||
845 | } | ||
846 | } | ||
847 | } else { | ||
848 | rxon->flags |= RXON_FLG_CHANNEL_MODE_LEGACY; | ||
832 | } | 849 | } |
833 | 850 | ||
834 | val = ht_info->ht_protection; | ||
835 | |||
836 | rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS); | ||
837 | |||
838 | if (priv->cfg->ops->hcmd->set_rxon_chain) | 851 | if (priv->cfg->ops->hcmd->set_rxon_chain) |
839 | priv->cfg->ops->hcmd->set_rxon_chain(priv); | 852 | priv->cfg->ops->hcmd->set_rxon_chain(priv); |
840 | 853 | ||
@@ -1122,8 +1135,9 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode) | |||
1122 | priv->staging_rxon.cck_basic_rates = | 1135 | priv->staging_rxon.cck_basic_rates = |
1123 | (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF; | 1136 | (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF; |
1124 | 1137 | ||
1125 | priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | | 1138 | /* clear both MIX and PURE40 mode flag */ |
1126 | RXON_FLG_CHANNEL_MODE_PURE_40_MSK); | 1139 | priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED | |
1140 | RXON_FLG_CHANNEL_MODE_PURE_40); | ||
1127 | memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); | 1141 | memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); |
1128 | memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN); | 1142 | memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN); |
1129 | priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff; | 1143 | priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 065214b55895..f6d4af5c7509 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c | |||
@@ -586,6 +586,7 @@ static void iwl_bg_request_scan(struct work_struct *data) | |||
586 | u8 rx_ant = priv->hw_params.valid_rx_ant; | 586 | u8 rx_ant = priv->hw_params.valid_rx_ant; |
587 | u8 rate; | 587 | u8 rate; |
588 | bool is_active = false; | 588 | bool is_active = false; |
589 | int chan_mod; | ||
589 | 590 | ||
590 | conf = ieee80211_get_hw_conf(priv->hw); | 591 | conf = ieee80211_get_hw_conf(priv->hw); |
591 | 592 | ||
@@ -703,7 +704,9 @@ static void iwl_bg_request_scan(struct work_struct *data) | |||
703 | if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) { | 704 | if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) { |
704 | band = IEEE80211_BAND_2GHZ; | 705 | band = IEEE80211_BAND_2GHZ; |
705 | scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; | 706 | scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; |
706 | if (priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) { | 707 | chan_mod = le32_to_cpu(priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_MSK) |
708 | >> RXON_FLG_CHANNEL_MODE_POS; | ||
709 | if (chan_mod == CHANNEL_MODE_PURE_40) { | ||
707 | rate = IWL_RATE_6M_PLCP; | 710 | rate = IWL_RATE_6M_PLCP; |
708 | } else { | 711 | } else { |
709 | rate = IWL_RATE_1M_PLCP; | 712 | rate = IWL_RATE_1M_PLCP; |