ath9k: fix short slot vs long slot handling, implement support for setting the covera...
authorFelix Fietkau <nbd@openwrt.org>
Fri, 15 Jan 2010 01:16:48 +0000 (01:16 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Fri, 15 Jan 2010 01:16:48 +0000 (01:16 +0000)
SVN-Revision: 19141

package/mac80211/patches/540-short_slot_handling.patch [new file with mode: 0644]
package/mac80211/patches/550-ath9k_clean_up_timing_handling.patch [new file with mode: 0644]
package/mac80211/patches/560-ath9k_coverage_class.patch [new file with mode: 0644]

diff --git a/package/mac80211/patches/540-short_slot_handling.patch b/package/mac80211/patches/540-short_slot_handling.patch
new file mode 100644 (file)
index 0000000..ed6831f
--- /dev/null
@@ -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 (file)
index 0000000..dc65022
--- /dev/null
@@ -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 (file)
index 0000000..035eabb
--- /dev/null
@@ -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,
+ };