--- /dev/null
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -100,6 +100,13 @@ static void ath9k_hw_set_clockrate(struc
+ if (conf_is_ht40(conf))
+ clockrate *= 2;
+
++ if (ah->curchan) {
++ if (IS_CHAN_HALF_RATE(ah->curchan))
++ clockrate /= 2;
++ if (IS_CHAN_QUARTER_RATE(ah->curchan))
++ clockrate /= 4;
++ }
++
+ common->clockrate = clockrate;
+ }
+
--- /dev/null
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -88,7 +88,10 @@ static void ath9k_hw_set_clockrate(struc
+ struct ath_common *common = ath9k_hw_common(ah);
+ unsigned int clockrate;
+
+- if (!ah->curchan) /* should really check for CCK instead */
++ /* AR9287 v1.3+ uses async FIFO and runs the MAC at 117 MHz */
++ if (AR_SREV_9287(ah) && AR_SREV_9287_13_OR_LATER(ah))
++ clockrate = 117;
++ else if (!ah->curchan) /* should really check for CCK instead */
+ clockrate = ATH9K_CLOCK_RATE_CCK;
+ else if (conf->channel->band == IEEE80211_BAND_2GHZ)
+ clockrate = ATH9K_CLOCK_RATE_2GHZ_OFDM;
--- /dev/null
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -951,25 +951,60 @@ static bool ath9k_hw_set_global_txtimeou
+
+ void ath9k_hw_init_global_settings(struct ath_hw *ah)
+ {
+- struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
++ struct ath_common *common = ath9k_hw_common(ah);
++ struct ieee80211_conf *conf = &common->hw->conf;
++ const struct ath9k_channel *chan = ah->curchan;
+ int acktimeout;
+ int slottime;
+ int sifstime;
++ int rx_lat = 0, tx_lat = 0, eifs = 0;
++ u32 reg;
+
+ ath_dbg(ath9k_hw_common(ah), ATH_DBG_RESET, "ah->misc_mode 0x%x\n",
+ ah->misc_mode);
+
++ if (!chan)
++ return;
++
+ if (ah->misc_mode != 0)
+ REG_SET_BIT(ah, AR_PCU_MISC, ah->misc_mode);
+
+- if (conf->channel && conf->channel->band == IEEE80211_BAND_5GHZ)
+- sifstime = 16;
+- else
+- sifstime = 10;
++ rx_lat = 37;
++ tx_lat = 54;
++
++ if (IS_CHAN_HALF_RATE(chan)) {
++ eifs = 175;
++ rx_lat *= 2;
++ tx_lat *= 2;
++ if (IS_CHAN_A_FAST_CLOCK(ah, chan))
++ tx_lat += 11;
++
++ slottime = 13;
++ sifstime = 32;
++ } else if (IS_CHAN_QUARTER_RATE(chan)) {
++ eifs = 340;
++ rx_lat *= 4;
++ tx_lat *= 4;
++ if (IS_CHAN_A_FAST_CLOCK(ah, chan))
++ tx_lat += 22;
++
++ slottime = 21;
++ sifstime = 64;
++ } else {
++ eifs = REG_READ(ah, AR_D_GBL_IFS_EIFS);
++ reg = REG_READ(ah, AR_USEC);
++ rx_lat = MS(reg, AR_USEC_RX_LAT);
++ tx_lat = MS(reg, AR_USEC_TX_LAT);
++
++ slottime = ah->slottime;
++ if (IS_CHAN_5GHZ(chan))
++ sifstime = 16;
++ else
++ sifstime = 10;
++ }
+
+ /* As defined by IEEE 802.11-2007 17.3.8.6 */
+- slottime = ah->slottime + 3 * ah->coverage_class;
+- acktimeout = slottime + sifstime;
++ acktimeout = slottime + sifstime + 3 * ah->coverage_class;
+
+ /*
+ * Workaround for early ACK timeouts, add an offset to match the
+@@ -981,11 +1016,19 @@ void ath9k_hw_init_global_settings(struc
+ if (conf->channel && conf->channel->band == IEEE80211_BAND_2GHZ)
+ acktimeout += 64 - sifstime - ah->slottime;
+
+- ath9k_hw_setslottime(ah, ah->slottime);
++ ath9k_hw_setslottime(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);
++
++ REG_WRITE(ah, AR_D_GBL_IFS_EIFS, ath9k_hw_mac_to_clks(ah, eifs));
++ REG_RMW(ah, AR_USEC,
++ (common->clockrate - 1) |
++ SM(rx_lat, AR_USEC_RX_LAT) |
++ SM(tx_lat, AR_USEC_TX_LAT),
++ AR_USEC_TX_LAT | AR_USEC_RX_LAT | AR_USEC_USEC);
++
+ }
+ EXPORT_SYMBOL(ath9k_hw_init_global_settings);
+
--- /dev/null
+--- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c
++++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
+@@ -499,45 +499,6 @@ void ar9002_hw_enable_async_fifo(struct
+ }
+ }
+
+-/*
+- * If Async FIFO is enabled, the following counters change as MAC now runs
+- * at 117 Mhz instead of 88/44MHz when async FIFO is disabled.
+- *
+- * The values below tested for ht40 2 chain.
+- * Overwrite the delay/timeouts initialized in process ini.
+- */
+-void ar9002_hw_update_async_fifo(struct ath_hw *ah)
+-{
+- if (AR_SREV_9287_13_OR_LATER(ah)) {
+- REG_WRITE(ah, AR_D_GBL_IFS_SIFS,
+- AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR);
+- REG_WRITE(ah, AR_D_GBL_IFS_SLOT,
+- AR_D_GBL_IFS_SLOT_ASYNC_FIFO_DUR);
+- REG_WRITE(ah, AR_D_GBL_IFS_EIFS,
+- AR_D_GBL_IFS_EIFS_ASYNC_FIFO_DUR);
+-
+- REG_WRITE(ah, AR_TIME_OUT, AR_TIME_OUT_ACK_CTS_ASYNC_FIFO_DUR);
+- REG_WRITE(ah, AR_USEC, AR_USEC_ASYNC_FIFO_DUR);
+-
+- REG_SET_BIT(ah, AR_MAC_PCU_LOGIC_ANALYZER,
+- AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768);
+- REG_RMW_FIELD(ah, AR_AHB_MODE, AR_AHB_CUSTOM_BURST_EN,
+- AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL);
+- }
+-}
+-
+-/*
+- * We don't enable WEP aggregation on mac80211 but we keep this
+- * around for HAL unification purposes.
+- */
+-void ar9002_hw_enable_wep_aggregation(struct ath_hw *ah)
+-{
+- if (AR_SREV_9287_13_OR_LATER(ah)) {
+- REG_SET_BIT(ah, AR_PCU_MISC_MODE2,
+- AR_PCU_MISC_MODE2_ENABLE_AGGWEP);
+- }
+-}
+-
+ /* Sets up the AR5008/AR9001/AR9002 hardware familiy callbacks */
+ void ar9002_hw_attach_ops(struct ath_hw *ah)
+ {
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -1633,9 +1633,13 @@ int ath9k_hw_reset(struct ath_hw *ah, st
+
+ ath9k_hw_init_global_settings(ah);
+
+- if (!AR_SREV_9300_20_OR_LATER(ah)) {
+- ar9002_hw_update_async_fifo(ah);
+- ar9002_hw_enable_wep_aggregation(ah);
++ if (AR_SREV_9287(ah) && AR_SREV_9287_13_OR_LATER(ah)) {
++ REG_SET_BIT(ah, AR_MAC_PCU_LOGIC_ANALYZER,
++ AR_MAC_PCU_LOGIC_ANALYZER_DISBUG20768);
++ REG_RMW_FIELD(ah, AR_AHB_MODE, AR_AHB_CUSTOM_BURST_EN,
++ AR_AHB_CUSTOM_BURST_ASYNC_FIFO_VAL);
++ REG_SET_BIT(ah, AR_PCU_MISC_MODE2,
++ AR_PCU_MISC_MODE2_ENABLE_AGGWEP);
+ }
+
+ REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM);
+--- a/drivers/net/wireless/ath/ath9k/hw.h
++++ b/drivers/net/wireless/ath/ath9k/hw.h
+@@ -984,8 +984,6 @@ void ath9k_hw_get_delta_slope_vals(struc
+ void ar9002_hw_cck_chan14_spread(struct ath_hw *ah);
+ int ar9002_hw_rf_claim(struct ath_hw *ah);
+ void ar9002_hw_enable_async_fifo(struct ath_hw *ah);
+-void ar9002_hw_update_async_fifo(struct ath_hw *ah);
+-void ar9002_hw_enable_wep_aggregation(struct ath_hw *ah);
+
+ /*
+ * Code specific to AR9003, we stuff these here to avoid callbacks
--- /dev/null
+--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
+@@ -111,7 +111,9 @@ static int ar9002_hw_set_channel(struct
+
+ switch (ah->eep_ops->get_eeprom(ah, EEP_FRAC_N_5G)) {
+ case 0:
+- if ((freq % 20) == 0)
++ if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))
++ aModeRefSel = 0;
++ else if ((freq % 20) == 0)
+ aModeRefSel = 3;
+ else if ((freq % 10) == 0)
+ aModeRefSel = 2;
--- /dev/null
+--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+@@ -627,6 +627,11 @@ static void ar5008_hw_init_bb(struct ath
+ else
+ synthDelay /= 10;
+
++ if (IS_CHAN_HALF_RATE(chan))
++ synthDelay *= 2;
++ else if (IS_CHAN_QUARTER_RATE(chan))
++ synthDelay *= 4;
++
+ REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+
+ udelay(synthDelay + BASE_ACTIVATE_DELAY);
--- /dev/null
+--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
+@@ -131,8 +131,9 @@ static int ar9002_hw_set_channel(struct
+ channelSel = CHANSEL_5G(freq);
+
+ /* RefDivA setting */
+- REG_RMW_FIELD(ah, AR_AN_SYNTH9,
+- AR_AN_SYNTH9_REFDIVA, refDivA);
++ ath9k_hw_analog_shift_rmw(ah, AR_AN_SYNTH9,
++ AR_AN_SYNTH9_REFDIVA,
++ AR_AN_SYNTH9_REFDIVA_S, refDivA);
+
+ }
+