diff options
author | Sujith <Sujith.Manoharan@atheros.com> | 2009-03-02 02:59:45 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-03-05 14:39:39 -0500 |
commit | 9331ec8060da5783307a565792ded33bfb9e54fc (patch) | |
tree | e5de7ce16432d7cf3aa742a34800e611767bc459 /drivers/net/wireless | |
parent | 25c9c8752849212a25bf7f38b40b64b3958d619b (diff) |
ath9k: Fill in rate_update mac80211 callback
This callback can be used to handle dynamic 20/40,
and changes in the operating channel's HT parameters.
Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/ath9k/rc.c | 121 |
1 files changed, 92 insertions, 29 deletions
diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index 18d19c394475..6d7e636054ed 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c | |||
@@ -1387,42 +1387,18 @@ static struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, | |||
1387 | static void ath_rc_init(struct ath_softc *sc, | 1387 | static void ath_rc_init(struct ath_softc *sc, |
1388 | struct ath_rate_priv *ath_rc_priv, | 1388 | struct ath_rate_priv *ath_rc_priv, |
1389 | struct ieee80211_supported_band *sband, | 1389 | struct ieee80211_supported_band *sband, |
1390 | struct ieee80211_sta *sta) | 1390 | struct ieee80211_sta *sta, |
1391 | struct ath_rate_table *rate_table) | ||
1391 | { | 1392 | { |
1392 | struct ath_rate_table *rate_table = NULL; | ||
1393 | struct ath_rateset *rateset = &ath_rc_priv->neg_rates; | 1393 | struct ath_rateset *rateset = &ath_rc_priv->neg_rates; |
1394 | u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates; | 1394 | u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates; |
1395 | u8 i, j, k, hi = 0, hthi = 0; | 1395 | u8 i, j, k, hi = 0, hthi = 0; |
1396 | struct ath_hw *ah = sc->sc_ah; | ||
1397 | |||
1398 | /* FIXME: Adhoc */ | ||
1399 | if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) || | ||
1400 | (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)) { | ||
1401 | bool is_cw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; | ||
1402 | rate_table = ath_choose_rate_table(sc, sband->band, | ||
1403 | sta->ht_cap.ht_supported, | ||
1404 | is_cw_40); | ||
1405 | } else if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { | ||
1406 | /* cur_rate_table would be set on init through config() */ | ||
1407 | rate_table = sc->cur_rate_table; | ||
1408 | } | ||
1409 | 1396 | ||
1410 | if (!rate_table) { | 1397 | if (!rate_table) { |
1411 | DPRINTF(sc, ATH_DBG_FATAL, "Rate table not initialized\n"); | 1398 | DPRINTF(sc, ATH_DBG_FATAL, "Rate table not initialized\n"); |
1412 | return; | 1399 | return; |
1413 | } | 1400 | } |
1414 | 1401 | ||
1415 | if (sta->ht_cap.ht_supported) { | ||
1416 | ath_rc_priv->ht_cap = WLAN_RC_HT_FLAG; | ||
1417 | if (sc->sc_ah->caps.tx_chainmask != 1 && | ||
1418 | ath9k_hw_getcapability(ah, ATH9K_CAP_DS, 0, NULL)) | ||
1419 | ath_rc_priv->ht_cap |= WLAN_RC_DS_FLAG; | ||
1420 | if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) | ||
1421 | ath_rc_priv->ht_cap |= WLAN_RC_40_FLAG; | ||
1422 | if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) | ||
1423 | ath_rc_priv->ht_cap |= WLAN_RC_SGI_FLAG; | ||
1424 | } | ||
1425 | |||
1426 | /* Initial rate table size. Will change depending | 1402 | /* Initial rate table size. Will change depending |
1427 | * on the working rate set */ | 1403 | * on the working rate set */ |
1428 | ath_rc_priv->rate_table_size = RATE_TABLE_SIZE; | 1404 | ath_rc_priv->rate_table_size = RATE_TABLE_SIZE; |
@@ -1442,7 +1418,7 @@ static void ath_rc_init(struct ath_softc *sc, | |||
1442 | ath_rc_priv->valid_phy_rateidx[i][j] = 0; | 1418 | ath_rc_priv->valid_phy_rateidx[i][j] = 0; |
1443 | ath_rc_priv->valid_phy_ratecnt[i] = 0; | 1419 | ath_rc_priv->valid_phy_ratecnt[i] = 0; |
1444 | } | 1420 | } |
1445 | ath_rc_priv->rc_phy_mode = (ath_rc_priv->ht_cap & WLAN_RC_40_FLAG); | 1421 | ath_rc_priv->rc_phy_mode = ath_rc_priv->ht_cap & WLAN_RC_40_FLAG; |
1446 | 1422 | ||
1447 | /* Set stream capability */ | 1423 | /* Set stream capability */ |
1448 | ath_rc_priv->single_stream = (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ? 0 : 1; | 1424 | ath_rc_priv->single_stream = (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ? 0 : 1; |
@@ -1487,9 +1463,34 @@ static void ath_rc_init(struct ath_softc *sc, | |||
1487 | ath_rc_sort_validrates(rate_table, ath_rc_priv); | 1463 | ath_rc_sort_validrates(rate_table, ath_rc_priv); |
1488 | ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4]; | 1464 | ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4]; |
1489 | sc->cur_rate_table = rate_table; | 1465 | sc->cur_rate_table = rate_table; |
1466 | |||
1467 | DPRINTF(sc, ATH_DBG_CONFIG, "RC Initialized with capabilities: 0x%x\n", | ||
1468 | ath_rc_priv->ht_cap); | ||
1490 | } | 1469 | } |
1491 | 1470 | ||
1492 | /* Rate Control callbacks */ | 1471 | static u8 ath_rc_build_ht_caps(struct ath_softc *sc, bool is_ht, bool is_cw40, |
1472 | bool is_sgi40) | ||
1473 | { | ||
1474 | u8 caps = 0; | ||
1475 | |||
1476 | if (is_ht) { | ||
1477 | caps = WLAN_RC_HT_FLAG; | ||
1478 | if (sc->sc_ah->caps.tx_chainmask != 1 && | ||
1479 | ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_DS, 0, NULL)) | ||
1480 | caps |= WLAN_RC_DS_FLAG; | ||
1481 | if (is_cw40) | ||
1482 | caps |= WLAN_RC_40_FLAG; | ||
1483 | if (is_sgi40) | ||
1484 | caps |= WLAN_RC_SGI_FLAG; | ||
1485 | } | ||
1486 | |||
1487 | return caps; | ||
1488 | } | ||
1489 | |||
1490 | /***********************************/ | ||
1491 | /* mac80211 Rate Control callbacks */ | ||
1492 | /***********************************/ | ||
1493 | |||
1493 | static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, | 1494 | static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, |
1494 | struct ieee80211_sta *sta, void *priv_sta, | 1495 | struct ieee80211_sta *sta, void *priv_sta, |
1495 | struct sk_buff *skb) | 1496 | struct sk_buff *skb) |
@@ -1585,6 +1586,8 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, | |||
1585 | { | 1586 | { |
1586 | struct ath_softc *sc = priv; | 1587 | struct ath_softc *sc = priv; |
1587 | struct ath_rate_priv *ath_rc_priv = priv_sta; | 1588 | struct ath_rate_priv *ath_rc_priv = priv_sta; |
1589 | struct ath_rate_table *rate_table = NULL; | ||
1590 | bool is_cw40, is_sgi40; | ||
1588 | int i, j = 0; | 1591 | int i, j = 0; |
1589 | 1592 | ||
1590 | for (i = 0; i < sband->n_bitrates; i++) { | 1593 | for (i = 0; i < sband->n_bitrates; i++) { |
@@ -1606,7 +1609,66 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, | |||
1606 | ath_rc_priv->neg_ht_rates.rs_nrates = j; | 1609 | ath_rc_priv->neg_ht_rates.rs_nrates = j; |
1607 | } | 1610 | } |
1608 | 1611 | ||
1609 | ath_rc_init(sc, priv_sta, sband, sta); | 1612 | is_cw40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; |
1613 | is_sgi40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40; | ||
1614 | |||
1615 | /* Choose rate table first */ | ||
1616 | |||
1617 | if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) || | ||
1618 | (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)) { | ||
1619 | rate_table = ath_choose_rate_table(sc, sband->band, | ||
1620 | sta->ht_cap.ht_supported, | ||
1621 | is_cw40); | ||
1622 | } else if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { | ||
1623 | /* cur_rate_table would be set on init through config() */ | ||
1624 | rate_table = sc->cur_rate_table; | ||
1625 | } | ||
1626 | |||
1627 | ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta->ht_cap.ht_supported, | ||
1628 | is_cw40, is_sgi40); | ||
1629 | ath_rc_init(sc, priv_sta, sband, sta, rate_table); | ||
1630 | } | ||
1631 | |||
1632 | static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband, | ||
1633 | struct ieee80211_sta *sta, void *priv_sta, | ||
1634 | u32 changed) | ||
1635 | { | ||
1636 | struct ath_softc *sc = priv; | ||
1637 | struct ath_rate_priv *ath_rc_priv = priv_sta; | ||
1638 | struct ath_rate_table *rate_table = NULL; | ||
1639 | bool oper_cw40 = false, oper_sgi40; | ||
1640 | bool local_cw40 = (ath_rc_priv->ht_cap & WLAN_RC_40_FLAG) ? | ||
1641 | true : false; | ||
1642 | bool local_sgi40 = (ath_rc_priv->ht_cap & WLAN_RC_SGI_FLAG) ? | ||
1643 | true : false; | ||
1644 | |||
1645 | /* FIXME: Handle AP mode later when we support CWM */ | ||
1646 | |||
1647 | if (changed & IEEE80211_RC_HT_CHANGED) { | ||
1648 | if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION) | ||
1649 | return; | ||
1650 | |||
1651 | if (sc->hw->conf.channel_type == NL80211_CHAN_HT40MINUS || | ||
1652 | sc->hw->conf.channel_type == NL80211_CHAN_HT40PLUS) | ||
1653 | oper_cw40 = true; | ||
1654 | |||
1655 | oper_sgi40 = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ? | ||
1656 | true : false; | ||
1657 | |||
1658 | if ((local_cw40 != oper_cw40) || (local_sgi40 != oper_sgi40)) { | ||
1659 | rate_table = ath_choose_rate_table(sc, sband->band, | ||
1660 | sta->ht_cap.ht_supported, | ||
1661 | oper_cw40); | ||
1662 | ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, | ||
1663 | sta->ht_cap.ht_supported, | ||
1664 | oper_cw40, oper_sgi40); | ||
1665 | ath_rc_init(sc, priv_sta, sband, sta, rate_table); | ||
1666 | |||
1667 | DPRINTF(sc, ATH_DBG_CONFIG, | ||
1668 | "Operating HT Bandwidth changed to: %d\n", | ||
1669 | sc->hw->conf.channel_type); | ||
1670 | } | ||
1671 | } | ||
1610 | } | 1672 | } |
1611 | 1673 | ||
1612 | static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) | 1674 | static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) |
@@ -1650,6 +1712,7 @@ static struct rate_control_ops ath_rate_ops = { | |||
1650 | .tx_status = ath_tx_status, | 1712 | .tx_status = ath_tx_status, |
1651 | .get_rate = ath_get_rate, | 1713 | .get_rate = ath_get_rate, |
1652 | .rate_init = ath_rate_init, | 1714 | .rate_init = ath_rate_init, |
1715 | .rate_update = ath_rate_update, | ||
1653 | .alloc = ath_rate_alloc, | 1716 | .alloc = ath_rate_alloc, |
1654 | .free = ath_rate_free, | 1717 | .free = ath_rate_free, |
1655 | .alloc_sta = ath_rate_alloc_sta, | 1718 | .alloc_sta = ath_rate_alloc_sta, |