aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRon Rindjunsky <ron.rindjunsky@intel.com>2008-05-15 01:53:55 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-05-21 21:47:52 -0400
commitedcdf8b21ac920e06b4180246123fe43b022e020 (patch)
treef24622a574e9f8a2746339ae0460f555a6bdd3b0
parent0b794d63c5db8d010d1584c694eba97f0391fca6 (diff)
mac80211: separate Tx and Rx MCS when configuring HT
This patch follows the 11n spec in separation between Tx and Rx MCS capabilities. Up until now, when configuring the HT possible set of Tx MCS only Rx MCS were considered, assuming they are the same as the Tx MCS. This patch fixed this by looking at low level driver Tx capabilities. Signed-off-by: Ron Rindjunsky <ron.rindjunsky@intel.com> Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl4965-base.c14
-rw-r--r--include/linux/ieee80211.h18
-rw-r--r--net/mac80211/main.c96
3 files changed, 83 insertions, 45 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 1a2d3768867d..c713b27ec653 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -3958,6 +3958,13 @@ static void iwl4965_dealloc_ucode_pci(struct iwl_priv *priv)
3958 iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot); 3958 iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot);
3959} 3959}
3960 3960
3961static void iwl4965_nic_start(struct iwl_priv *priv)
3962{
3963 /* Remove all resets to allow NIC to operate */
3964 iwl_write32(priv, CSR_RESET, 0);
3965}
3966
3967
3961/** 3968/**
3962 * iwl4965_read_ucode - Read uCode images from disk file. 3969 * iwl4965_read_ucode - Read uCode images from disk file.
3963 * 3970 *
@@ -4447,8 +4454,7 @@ static int __iwl4965_up(struct iwl_priv *priv)
4447 } 4454 }
4448 4455
4449 /* start card; "initialize" will load runtime ucode */ 4456 /* start card; "initialize" will load runtime ucode */
4450 /* Remove all resets to allow NIC to operate */ 4457 iwl4965_nic_start(priv);
4451 iwl_write32(priv, CSR_RESET, 0);
4452 4458
4453 IWL_DEBUG_INFO(DRV_NAME " is coming up\n"); 4459 IWL_DEBUG_INFO(DRV_NAME " is coming up\n");
4454 4460
@@ -6842,10 +6848,6 @@ static int __init iwl4965_init(void)
6842 6848
6843 return ret; 6849 return ret;
6844 6850
6845
6846#ifdef CONFIG_IWLWIFI_DEBUG
6847 pci_unregister_driver(&iwl_driver);
6848#endif
6849error_register: 6851error_register:
6850 iwl4965_rate_control_unregister(); 6852 iwl4965_rate_control_unregister();
6851 return ret; 6853 return ret;
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index a9102bc78b61..3c2ac0c37aa8 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -306,8 +306,18 @@ struct ieee80211_ht_addt_info {
306#define IEEE80211_HT_CAP_SGI_40 0x0040 306#define IEEE80211_HT_CAP_SGI_40 0x0040
307#define IEEE80211_HT_CAP_DELAY_BA 0x0400 307#define IEEE80211_HT_CAP_DELAY_BA 0x0400
308#define IEEE80211_HT_CAP_MAX_AMSDU 0x0800 308#define IEEE80211_HT_CAP_MAX_AMSDU 0x0800
309/* 802.11n HT capability AMPDU settings */
309#define IEEE80211_HT_CAP_AMPDU_FACTOR 0x03 310#define IEEE80211_HT_CAP_AMPDU_FACTOR 0x03
310#define IEEE80211_HT_CAP_AMPDU_DENSITY 0x1C 311#define IEEE80211_HT_CAP_AMPDU_DENSITY 0x1C
312/* 802.11n HT capability MSC set */
313#define IEEE80211_SUPP_MCS_SET_UEQM 4
314#define IEEE80211_HT_CAP_MAX_STREAMS 4
315#define IEEE80211_SUPP_MCS_SET_LEN 10
316/* maximum streams the spec allows */
317#define IEEE80211_HT_CAP_MCS_TX_DEFINED 0x01
318#define IEEE80211_HT_CAP_MCS_TX_RX_DIFF 0x02
319#define IEEE80211_HT_CAP_MCS_TX_STREAMS 0x0C
320#define IEEE80211_HT_CAP_MCS_TX_UEQM 0x10
311/* 802.11n HT IE masks */ 321/* 802.11n HT IE masks */
312#define IEEE80211_HT_IE_CHA_SEC_OFFSET 0x03 322#define IEEE80211_HT_IE_CHA_SEC_OFFSET 0x03
313#define IEEE80211_HT_IE_CHA_WIDTH 0x04 323#define IEEE80211_HT_IE_CHA_WIDTH 0x04
@@ -316,10 +326,10 @@ struct ieee80211_ht_addt_info {
316#define IEEE80211_HT_IE_NON_HT_STA_PRSNT 0x0010 326#define IEEE80211_HT_IE_NON_HT_STA_PRSNT 0x0010
317 327
318/* MIMO Power Save Modes */ 328/* MIMO Power Save Modes */
319#define WLAN_HT_CAP_MIMO_PS_STATIC 0 329#define WLAN_HT_CAP_MIMO_PS_STATIC 0
320#define WLAN_HT_CAP_MIMO_PS_DYNAMIC 1 330#define WLAN_HT_CAP_MIMO_PS_DYNAMIC 1
321#define WLAN_HT_CAP_MIMO_PS_INVALID 2 331#define WLAN_HT_CAP_MIMO_PS_INVALID 2
322#define WLAN_HT_CAP_MIMO_PS_DISABLED 3 332#define WLAN_HT_CAP_MIMO_PS_DISABLED 3
323 333
324/* Authentication algorithms */ 334/* Authentication algorithms */
325#define WLAN_AUTH_OPEN 0 335#define WLAN_AUTH_OPEN 0
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 36016363d225..b0fddb7de549 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -35,8 +35,6 @@
35#include "debugfs.h" 35#include "debugfs.h"
36#include "debugfs_netdev.h" 36#include "debugfs_netdev.h"
37 37
38#define SUPP_MCS_SET_LEN 16
39
40/* 38/*
41 * For seeing transmitted packets on monitor interfaces 39 * For seeing transmitted packets on monitor interfaces
42 * we have a radiotap header too. 40 * we have a radiotap header too.
@@ -1068,56 +1066,84 @@ u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht,
1068 struct ieee80211_supported_band *sband; 1066 struct ieee80211_supported_band *sband;
1069 struct ieee80211_ht_info ht_conf; 1067 struct ieee80211_ht_info ht_conf;
1070 struct ieee80211_ht_bss_info ht_bss_conf; 1068 struct ieee80211_ht_bss_info ht_bss_conf;
1071 int i;
1072 u32 changed = 0; 1069 u32 changed = 0;
1070 int i;
1071 u8 max_tx_streams = IEEE80211_HT_CAP_MAX_STREAMS;
1072 u8 tx_mcs_set_cap;
1073 1073
1074 sband = local->hw.wiphy->bands[conf->channel->band]; 1074 sband = local->hw.wiphy->bands[conf->channel->band];
1075 1075
1076 memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info));
1077 memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info));
1078
1076 /* HT is not supported */ 1079 /* HT is not supported */
1077 if (!sband->ht_info.ht_supported) { 1080 if (!sband->ht_info.ht_supported) {
1078 conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; 1081 conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
1079 return 0; 1082 goto out;
1080 } 1083 }
1081 1084
1082 memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info)); 1085 /* disable HT */
1083 memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info)); 1086 if (!enable_ht) {
1084 1087 if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)
1085 if (enable_ht) {
1086 if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE))
1087 changed |= BSS_CHANGED_HT; 1088 changed |= BSS_CHANGED_HT;
1089 conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
1090 conf->ht_conf.ht_supported = 0;
1091 goto out;
1092 }
1088 1093
1089 conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
1090 ht_conf.ht_supported = 1;
1091 1094
1092 ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap; 1095 if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE))
1093 ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS); 1096 changed |= BSS_CHANGED_HT;
1094 ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
1095 1097
1096 for (i = 0; i < SUPP_MCS_SET_LEN; i++) 1098 conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
1097 ht_conf.supp_mcs_set[i] = 1099 ht_conf.ht_supported = 1;
1098 sband->ht_info.supp_mcs_set[i] &
1099 req_ht_cap->supp_mcs_set[i];
1100 1100
1101 ht_bss_conf.primary_channel = req_bss_cap->primary_channel; 1101 ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap;
1102 ht_bss_conf.bss_cap = req_bss_cap->bss_cap; 1102 ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS);
1103 ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode; 1103 ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
1104 ht_bss_conf.primary_channel = req_bss_cap->primary_channel;
1105 ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
1106 ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
1104 1107
1105 ht_conf.ampdu_factor = req_ht_cap->ampdu_factor; 1108 ht_conf.ampdu_factor = req_ht_cap->ampdu_factor;
1106 ht_conf.ampdu_density = req_ht_cap->ampdu_density; 1109 ht_conf.ampdu_density = req_ht_cap->ampdu_density;
1107 1110
1108 /* if bss configuration changed store the new one */ 1111 /* Bits 96-100 */
1109 if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) || 1112 tx_mcs_set_cap = sband->ht_info.supp_mcs_set[12];
1110 memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) {
1111 changed |= BSS_CHANGED_HT;
1112 memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf));
1113 memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf));
1114 }
1115 } else {
1116 if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)
1117 changed |= BSS_CHANGED_HT;
1118 conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
1119 }
1120 1113
1114 /* configure suppoerted Tx MCS according to requested MCS
1115 * (based in most cases on Rx capabilities of peer) and self
1116 * Tx MCS capabilities (as defined by low level driver HW
1117 * Tx capabilities) */
1118 if (!(tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_DEFINED))
1119 goto check_changed;
1120
1121 /* Counting from 0 therfore + 1 */
1122 if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_RX_DIFF)
1123 max_tx_streams = ((tx_mcs_set_cap &
1124 IEEE80211_HT_CAP_MCS_TX_STREAMS) >> 2) + 1;
1125
1126 for (i = 0; i < max_tx_streams; i++)
1127 ht_conf.supp_mcs_set[i] =
1128 sband->ht_info.supp_mcs_set[i] &
1129 req_ht_cap->supp_mcs_set[i];
1130
1131 if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_UEQM)
1132 for (i = IEEE80211_SUPP_MCS_SET_UEQM;
1133 i < IEEE80211_SUPP_MCS_SET_LEN; i++)
1134 ht_conf.supp_mcs_set[i] =
1135 sband->ht_info.supp_mcs_set[i] &
1136 req_ht_cap->supp_mcs_set[i];
1137
1138check_changed:
1139 /* if bss configuration changed store the new one */
1140 if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) ||
1141 memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) {
1142 changed |= BSS_CHANGED_HT;
1143 memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf));
1144 memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf));
1145 }
1146out:
1121 return changed; 1147 return changed;
1122} 1148}
1123 1149