aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2008-10-14 10:58:37 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-10-31 19:00:16 -0400
commitae5eb02641233a4e9d1b92d22090f1b1afa14466 (patch)
tree117b7cb5efa3ff1cf714218098fc6db3820ed4e0 /drivers
parentbda3933a8aceedd03e0dd410844bd310033ca756 (diff)
mac80211: rewrite HT handling
The HT handling has the following deficiencies, which I've (partially) fixed: * it always uses the AP info even if there is no AP, hence has no chance of working as an AP * it pretends to be HW config, but really is per-BSS * channel sanity checking is left to the drivers * it generally lets the driver control too much HT enabling is still wrong with this patch if you have more than one virtual STA mode interface, but that never happens currently. Once WDS, IBSS or AP/VLAN gets HT capabilities, it will also be wrong, see the comment in ieee80211_enable_ht(). Additionally, this fixes a number of bugs: * mac80211: ieee80211_set_disassoc doesn't notify the driver any more since the refactoring * iwl-agn-rs: always uses the HT capabilities from the wrong stuff mac80211 gives it rather than the actual peer STA * ath9k: a number of bugs resulting from the broken HT API I'm not entirely happy with putting the HT capabilities into struct ieee80211_sta as restricted to our own HT TX capabilities, but I see no cleaner solution for now. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/ath9k/core.h6
-rw-r--r--drivers/net/wireless/ath9k/main.c41
-rw-r--r--drivers/net/wireless/ath9k/rc.c8
-rw-r--r--drivers/net/wireless/ath9k/recv.c3
-rw-r--r--drivers/net/wireless/ath9k/xmit.c17
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c23
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c39
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c17
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c33
10 files changed, 100 insertions, 88 deletions
diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h
index cb3e61e57c4d..59d835b72cd8 100644
--- a/drivers/net/wireless/ath9k/core.h
+++ b/drivers/net/wireless/ath9k/core.h
@@ -380,7 +380,6 @@ void ath_rx_cleanup(struct ath_softc *sc);
380int ath_rx_tasklet(struct ath_softc *sc, int flush); 380int ath_rx_tasklet(struct ath_softc *sc, int flush);
381int ath_rx_input(struct ath_softc *sc, 381int ath_rx_input(struct ath_softc *sc,
382 struct ath_node *node, 382 struct ath_node *node,
383 int is_ampdu,
384 struct sk_buff *skb, 383 struct sk_buff *skb,
385 struct ath_recv_status *rx_status, 384 struct ath_recv_status *rx_status,
386 enum ATH_RX_TYPE *status); 385 enum ATH_RX_TYPE *status);
@@ -650,6 +649,9 @@ struct ath_node {
650 u8 an_smmode; /* SM Power save mode */ 649 u8 an_smmode; /* SM Power save mode */
651 u8 an_flags; 650 u8 an_flags;
652 u8 an_addr[ETH_ALEN]; 651 u8 an_addr[ETH_ALEN];
652
653 u16 maxampdu;
654 u8 mpdudensity;
653}; 655};
654 656
655void ath_tx_resume_tid(struct ath_softc *sc, 657void ath_tx_resume_tid(struct ath_softc *sc,
@@ -919,8 +921,6 @@ enum RATE_TYPE {
919 921
920struct ath_ht_info { 922struct ath_ht_info {
921 enum ath9k_ht_macmode tx_chan_width; 923 enum ath9k_ht_macmode tx_chan_width;
922 u16 maxampdu;
923 u8 mpdudensity;
924 u8 ext_chan_offset; 924 u8 ext_chan_offset;
925}; 925};
926 926
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index 41cd114c438c..7555c3413384 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -330,25 +330,15 @@ static void ath9k_ht_conf(struct ath_softc *sc,
330{ 330{
331 struct ath_ht_info *ht_info = &sc->sc_ht_info; 331 struct ath_ht_info *ht_info = &sc->sc_ht_info;
332 332
333 if (bss_conf->assoc_ht) { 333 if (sc->hw->conf.ht.enabled) {
334 ht_info->ext_chan_offset = 334 ht_info->ext_chan_offset = bss_conf->ht.secondary_channel_offset;
335 bss_conf->ht_bss_conf->bss_cap & 335
336 IEEE80211_HT_PARAM_CHA_SEC_OFFSET; 336 if (bss_conf->ht.width_40_ok)
337
338 if (!(bss_conf->ht_cap->cap &
339 IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
340 (bss_conf->ht_bss_conf->bss_cap &
341 IEEE80211_HT_PARAM_CHAN_WIDTH_ANY))
342 ht_info->tx_chan_width = ATH9K_HT_MACMODE_2040; 337 ht_info->tx_chan_width = ATH9K_HT_MACMODE_2040;
343 else 338 else
344 ht_info->tx_chan_width = ATH9K_HT_MACMODE_20; 339 ht_info->tx_chan_width = ATH9K_HT_MACMODE_20;
345 340
346 ath9k_hw_set11nmac2040(sc->sc_ah, ht_info->tx_chan_width); 341 ath9k_hw_set11nmac2040(sc->sc_ah, ht_info->tx_chan_width);
347 ht_info->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
348 bss_conf->ht_cap->ampdu_factor);
349 ht_info->mpdudensity =
350 parse_mpdudensity(bss_conf->ht_cap->ampdu_density);
351
352 } 342 }
353} 343}
354 344
@@ -390,7 +380,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
390 sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; 380 sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER;
391 381
392 /* Update chainmask */ 382 /* Update chainmask */
393 ath_update_chainmask(sc, bss_conf->assoc_ht); 383 ath_update_chainmask(sc, hw->conf.ht.enabled);
394 384
395 DPRINTF(sc, ATH_DBG_CONFIG, 385 DPRINTF(sc, ATH_DBG_CONFIG,
396 "%s: bssid %pM aid 0x%x\n", 386 "%s: bssid %pM aid 0x%x\n",
@@ -408,7 +398,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
408 return; 398 return;
409 } 399 }
410 400
411 if (hw->conf.ht_cap.ht_supported) 401 if (hw->conf.ht.enabled)
412 sc->sc_ah->ah_channels[pos].chanmode = 402 sc->sc_ah->ah_channels[pos].chanmode =
413 ath_get_extchanmode(sc, curchan); 403 ath_get_extchanmode(sc, curchan);
414 else 404 else
@@ -531,7 +521,6 @@ int _ath_rx_indicate(struct ath_softc *sc,
531 521
532 if (an) { 522 if (an) {
533 ath_rx_input(sc, an, 523 ath_rx_input(sc, an,
534 hw->conf.ht_cap.ht_supported,
535 skb, status, &st); 524 skb, status, &st);
536 } 525 }
537 if (!an || (st != ATH_RX_CONSUMED)) 526 if (!an || (st != ATH_RX_CONSUMED))
@@ -1241,6 +1230,9 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
1241 __func__, 1230 __func__,
1242 curchan->center_freq); 1231 curchan->center_freq);
1243 1232
1233 /* Update chainmask */
1234 ath_update_chainmask(sc, conf->ht.enabled);
1235
1244 pos = ath_get_channel(sc, curchan); 1236 pos = ath_get_channel(sc, curchan);
1245 if (pos == -1) { 1237 if (pos == -1) {
1246 DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__); 1238 DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__);
@@ -1251,7 +1243,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
1251 (curchan->band == IEEE80211_BAND_2GHZ) ? 1243 (curchan->band == IEEE80211_BAND_2GHZ) ?
1252 CHANNEL_G : CHANNEL_A; 1244 CHANNEL_G : CHANNEL_A;
1253 1245
1254 if (sc->sc_curaid && hw->conf.ht_cap.ht_supported) 1246 if (sc->sc_curaid && hw->conf.ht.enabled)
1255 sc->sc_ah->ah_channels[pos].chanmode = 1247 sc->sc_ah->ah_channels[pos].chanmode =
1256 ath_get_extchanmode(sc, curchan); 1248 ath_get_extchanmode(sc, curchan);
1257 1249
@@ -1434,6 +1426,14 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw,
1434 } else { 1426 } else {
1435 ath_node_get(sc, sta->addr); 1427 ath_node_get(sc, sta->addr);
1436 } 1428 }
1429
1430 /* XXX: Is this right? Can the capabilities change? */
1431 an = ath_node_find(sc, sta->addr);
1432 an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
1433 sta->ht_cap.ampdu_factor);
1434 an->mpdudensity =
1435 parse_mpdudensity(sta->ht_cap.ampdu_density);
1436
1437 spin_unlock_irqrestore(&sc->node_lock, flags); 1437 spin_unlock_irqrestore(&sc->node_lock, flags);
1438 break; 1438 break;
1439 case STA_NOTIFY_REMOVE: 1439 case STA_NOTIFY_REMOVE:
@@ -1552,9 +1552,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
1552 } 1552 }
1553 1553
1554 if (changed & BSS_CHANGED_HT) { 1554 if (changed & BSS_CHANGED_HT) {
1555 DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed HT %d\n", 1555 DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed HT\n",
1556 __func__, 1556 __func__);
1557 bss_conf->assoc_ht);
1558 ath9k_ht_conf(sc, bss_conf); 1557 ath9k_ht_conf(sc, bss_conf);
1559 } 1558 }
1560 1559
diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c
index ee2dbce42b4d..9b2526030965 100644
--- a/drivers/net/wireless/ath9k/rc.c
+++ b/drivers/net/wireless/ath9k/rc.c
@@ -1838,7 +1838,7 @@ void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv)
1838 struct ath_softc *sc = hw->priv; 1838 struct ath_softc *sc = hw->priv;
1839 u32 capflag = 0; 1839 u32 capflag = 0;
1840 1840
1841 if (hw->conf.ht_cap.ht_supported) { 1841 if (hw->conf.ht.enabled) {
1842 capflag |= ATH_RC_HT_FLAG | ATH_RC_DS_FLAG; 1842 capflag |= ATH_RC_HT_FLAG | ATH_RC_DS_FLAG;
1843 if (sc->sc_ht_info.tx_chan_width == ATH9K_HT_MACMODE_2040) 1843 if (sc->sc_ht_info.tx_chan_width == ATH9K_HT_MACMODE_2040)
1844 capflag |= ATH_RC_CW40_FLAG; 1844 capflag |= ATH_RC_CW40_FLAG;
@@ -1979,7 +1979,7 @@ static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband,
1979 1979
1980 /* Check if aggregation has to be enabled for this tid */ 1980 /* Check if aggregation has to be enabled for this tid */
1981 1981
1982 if (hw->conf.ht_cap.ht_supported) { 1982 if (hw->conf.ht.enabled) {
1983 if (ieee80211_is_data_qos(fc)) { 1983 if (ieee80211_is_data_qos(fc)) {
1984 qc = ieee80211_get_qos_ctl(hdr); 1984 qc = ieee80211_get_qos_ctl(hdr);
1985 tid = qc[0] & 0xf; 1985 tid = qc[0] & 0xf;
@@ -2026,9 +2026,9 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
2026 DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); 2026 DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__);
2027 2027
2028 ath_setup_rates(sc, sband, sta, ath_rc_priv); 2028 ath_setup_rates(sc, sband, sta, ath_rc_priv);
2029 if (sc->hw->conf.flags & IEEE80211_CONF_SUPPORT_HT_MODE) { 2029 if (sc->hw->conf.ht.enabled) {
2030 for (i = 0; i < 77; i++) { 2030 for (i = 0; i < 77; i++) {
2031 if (sc->hw->conf.ht_cap.mcs.rx_mask[i/8] & (1<<(i%8))) 2031 if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8)))
2032 ath_rc_priv->neg_ht_rates.rs_rates[j++] = i; 2032 ath_rc_priv->neg_ht_rates.rs_rates[j++] = i;
2033 if (j == ATH_RATE_MAX) 2033 if (j == ATH_RATE_MAX)
2034 break; 2034 break;
diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c
index 010fcdfec3f6..828322840a86 100644
--- a/drivers/net/wireless/ath9k/recv.c
+++ b/drivers/net/wireless/ath9k/recv.c
@@ -720,12 +720,11 @@ void ath_flushrecv(struct ath_softc *sc)
720 720
721int ath_rx_input(struct ath_softc *sc, 721int ath_rx_input(struct ath_softc *sc,
722 struct ath_node *an, 722 struct ath_node *an,
723 int is_ampdu,
724 struct sk_buff *skb, 723 struct sk_buff *skb,
725 struct ath_recv_status *rx_status, 724 struct ath_recv_status *rx_status,
726 enum ATH_RX_TYPE *status) 725 enum ATH_RX_TYPE *status)
727{ 726{
728 if (is_ampdu && (sc->sc_flags & SC_OP_RXAGGR)) { 727 if (sc->sc_flags & SC_OP_RXAGGR) {
729 *status = ATH_RX_CONSUMED; 728 *status = ATH_RX_CONSUMED;
730 return ath_ampdu_input(sc, an, skb, rx_status); 729 return ath_ampdu_input(sc, an, skb, rx_status);
731 } else { 730 } else {
diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c
index 3770fbe84fce..ba818cc2fb5c 100644
--- a/drivers/net/wireless/ath9k/xmit.c
+++ b/drivers/net/wireless/ath9k/xmit.c
@@ -300,7 +300,8 @@ static int ath_tx_prepare(struct ath_softc *sc,
300 if (ieee80211_is_data(fc) && !txctl->use_minrate) { 300 if (ieee80211_is_data(fc) && !txctl->use_minrate) {
301 301
302 /* Enable HT only for DATA frames and not for EAPOL */ 302 /* Enable HT only for DATA frames and not for EAPOL */
303 txctl->ht = (hw->conf.ht_cap.ht_supported && 303 /* XXX why AMPDU only?? */
304 txctl->ht = (hw->conf.ht.enabled &&
304 (tx_info->flags & IEEE80211_TX_CTL_AMPDU)); 305 (tx_info->flags & IEEE80211_TX_CTL_AMPDU));
305 306
306 if (is_multicast_ether_addr(hdr->addr1)) { 307 if (is_multicast_ether_addr(hdr->addr1)) {
@@ -1450,7 +1451,8 @@ static int ath_tx_send_ampdu(struct ath_softc *sc,
1450 */ 1451 */
1451 1452
1452static u32 ath_lookup_rate(struct ath_softc *sc, 1453static u32 ath_lookup_rate(struct ath_softc *sc,
1453 struct ath_buf *bf) 1454 struct ath_buf *bf,
1455 struct ath_atx_tid *tid)
1454{ 1456{
1455 const struct ath9k_rate_table *rt = sc->sc_currates; 1457 const struct ath9k_rate_table *rt = sc->sc_currates;
1456 struct sk_buff *skb; 1458 struct sk_buff *skb;
@@ -1504,7 +1506,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc,
1504 * The IE, however can hold upto 65536, which shows up here 1506 * The IE, however can hold upto 65536, which shows up here
1505 * as zero. Ignore 65536 since we are constrained by hw. 1507 * as zero. Ignore 65536 since we are constrained by hw.
1506 */ 1508 */
1507 maxampdu = sc->sc_ht_info.maxampdu; 1509 maxampdu = tid->an->maxampdu;
1508 if (maxampdu) 1510 if (maxampdu)
1509 aggr_limit = min(aggr_limit, maxampdu); 1511 aggr_limit = min(aggr_limit, maxampdu);
1510 1512
@@ -1518,6 +1520,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc,
1518 */ 1520 */
1519 1521
1520static int ath_compute_num_delims(struct ath_softc *sc, 1522static int ath_compute_num_delims(struct ath_softc *sc,
1523 struct ath_atx_tid *tid,
1521 struct ath_buf *bf, 1524 struct ath_buf *bf,
1522 u16 frmlen) 1525 u16 frmlen)
1523{ 1526{
@@ -1545,7 +1548,7 @@ static int ath_compute_num_delims(struct ath_softc *sc,
1545 * required minimum length for subframe. Take into account 1548 * required minimum length for subframe. Take into account
1546 * whether high rate is 20 or 40Mhz and half or full GI. 1549 * whether high rate is 20 or 40Mhz and half or full GI.
1547 */ 1550 */
1548 mpdudensity = sc->sc_ht_info.mpdudensity; 1551 mpdudensity = tid->an->mpdudensity;
1549 1552
1550 /* 1553 /*
1551 * If there is no mpdu density restriction, no further calculation 1554 * If there is no mpdu density restriction, no further calculation
@@ -1619,7 +1622,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
1619 } 1622 }
1620 1623
1621 if (!rl) { 1624 if (!rl) {
1622 aggr_limit = ath_lookup_rate(sc, bf); 1625 aggr_limit = ath_lookup_rate(sc, bf, tid);
1623 rl = 1; 1626 rl = 1;
1624 /* 1627 /*
1625 * Is rate dual stream 1628 * Is rate dual stream
@@ -1657,7 +1660,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
1657 * Get the delimiters needed to meet the MPDU 1660 * Get the delimiters needed to meet the MPDU
1658 * density for this node. 1661 * density for this node.
1659 */ 1662 */
1660 ndelim = ath_compute_num_delims(sc, bf_first, bf->bf_frmlen); 1663 ndelim = ath_compute_num_delims(sc, tid, bf_first, bf->bf_frmlen);
1661 1664
1662 bpad = PADBYTES(al_delta) + (ndelim << 2); 1665 bpad = PADBYTES(al_delta) + (ndelim << 2);
1663 1666
@@ -2629,7 +2632,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
2629 struct ath_atx_ac *ac; 2632 struct ath_atx_ac *ac;
2630 int tidno, acno; 2633 int tidno, acno;
2631 2634
2632 sc->sc_ht_info.maxampdu = ATH_AMPDU_LIMIT_DEFAULT; 2635 an->maxampdu = ATH_AMPDU_LIMIT_DEFAULT;
2633 2636
2634 /* 2637 /*
2635 * Init per tid tx state 2638 * Init per tid tx state
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index cd1bff590491..e10e0ca09ce9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -1133,8 +1133,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
1133 s32 rate; 1133 s32 rate;
1134 s8 is_green = lq_sta->is_green; 1134 s8 is_green = lq_sta->is_green;
1135 1135
1136 if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || 1136 if (!conf->ht.enabled || !sta->ht_cap.ht_supported)
1137 !sta->ht_cap.ht_supported)
1138 return -1; 1137 return -1;
1139 1138
1140 if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) 1139 if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2)
@@ -1201,8 +1200,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
1201 u8 is_green = lq_sta->is_green; 1200 u8 is_green = lq_sta->is_green;
1202 s32 rate; 1201 s32 rate;
1203 1202
1204 if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || 1203 if (!conf->ht.enabled || !sta->ht_cap.ht_supported)
1205 !sta->ht_cap.ht_supported)
1206 return -1; 1204 return -1;
1207 1205
1208 IWL_DEBUG_RATE("LQ: try to switch to SISO\n"); 1206 IWL_DEBUG_RATE("LQ: try to switch to SISO\n");
@@ -2001,9 +1999,8 @@ lq_update:
2001 * stay with best antenna legacy modulation for a while 1999 * stay with best antenna legacy modulation for a while
2002 * before next round of mode comparisons. */ 2000 * before next round of mode comparisons. */
2003 tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]); 2001 tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]);
2004 if (is_legacy(tbl1->lq_type) && 2002 if (is_legacy(tbl1->lq_type) && !conf->ht.enabled &&
2005 (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) && 2003 lq_sta->action_counter >= 1) {
2006 (lq_sta->action_counter >= 1)) {
2007 lq_sta->action_counter = 0; 2004 lq_sta->action_counter = 0;
2008 IWL_DEBUG_RATE("LQ: STAY in legacy table\n"); 2005 IWL_DEBUG_RATE("LQ: STAY in legacy table\n");
2009 rs_set_stay_in_table(priv, 1, lq_sta); 2006 rs_set_stay_in_table(priv, 1, lq_sta);
@@ -2238,19 +2235,19 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
2238 * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3), 2235 * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3),
2239 * supp_rates[] does not; shift to convert format, force 9 MBits off. 2236 * supp_rates[] does not; shift to convert format, force 9 MBits off.
2240 */ 2237 */
2241 lq_sta->active_siso_rate = conf->ht_cap.mcs.rx_mask[0] << 1; 2238 lq_sta->active_siso_rate = sta->ht_cap.mcs.rx_mask[0] << 1;
2242 lq_sta->active_siso_rate |= conf->ht_cap.mcs.rx_mask[0] & 0x1; 2239 lq_sta->active_siso_rate |= sta->ht_cap.mcs.rx_mask[0] & 0x1;
2243 lq_sta->active_siso_rate &= ~((u16)0x2); 2240 lq_sta->active_siso_rate &= ~((u16)0x2);
2244 lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE; 2241 lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE;
2245 2242
2246 /* Same here */ 2243 /* Same here */
2247 lq_sta->active_mimo2_rate = conf->ht_cap.mcs.rx_mask[1] << 1; 2244 lq_sta->active_mimo2_rate = sta->ht_cap.mcs.rx_mask[1] << 1;
2248 lq_sta->active_mimo2_rate |= conf->ht_cap.mcs.rx_mask[1] & 0x1; 2245 lq_sta->active_mimo2_rate |= sta->ht_cap.mcs.rx_mask[1] & 0x1;
2249 lq_sta->active_mimo2_rate &= ~((u16)0x2); 2246 lq_sta->active_mimo2_rate &= ~((u16)0x2);
2250 lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; 2247 lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE;
2251 2248
2252 lq_sta->active_mimo3_rate = conf->ht_cap.mcs.rx_mask[2] << 1; 2249 lq_sta->active_mimo3_rate = sta->ht_cap.mcs.rx_mask[2] << 1;
2253 lq_sta->active_mimo3_rate |= conf->ht_cap.mcs.rx_mask[2] & 0x1; 2250 lq_sta->active_mimo3_rate |= sta->ht_cap.mcs.rx_mask[2] & 0x1;
2254 lq_sta->active_mimo3_rate &= ~((u16)0x2); 2251 lq_sta->active_mimo3_rate &= ~((u16)0x2);
2255 lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE; 2252 lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE;
2256 2253
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 79a24410dd0a..7c3eb3d8f7e7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -552,17 +552,30 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv)
552static void iwl4965_ht_conf(struct iwl_priv *priv, 552static void iwl4965_ht_conf(struct iwl_priv *priv,
553 struct ieee80211_bss_conf *bss_conf) 553 struct ieee80211_bss_conf *bss_conf)
554{ 554{
555 struct ieee80211_sta_ht_cap *ht_conf = bss_conf->ht_cap; 555 struct ieee80211_sta_ht_cap *ht_conf;
556 struct ieee80211_ht_bss_info *ht_bss_conf = bss_conf->ht_bss_conf;
557 struct iwl_ht_info *iwl_conf = &priv->current_ht_config; 556 struct iwl_ht_info *iwl_conf = &priv->current_ht_config;
557 struct ieee80211_sta *sta;
558 558
559 IWL_DEBUG_MAC80211("enter: \n"); 559 IWL_DEBUG_MAC80211("enter: \n");
560 560
561 iwl_conf->is_ht = bss_conf->assoc_ht;
562
563 if (!iwl_conf->is_ht) 561 if (!iwl_conf->is_ht)
564 return; 562 return;
565 563
564
565 /*
566 * It is totally wrong to base global information on something
567 * that is valid only when associated, alas, this driver works
568 * that way and I don't know how to fix it.
569 */
570
571 rcu_read_lock();
572 sta = ieee80211_find_sta(priv->hw, priv->bssid);
573 if (!sta) {
574 rcu_read_unlock();
575 return;
576 }
577 ht_conf = &sta->ht_cap;
578
566 if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20) 579 if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20)
567 iwl_conf->sgf |= HT_SHORT_GI_20MHZ; 580 iwl_conf->sgf |= HT_SHORT_GI_20MHZ;
568 if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40) 581 if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40)
@@ -574,8 +587,8 @@ static void iwl4965_ht_conf(struct iwl_priv *priv,
574 587
575 iwl_conf->supported_chan_width = 588 iwl_conf->supported_chan_width =
576 !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40); 589 !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40);
577 iwl_conf->extension_chan_offset = 590
578 ht_bss_conf->bss_cap & IEEE80211_HT_PARAM_CHA_SEC_OFFSET; 591 iwl_conf->extension_chan_offset = bss_conf->ht.secondary_channel_offset;
579 /* If no above or below channel supplied disable FAT channel */ 592 /* If no above or below channel supplied disable FAT channel */
580 if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE && 593 if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE &&
581 iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) { 594 iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) {
@@ -587,15 +600,14 @@ static void iwl4965_ht_conf(struct iwl_priv *priv,
587 600
588 memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16); 601 memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16);
589 602
590 iwl_conf->control_channel = ht_bss_conf->primary_channel; 603 iwl_conf->tx_chan_width = bss_conf->ht.width_40_ok;
591 iwl_conf->tx_chan_width =
592 !!(ht_bss_conf->bss_cap & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY);
593 iwl_conf->ht_protection = 604 iwl_conf->ht_protection =
594 ht_bss_conf->bss_op_mode & IEEE80211_HT_OP_MODE_PROTECTION; 605 bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
595 iwl_conf->non_GF_STA_present = 606 iwl_conf->non_GF_STA_present =
596 !!(ht_bss_conf->bss_op_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); 607 !!(bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
608
609 rcu_read_unlock();
597 610
598 IWL_DEBUG_MAC80211("control channel %d\n", iwl_conf->control_channel);
599 IWL_DEBUG_MAC80211("leave\n"); 611 IWL_DEBUG_MAC80211("leave\n");
600} 612}
601 613
@@ -2746,6 +2758,8 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, u32 changed)
2746 mutex_lock(&priv->mutex); 2758 mutex_lock(&priv->mutex);
2747 IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value); 2759 IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value);
2748 2760
2761 priv->current_ht_config.is_ht = conf->ht.enabled;
2762
2749 if (conf->radio_enabled && iwl_radio_kill_sw_enable_radio(priv)) { 2763 if (conf->radio_enabled && iwl_radio_kill_sw_enable_radio(priv)) {
2750 IWL_DEBUG_MAC80211("leave - RF-KILL - waiting for uCode\n"); 2764 IWL_DEBUG_MAC80211("leave - RF-KILL - waiting for uCode\n");
2751 goto out; 2765 goto out;
@@ -3104,7 +3118,6 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
3104 } 3118 }
3105 3119
3106 if (changes & BSS_CHANGED_HT) { 3120 if (changes & BSS_CHANGED_HT) {
3107 IWL_DEBUG_MAC80211("HT %d\n", bss_conf->assoc_ht);
3108 iwl4965_ht_conf(priv, bss_conf); 3121 iwl4965_ht_conf(priv, bss_conf);
3109 iwl_set_rxon_chain(priv); 3122 iwl_set_rxon_chain(priv);
3110 } 3123 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 4678da447ff6..10f5a0a233fe 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -637,8 +637,8 @@ u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
637 } 637 }
638 638
639 return iwl_is_channel_extension(priv, priv->band, 639 return iwl_is_channel_extension(priv, priv->band,
640 iwl_ht_conf->control_channel, 640 le16_to_cpu(priv->staging_rxon.channel),
641 iwl_ht_conf->extension_chan_offset); 641 iwl_ht_conf->extension_chan_offset);
642} 642}
643EXPORT_SYMBOL(iwl_is_fat_tx_allowed); 643EXPORT_SYMBOL(iwl_is_fat_tx_allowed);
644 644
@@ -663,13 +663,6 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
663 rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | 663 rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
664 RXON_FLG_CHANNEL_MODE_PURE_40_MSK); 664 RXON_FLG_CHANNEL_MODE_PURE_40_MSK);
665 665
666 if (le16_to_cpu(rxon->channel) != ht_info->control_channel) {
667 IWL_DEBUG_ASSOC("control diff than current %d %d\n",
668 le16_to_cpu(rxon->channel),
669 ht_info->control_channel);
670 return;
671 }
672
673 /* Note: control channel is opposite of extension channel */ 666 /* Note: control channel is opposite of extension channel */
674 switch (ht_info->extension_chan_offset) { 667 switch (ht_info->extension_chan_offset) {
675 case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: 668 case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
@@ -692,14 +685,12 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info)
692 685
693 IWL_DEBUG_ASSOC("supported HT rate 0x%X 0x%X 0x%X " 686 IWL_DEBUG_ASSOC("supported HT rate 0x%X 0x%X 0x%X "
694 "rxon flags 0x%X operation mode :0x%X " 687 "rxon flags 0x%X operation mode :0x%X "
695 "extension channel offset 0x%x " 688 "extension channel offset 0x%x\n",
696 "control chan %d\n",
697 ht_info->mcs.rx_mask[0], 689 ht_info->mcs.rx_mask[0],
698 ht_info->mcs.rx_mask[1], 690 ht_info->mcs.rx_mask[1],
699 ht_info->mcs.rx_mask[2], 691 ht_info->mcs.rx_mask[2],
700 le32_to_cpu(rxon->flags), ht_info->ht_protection, 692 le32_to_cpu(rxon->flags), ht_info->ht_protection,
701 ht_info->extension_chan_offset, 693 ht_info->extension_chan_offset);
702 ht_info->control_channel);
703 return; 694 return;
704} 695}
705EXPORT_SYMBOL(iwl_set_rxon_ht); 696EXPORT_SYMBOL(iwl_set_rxon_ht);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 572250ee9d58..2e9514933970 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -413,7 +413,6 @@ struct iwl_ht_info {
413 u8 mpdu_density; 413 u8 mpdu_density;
414 struct ieee80211_mcs_info mcs; 414 struct ieee80211_mcs_info mcs;
415 /* BSS related data */ 415 /* BSS related data */
416 u8 control_channel;
417 u8 extension_chan_offset; 416 u8 extension_chan_offset;
418 u8 tx_chan_width; 417 u8 tx_chan_width;
419 u8 ht_protection; 418 u8 ht_protection;
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index b9b8554433a6..218483d096cc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -890,20 +890,31 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap)
890 */ 890 */
891int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) 891int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
892{ 892{
893 struct ieee80211_sta *sta;
894 struct ieee80211_sta_ht_cap ht_config;
895 struct ieee80211_sta_ht_cap *cur_ht_config = NULL;
893 u8 sta_id; 896 u8 sta_id;
894 897
895 /* Add station to device's station table */ 898 /* Add station to device's station table */
896 struct ieee80211_conf *conf = &priv->hw->conf; 899
897 struct ieee80211_sta_ht_cap *cur_ht_config = &conf->ht_cap; 900 /*
898 901 * XXX: This check is definitely not correct, if we're an AP
899 if ((is_ap) && 902 * it'll always be false which is not what we want, but
900 (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && 903 * it doesn't look like iwlagn is prepared to be an HT
901 (priv->iw_mode == NL80211_IFTYPE_STATION)) 904 * AP anyway.
902 sta_id = iwl_add_station_flags(priv, addr, is_ap, 905 */
903 0, cur_ht_config); 906 if (priv->current_ht_config.is_ht) {
904 else 907 rcu_read_lock();
905 sta_id = iwl_add_station_flags(priv, addr, is_ap, 908 sta = ieee80211_find_sta(priv->hw, addr);
906 0, NULL); 909 if (sta) {
910 memcpy(&ht_config, &sta->ht_cap, sizeof(ht_config));
911 cur_ht_config = &ht_config;
912 }
913 rcu_read_unlock();
914 }
915
916 sta_id = iwl_add_station_flags(priv, addr, is_ap,
917 0, cur_ht_config);
907 918
908 /* Set up default rate scaling table in device's station table */ 919 /* Set up default rate scaling table in device's station table */
909 iwl_sta_init_lq(priv, addr, is_ap); 920 iwl_sta_init_lq(priv, addr, is_ap);