From 0c66d3eef2355c44e7f7e0f2a8dfa2b2b83776c8 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 15 Jan 2010 01:16:48 +0000 Subject: ath9k: fix short slot vs long slot handling, implement support for setting the coverage class SVN-Revision: 19141 --- .../mac80211/patches/540-short_slot_handling.patch | 11 + .../550-ath9k_clean_up_timing_handling.patch | 229 +++++++++++++++++++++ .../patches/560-ath9k_coverage_class.patch | 60 ++++++ 3 files changed, 300 insertions(+) create mode 100644 package/mac80211/patches/540-short_slot_handling.patch create mode 100644 package/mac80211/patches/550-ath9k_clean_up_timing_handling.patch create mode 100644 package/mac80211/patches/560-ath9k_coverage_class.patch (limited to 'package') diff --git a/package/mac80211/patches/540-short_slot_handling.patch b/package/mac80211/patches/540-short_slot_handling.patch new file mode 100644 index 0000000..ed6831f --- /dev/null +++ b/package/mac80211/patches/540-short_slot_handling.patch @@ -0,0 +1,11 @@ +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -670,6 +670,8 @@ static u32 ieee80211_handle_bss_capabili + } + + use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); ++ if (sdata->local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) ++ use_short_slot = true; + + if (use_protection != bss_conf->use_cts_prot) { + bss_conf->use_cts_prot = use_protection; diff --git a/package/mac80211/patches/550-ath9k_clean_up_timing_handling.patch b/package/mac80211/patches/550-ath9k_clean_up_timing_handling.patch new file mode 100644 index 0000000..dc65022 --- /dev/null +++ b/package/mac80211/patches/550-ath9k_clean_up_timing_handling.patch @@ -0,0 +1,229 @@ +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -1790,6 +1790,7 @@ static void ath9k_bss_info_changed(struc + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ath_vif *avp = (void *)vif->drv_priv; ++ int slottime; + int error; + + mutex_lock(&sc->mutex); +@@ -1825,6 +1826,25 @@ static void ath9k_bss_info_changed(struc + ath_beacon_config(sc, vif); + } + ++ if (changed & BSS_CHANGED_ERP_SLOT) { ++ if (bss_conf->use_short_slot) ++ slottime = 9; ++ else ++ slottime = 20; ++ if (vif->type == NL80211_IFTYPE_AP) { ++ /* ++ * Defer update, so that connected stations can adjust ++ * their settings at the same time. ++ * See beacon.c for more details ++ */ ++ sc->beacon.slottime = slottime; ++ sc->beacon.updateslot = UPDATE; ++ } else { ++ ah->slottime = slottime; ++ ath9k_hw_init_global_settings(ah); ++ } ++ } ++ + /* Disable transmission of beacons */ + if ((changed & BSS_CHANGED_BEACON_ENABLED) && !bss_conf->enable_beacon) + ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -55,28 +55,6 @@ module_exit(ath9k_exit); + /* Helper Functions */ + /********************/ + +-static u32 ath9k_hw_mac_usec(struct ath_hw *ah, u32 clks) +-{ +- struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; +- +- if (!ah->curchan) /* should really check for CCK instead */ +- return clks / ATH9K_CLOCK_RATE_CCK; +- if (conf->channel->band == IEEE80211_BAND_2GHZ) +- return clks / ATH9K_CLOCK_RATE_2GHZ_OFDM; +- +- return clks / ATH9K_CLOCK_RATE_5GHZ_OFDM; +-} +- +-static u32 ath9k_hw_mac_to_usec(struct ath_hw *ah, u32 clks) +-{ +- struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; +- +- if (conf_is_ht40(conf)) +- return ath9k_hw_mac_usec(ah, clks) / 2; +- else +- return ath9k_hw_mac_usec(ah, clks); +-} +- + static u32 ath9k_hw_mac_clks(struct ath_hw *ah, u32 usecs) + { + struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; +@@ -413,8 +391,6 @@ static void ath9k_hw_init_defaults(struc + ah->beacon_interval = 100; + ah->enable_32kHz_clock = DONT_USE_32KHZ; + ah->slottime = (u32) -1; +- ah->acktimeout = (u32) -1; +- ah->ctstimeout = (u32) -1; + ah->globaltxtimeout = (u32) -1; + ah->power_mode = ATH9K_PM_UNDEFINED; + } +@@ -1196,34 +1172,25 @@ static void ath9k_hw_init_interrupt_mask + } + } + +-static bool ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us) ++static void ath9k_hw_setslottime(struct ath_hw *ah, u32 us) + { +- if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { +- ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, +- "bad ack timeout %u\n", us); +- ah->acktimeout = (u32) -1; +- return false; +- } else { +- REG_RMW_FIELD(ah, AR_TIME_OUT, +- AR_TIME_OUT_ACK, ath9k_hw_mac_to_clks(ah, us)); +- ah->acktimeout = us; +- return true; +- } ++ u32 val = ath9k_hw_mac_to_clks(ah, us); ++ val = min(val, (u32) 0xFFFF); ++ REG_WRITE(ah, AR_D_GBL_IFS_SLOT, val); + } + +-static bool ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us) ++static void ath9k_hw_set_ack_timeout(struct ath_hw *ah, u32 us) + { +- if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { +- ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, +- "bad cts timeout %u\n", us); +- ah->ctstimeout = (u32) -1; +- return false; +- } else { +- REG_RMW_FIELD(ah, AR_TIME_OUT, +- AR_TIME_OUT_CTS, ath9k_hw_mac_to_clks(ah, us)); +- ah->ctstimeout = us; +- return true; +- } ++ u32 val = ath9k_hw_mac_to_clks(ah, us); ++ val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_ACK)); ++ REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_ACK, val); ++} ++ ++static void ath9k_hw_set_cts_timeout(struct ath_hw *ah, u32 us) ++{ ++ u32 val = ath9k_hw_mac_to_clks(ah, us); ++ val = min(val, (u32) MS(0xFFFFFFFF, AR_TIME_OUT_CTS)); ++ REG_RMW_FIELD(ah, AR_TIME_OUT, AR_TIME_OUT_CTS, val); + } + + static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu) +@@ -1240,23 +1207,32 @@ static bool ath9k_hw_set_global_txtimeou + } + } + +-static void ath9k_hw_init_user_settings(struct ath_hw *ah) ++void ath9k_hw_init_global_settings(struct ath_hw *ah) + { ++ struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; ++ int acktimeout; ++ int sifstime; ++ + ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, "ah->misc_mode 0x%x\n", + ah->misc_mode); + + if (ah->misc_mode != 0) + REG_WRITE(ah, AR_PCU_MISC, + REG_READ(ah, AR_PCU_MISC) | ah->misc_mode); +- if (ah->slottime != (u32) -1) +- ath9k_hw_setslottime(ah, ah->slottime); +- if (ah->acktimeout != (u32) -1) +- ath9k_hw_set_ack_timeout(ah, ah->acktimeout); +- if (ah->ctstimeout != (u32) -1) +- ath9k_hw_set_cts_timeout(ah, ah->ctstimeout); ++ ++ if (conf->channel && conf->channel->band == IEEE80211_BAND_5GHZ) ++ sifstime = 16; ++ else ++ sifstime = 10; ++ ++ acktimeout = ah->slottime + sifstime; ++ ath9k_hw_setslottime(ah, ah->slottime); ++ ath9k_hw_set_ack_timeout(ah, acktimeout); ++ ath9k_hw_set_cts_timeout(ah, acktimeout); + if (ah->globaltxtimeout != (u32) -1) + ath9k_hw_set_global_txtimeout(ah, ah->globaltxtimeout); + } ++EXPORT_SYMBOL(ath9k_hw_init_global_settings); + + void ath9k_hw_deinit(struct ath_hw *ah) + { +@@ -2077,7 +2053,7 @@ int ath9k_hw_reset(struct ath_hw *ah, st + if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + ath9k_enable_rfkill(ah); + +- ath9k_hw_init_user_settings(ah); ++ ath9k_hw_init_global_settings(ah); + + if (AR_SREV_9287_12_OR_LATER(ah)) { + REG_WRITE(ah, AR_D_GBL_IFS_SIFS, +@@ -3674,21 +3650,6 @@ u64 ath9k_hw_extend_tsf(struct ath_hw *a + } + EXPORT_SYMBOL(ath9k_hw_extend_tsf); + +-bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us) +-{ +- if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) { +- ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, +- "bad slot time %u\n", us); +- ah->slottime = (u32) -1; +- return false; +- } else { +- REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath9k_hw_mac_to_clks(ah, us)); +- ah->slottime = us; +- return true; +- } +-} +-EXPORT_SYMBOL(ath9k_hw_setslottime); +- + void ath9k_hw_set11nmac2040(struct ath_hw *ah) + { + struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; +--- a/drivers/net/wireless/ath/ath9k/hw.h ++++ b/drivers/net/wireless/ath/ath9k/hw.h +@@ -553,8 +553,6 @@ struct ath_hw { + int16_t txpower_indexoffset; + u32 beacon_interval; + u32 slottime; +- u32 acktimeout; +- u32 ctstimeout; + u32 globaltxtimeout; + + /* ANI */ +@@ -668,7 +666,7 @@ void ath9k_hw_settsf64(struct ath_hw *ah + void ath9k_hw_reset_tsf(struct ath_hw *ah); + void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting); + u64 ath9k_hw_extend_tsf(struct ath_hw *ah, u32 rstamp); +-bool ath9k_hw_setslottime(struct ath_hw *ah, u32 us); ++void ath9k_hw_init_global_settings(struct ath_hw *ah); + void ath9k_hw_set11nmac2040(struct ath_hw *ah); + void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period); + void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah, +--- a/drivers/net/wireless/ath/ath9k/beacon.c ++++ b/drivers/net/wireless/ath/ath9k/beacon.c +@@ -480,7 +480,8 @@ void ath_beacon_tasklet(unsigned long da + sc->beacon.updateslot = COMMIT; /* commit next beacon */ + sc->beacon.slotupdate = slot; + } else if (sc->beacon.updateslot == COMMIT && sc->beacon.slotupdate == slot) { +- ath9k_hw_setslottime(sc->sc_ah, sc->beacon.slottime); ++ ah->slottime = sc->beacon.slottime; ++ ath9k_hw_init_global_settings(ah); + sc->beacon.updateslot = OK; + } + if (bfaddr != 0) { diff --git a/package/mac80211/patches/560-ath9k_coverage_class.patch b/package/mac80211/patches/560-ath9k_coverage_class.patch new file mode 100644 index 0000000..035eabb --- /dev/null +++ b/package/mac80211/patches/560-ath9k_coverage_class.patch @@ -0,0 +1,60 @@ +--- a/drivers/net/wireless/ath/ath9k/hw.c ++++ b/drivers/net/wireless/ath/ath9k/hw.c +@@ -1211,6 +1211,7 @@ void ath9k_hw_init_global_settings(struc + { + struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; + int acktimeout; ++ int slottime; + int sifstime; + + ath_print(ath9k_hw_common(ah), ATH_DBG_RESET, "ah->misc_mode 0x%x\n", +@@ -1225,8 +1226,10 @@ void ath9k_hw_init_global_settings(struc + else + sifstime = 10; + +- acktimeout = ah->slottime + sifstime; +- ath9k_hw_setslottime(ah, ah->slottime); ++ /* As defined by IEEE 802.11-2007 17.3.8.6 */ ++ slottime = ah->slottime + 3 * ah->coverage_class; ++ acktimeout = slottime + sifstime; ++ ath9k_hw_setslottime(ah, slottime); + ath9k_hw_set_ack_timeout(ah, acktimeout); + ath9k_hw_set_cts_timeout(ah, acktimeout); + if (ah->globaltxtimeout != (u32) -1) +--- a/drivers/net/wireless/ath/ath9k/hw.h ++++ b/drivers/net/wireless/ath/ath9k/hw.h +@@ -551,6 +551,7 @@ struct ath_hw { + u32 *bank6Temp; + + int16_t txpower_indexoffset; ++ int coverage_class; + u32 beacon_interval; + u32 slottime; + u32 globaltxtimeout; +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -2015,6 +2015,18 @@ static void ath9k_sw_scan_complete(struc + mutex_unlock(&sc->mutex); + } + ++static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class) ++{ ++ struct ath_wiphy *aphy = hw->priv; ++ struct ath_softc *sc = aphy->sc; ++ struct ath_hw *ah = sc->sc_ah; ++ ++ mutex_lock(&sc->mutex); ++ ah->coverage_class = coverage_class; ++ ath9k_hw_init_global_settings(ah); ++ mutex_unlock(&sc->mutex); ++} ++ + struct ieee80211_ops ath9k_ops = { + .tx = ath9k_tx, + .start = ath9k_start, +@@ -2034,4 +2046,5 @@ struct ieee80211_ops ath9k_ops = { + .sw_scan_start = ath9k_sw_scan_start, + .sw_scan_complete = ath9k_sw_scan_complete, + .rfkill_poll = ath9k_rfkill_poll_state, ++ .set_coverage_class = ath9k_set_coverage_class, + }; -- cgit v1.1