aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi
diff options
context:
space:
mode:
authorWey-Yi Guy <wey-yi.w.guy@intel.com>2009-05-22 14:01:49 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-05-22 14:06:05 -0400
commita2b0f02e4795bfde5f11720a10af8923cb98b654 (patch)
tree1d2cad3ff20f43ba51aace00a8c2c627fe013581 /drivers/net/wireless/iwlwifi
parenta9c146b369cd8facbbbec7d8b31440f6eaa43e03 (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/iwlwifi')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h14
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c84
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c5
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
296static int is_fat_channel(__le32 rxon_flags) 296static 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 */
619enum {
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}
634EXPORT_SYMBOL(iwl_is_fat_tx_allowed); 638EXPORT_SYMBOL(iwl_is_fat_tx_allowed);
635 639
@@ -799,42 +803,51 @@ EXPORT_SYMBOL(iwl_rate_get_lowest_plcp);
799void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) 803void 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;