summaryrefslogtreecommitdiffstats
path: root/package/mac80211/patches/340-ath9k_ap_rc.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/mac80211/patches/340-ath9k_ap_rc.patch')
-rw-r--r--package/mac80211/patches/340-ath9k_ap_rc.patch210
1 files changed, 210 insertions, 0 deletions
diff --git a/package/mac80211/patches/340-ath9k_ap_rc.patch b/package/mac80211/patches/340-ath9k_ap_rc.patch
new file mode 100644
index 000000000..d6bc232b7
--- /dev/null
+++ b/package/mac80211/patches/340-ath9k_ap_rc.patch
@@ -0,0 +1,210 @@
+Hostapd now passes the HT parameters through the config()
+callback, use these to set the appropriate channel in AP mode.
+
+Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
+---
+Note: This patch depends on [PATCHv2] nl80211: Add frequency configuration (including HT40)
+posted by Jouni.
+
+ drivers/net/wireless/ath9k/main.c | 60 ++++++++++++++++++++++++++----------
+ drivers/net/wireless/ath9k/rc.c | 55 +++++++++++++++++++++++++++++----
+ 2 files changed, 91 insertions(+), 24 deletions(-)
+
+diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
+index 6e103d5..d1ddb07 100644
+--- a/drivers/net/wireless/ath9k/main.c
++++ b/drivers/net/wireless/ath9k/main.c
+@@ -622,35 +622,35 @@ static int ath_get_channel(struct ath_softc *sc,
+ return -1;
+ }
+
++/* ext_chan_offset: (-1, 0, 1) (below, none, above) */
++
+ static u32 ath_get_extchanmode(struct ath_softc *sc,
+ struct ieee80211_channel *chan,
+- struct ieee80211_bss_conf *bss_conf)
++ int ext_chan_offset,
++ enum ath9k_ht_macmode tx_chan_width)
+ {
+ u32 chanmode = 0;
+- u8 ext_chan_offset = bss_conf->ht.secondary_channel_offset;
+- enum ath9k_ht_macmode tx_chan_width = (bss_conf->ht.width_40_ok) ?
+- ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20;
+
+ switch (chan->band) {
+ case IEEE80211_BAND_2GHZ:
+- if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE) &&
++ if ((ext_chan_offset == 0) &&
+ (tx_chan_width == ATH9K_HT_MACMODE_20))
+ chanmode = CHANNEL_G_HT20;
+- if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) &&
++ if ((ext_chan_offset == 1) &&
+ (tx_chan_width == ATH9K_HT_MACMODE_2040))
+ chanmode = CHANNEL_G_HT40PLUS;
+- if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) &&
++ if ((ext_chan_offset == -1) &&
+ (tx_chan_width == ATH9K_HT_MACMODE_2040))
+ chanmode = CHANNEL_G_HT40MINUS;
+ break;
+ case IEEE80211_BAND_5GHZ:
+- if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE) &&
++ if ((ext_chan_offset == 0) &&
+ (tx_chan_width == ATH9K_HT_MACMODE_20))
+ chanmode = CHANNEL_A_HT20;
+- if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) &&
++ if ((ext_chan_offset == 1) &&
+ (tx_chan_width == ATH9K_HT_MACMODE_2040))
+ chanmode = CHANNEL_A_HT40PLUS;
+- if ((ext_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) &&
++ if ((ext_chan_offset == -1) &&
+ (tx_chan_width == ATH9K_HT_MACMODE_2040))
+ chanmode = CHANNEL_A_HT40MINUS;
+ break;
+@@ -841,6 +841,18 @@ static void ath9k_ht_conf(struct ath_softc *sc,
+ }
+ }
+
++static inline int ath_sec_offset(u8 ext_offset)
++{
++ if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_NONE)
++ return 0;
++ else if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
++ return 1;
++ else if (ext_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW)
++ return -1;
++
++ return 0;
++}
++
+ static void ath9k_bss_assoc_info(struct ath_softc *sc,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf)
+@@ -893,13 +905,14 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
+ }
+
+ if (hw->conf.ht.enabled) {
+- sc->sc_ah->ah_channels[pos].chanmode =
+- ath_get_extchanmode(sc, curchan, bss_conf);
++ int offset =
++ ath_sec_offset(bss_conf->ht.secondary_channel_offset);
++ sc->tx_chan_width = (bss_conf->ht.width_40_ok) ?
++ ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20;
+
+- if (bss_conf->ht.width_40_ok)
+- sc->tx_chan_width = ATH9K_HT_MACMODE_2040;
+- else
+- sc->tx_chan_width = ATH9K_HT_MACMODE_20;
++ sc->sc_ah->ah_channels[pos].chanmode =
++ ath_get_extchanmode(sc, curchan,
++ offset, sc->tx_chan_width);
+ } else {
+ sc->sc_ah->ah_channels[pos].chanmode =
+ (curchan->band == IEEE80211_BAND_2GHZ) ?
+@@ -2172,9 +2185,22 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
+ (curchan->band == IEEE80211_BAND_2GHZ) ?
+ CHANNEL_G : CHANNEL_A;
+
+- if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0)
++ if ((sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) &&
++ (conf->ht.enabled)) {
++ sc->tx_chan_width = (!!conf->ht.sec_chan_offset) ?
++ ATH9K_HT_MACMODE_2040 : ATH9K_HT_MACMODE_20;
++
++ sc->sc_ah->ah_channels[pos].chanmode =
++ ath_get_extchanmode(sc, curchan,
++ conf->ht.sec_chan_offset,
++ sc->tx_chan_width);
++ }
++
++ if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) {
+ DPRINTF(sc, ATH_DBG_FATAL,
+ "%s: Unable to set channel\n", __func__);
++ return -EINVAL;
++ }
+ }
+
+ if (changed & IEEE80211_CONF_CHANGE_HT)
+diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c
+index 93dfea8..7c08583 100644
+--- a/drivers/net/wireless/ath9k/rc.c
++++ b/drivers/net/wireless/ath9k/rc.c
+@@ -1304,6 +1304,38 @@ static void ath_rc_tx_status(struct ath_softc *sc,
+ xretries, long_retry);
+ }
+
++static struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc,
++ enum ieee80211_band band,
++ bool is_ht, bool is_cw_40)
++{
++ int mode = 0;
++
++ switch(band) {
++ case IEEE80211_BAND_2GHZ:
++ mode = ATH9K_MODE_11G;
++ if (is_ht)
++ mode = ATH9K_MODE_11NG_HT20;
++ if (is_cw_40)
++ mode = ATH9K_MODE_11NG_HT40PLUS;
++ break;
++ case IEEE80211_BAND_5GHZ:
++ mode = ATH9K_MODE_11A;
++ if (is_ht)
++ mode = ATH9K_MODE_11NA_HT20;
++ if (is_cw_40)
++ mode = ATH9K_MODE_11NA_HT40PLUS;
++ break;
++ default:
++ DPRINTF(sc, ATH_DBG_RATE, "Invalid band\n");
++ return NULL;
++ }
++
++ BUG_ON(mode >= ATH9K_MODE_MAX);
++
++ DPRINTF(sc, ATH_DBG_RATE, "Choosing rate table for mode: %d\n", mode);
++ return sc->hw_rate_table[mode];
++}
++
+ static void ath_rc_init(struct ath_softc *sc,
+ struct ath_rate_priv *ath_rc_priv,
+ struct ieee80211_supported_band *sband,
+@@ -1314,16 +1346,25 @@ static void ath_rc_init(struct ath_softc *sc,
+ u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates;
+ u8 i, j, k, hi = 0, hthi = 0;
+
+- rate_table = sc->hw_rate_table[sc->sc_curmode];
++ /* FIXME: Adhoc */
++ if ((sc->sc_ah->ah_opmode == ATH9K_M_STA) ||
++ (sc->sc_ah->ah_opmode == ATH9K_M_IBSS)) {
++ bool is_cw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
++ rate_table = ath_choose_rate_table(sc, sband->band,
++ sta->ht_cap.ht_supported,
++ is_cw_40);
++ } else if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) {
++ /* sc_curmode would be set on init through config() */
++ rate_table = sc->hw_rate_table[sc->sc_curmode];
++ }
+
+- if (sta->ht_cap.ht_supported) {
+- if (sband->band == IEEE80211_BAND_2GHZ)
+- rate_table = sc->hw_rate_table[ATH9K_MODE_11NG_HT20];
+- else
+- rate_table = sc->hw_rate_table[ATH9K_MODE_11NA_HT20];
++ if (!rate_table) {
++ DPRINTF(sc, ATH_DBG_FATAL, "Rate table not initialized\n");
++ return;
++ }
+
++ if (sta->ht_cap.ht_supported) {
+ ath_rc_priv->ht_cap = (WLAN_RC_HT_FLAG | WLAN_RC_DS_FLAG);
+-
+ if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
+ ath_rc_priv->ht_cap |= WLAN_RC_40_FLAG;
+ }
+--
+1.6.0.3
+
+--
+To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
+the body of a message to majordomo@vger.kernel.org
+More majordomo info at http://vger.kernel.org/majordomo-info.html
+