diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2008-10-14 10:58:37 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-10-31 19:00:16 -0400 |
commit | ae5eb02641233a4e9d1b92d22090f1b1afa14466 (patch) | |
tree | 117b7cb5efa3ff1cf714218098fc6db3820ed4e0 /drivers | |
parent | bda3933a8aceedd03e0dd410844bd310033ca756 (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.h | 6 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/main.c | 41 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/rc.c | 8 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/recv.c | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath9k/xmit.c | 17 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-rs.c | 23 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 39 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 17 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-dev.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-sta.c | 33 |
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); | |||
380 | int ath_rx_tasklet(struct ath_softc *sc, int flush); | 380 | int ath_rx_tasklet(struct ath_softc *sc, int flush); |
381 | int ath_rx_input(struct ath_softc *sc, | 381 | int 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 | ||
655 | void ath_tx_resume_tid(struct ath_softc *sc, | 657 | void ath_tx_resume_tid(struct ath_softc *sc, |
@@ -919,8 +921,6 @@ enum RATE_TYPE { | |||
919 | 921 | ||
920 | struct ath_ht_info { | 922 | struct 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 | ||
721 | int ath_rx_input(struct ath_softc *sc, | 721 | int 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 | ||
1452 | static u32 ath_lookup_rate(struct ath_softc *sc, | 1453 | static 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 | ||
1520 | static int ath_compute_num_delims(struct ath_softc *sc, | 1522 | static 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) | |||
552 | static void iwl4965_ht_conf(struct iwl_priv *priv, | 552 | static 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 | } |
643 | EXPORT_SYMBOL(iwl_is_fat_tx_allowed); | 643 | EXPORT_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 | } |
705 | EXPORT_SYMBOL(iwl_set_rxon_ht); | 696 | EXPORT_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 | */ |
891 | int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) | 891 | int 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); |