ath9k: add noise floor calibration fix that should improve stability
[openwrt/svn-archive/archive.git] / package / mac80211 / patches / 300-pending_work.patch
index 40fd32db26a79305453ff52710939e288860a603..f06e9df99b29413504f571459870586e25fb54c5 100644 (file)
---- a/drivers/net/wireless/ath/ath9k/main.c
-+++ b/drivers/net/wireless/ath/ath9k/main.c
-@@ -1048,6 +1048,8 @@ static int ath9k_start(struct ieee80211_
-               "Starting driver with initial channel: %d MHz\n",
-               curchan->center_freq);
+--- a/net/wireless/reg.c
++++ b/net/wireless/reg.c
+@@ -1456,7 +1456,8 @@ static void reg_process_hint(struct regu
+        * We only time out user hints, given that they should be the only
+        * source of bogus requests.
+        */
+-      if (reg_request->initiator == NL80211_REGDOM_SET_BY_USER)
++      if (r != -EALREADY &&
++          reg_request->initiator == NL80211_REGDOM_SET_BY_USER)
+               schedule_delayed_work(&reg_timeout, msecs_to_jiffies(3142));
+ }
  
-+      ath9k_ps_wakeup(sc);
-+
-       mutex_lock(&sc->mutex);
+--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+@@ -18,13 +18,13 @@
+ #include "hw-ops.h"
+ #include "ar9003_phy.h"
+-#define MPASS 3
+ #define MAX_MEASUREMENT       8
+-#define MAX_DIFFERENCE        10
++#define MAX_MAG_DELTA 11
++#define MAX_PHS_DELTA 10
+ struct coeff {
+-      int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MPASS];
+-      int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MPASS];
++      int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT];
++      int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT];
+       int iqc_coeff[2];
+ };
  
-       /* setup initial channel */
-@@ -1143,6 +1145,8 @@ static int ath9k_start(struct ieee80211_
- mutex_unlock:
-       mutex_unlock(&sc->mutex);
+@@ -608,36 +608,48 @@ static bool ar9003_hw_calc_iq_corr(struc
+       return true;
+ }
+-static bool ar9003_hw_compute_closest_pass_and_avg(int *mp_coeff, int *mp_avg)
++static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,
++                                   int max_delta)
+ {
+-      int diff[MPASS];
+-
+-      diff[0] = abs(mp_coeff[0] - mp_coeff[1]);
+-      diff[1] = abs(mp_coeff[1] - mp_coeff[2]);
+-      diff[2] = abs(mp_coeff[2] - mp_coeff[0]);
+-
+-      if (diff[0] > MAX_DIFFERENCE &&
+-          diff[1] > MAX_DIFFERENCE &&
+-          diff[2] > MAX_DIFFERENCE)
+-              return false;
+-
+-      if (diff[0] <= diff[1] && diff[0] <= diff[2])
+-              *mp_avg = (mp_coeff[0] + mp_coeff[1]) / 2;
+-      else if (diff[1] <= diff[2])
+-              *mp_avg = (mp_coeff[1] + mp_coeff[2]) / 2;
+-      else
+-              *mp_avg = (mp_coeff[2] + mp_coeff[0]) / 2;
++      int mp_max = -64, max_idx = 0;
++      int mp_min = 63, min_idx = 0;
++      int mp_avg = 0, i, outlier_idx = 0;
++
++      /* find min/max mismatch across all calibrated gains */
++      for (i = 0; i < nmeasurement; i++) {
++              mp_avg += mp_coeff[i];
++              if (mp_coeff[i] > mp_max) {
++                      mp_max = mp_coeff[i];
++                      max_idx = i;
++              } else if (mp_coeff[i] < mp_min) {
++                      mp_min = mp_coeff[i];
++                      min_idx = i;
++              }
++      }
  
-+      ath9k_ps_restore(sc);
+-      return true;
++      /* find average (exclude max abs value) */
++      for (i = 0; i < nmeasurement; i++) {
++              if ((abs(mp_coeff[i]) < abs(mp_max)) ||
++                  (abs(mp_coeff[i]) < abs(mp_min)))
++                      mp_avg += mp_coeff[i];
++      }
++      mp_avg /= (nmeasurement - 1);
 +
-       return r;
++      /* detect outlier */
++      if (abs(mp_max - mp_min) > max_delta) {
++              if (abs(mp_max - mp_avg) > abs(mp_min - mp_avg))
++                      outlier_idx = max_idx;
++              else
++                      outlier_idx = min_idx;
++      }
++      mp_coeff[outlier_idx] = mp_avg;
  }
  
---- a/net/mac80211/ibss.c
-+++ b/net/mac80211/ibss.c
-@@ -661,7 +661,6 @@ static void ieee80211_sta_find_ibss(stru
- static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
-                                       struct sk_buff *req)
+ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
+                                                u8 num_chains,
+                                                struct coeff *coeff)
  {
--      struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(req);
-       struct ieee80211_mgmt *mgmt = (void *)req->data;
-       struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
-       struct ieee80211_local *local = sdata->local;
-@@ -685,7 +684,7 @@ static void ieee80211_rx_mgmt_probe_req(
-              mgmt->bssid, tx_last_beacon);
- #endif /* CONFIG_MAC80211_IBSS_DEBUG */
--      if (!tx_last_beacon && !(rx_status->rx_flags & IEEE80211_RX_RA_MATCH))
-+      if (!tx_last_beacon && is_multicast_ether_addr(mgmt->da))
-               return;
-       if (memcmp(mgmt->bssid, ifibss->bssid, ETH_ALEN) != 0 &&
---- a/net/mac80211/rc80211_minstrel_ht.c
-+++ b/net/mac80211/rc80211_minstrel_ht.c
-@@ -659,18 +659,14 @@ minstrel_ht_update_caps(void *priv, stru
-       struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs;
-       struct ieee80211_local *local = hw_to_local(mp->hw);
-       u16 sta_cap = sta->ht_cap.cap;
-+      int n_supported = 0;
-       int ack_dur;
-       int stbc;
-       int i;
+-      struct ath_common *common = ath9k_hw_common(ah);
+       int i, im, nmeasurement;
+-      int magnitude, phase;
+       u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS];
+       memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff));
+@@ -657,37 +669,28 @@ static void ar9003_hw_tx_iqcal_load_avg_
+       /* Load the average of 2 passes */
+       for (i = 0; i < num_chains; i++) {
+-              if (AR_SREV_9485(ah))
+-                      nmeasurement = REG_READ_FIELD(ah,
+-                                      AR_PHY_TX_IQCAL_STATUS_B0_9485,
+-                                      AR_PHY_CALIBRATED_GAINS_0);
+-              else
+-                      nmeasurement = REG_READ_FIELD(ah,
+-                                      AR_PHY_TX_IQCAL_STATUS_B0,
+-                                      AR_PHY_CALIBRATED_GAINS_0);
++              nmeasurement = REG_READ_FIELD(ah,
++                              AR_PHY_TX_IQCAL_STATUS_B0,
++                              AR_PHY_CALIBRATED_GAINS_0);
+               if (nmeasurement > MAX_MEASUREMENT)
+                       nmeasurement = MAX_MEASUREMENT;
+-              for (im = 0; im < nmeasurement; im++) {
+-                      /*
+-                       * Determine which 2 passes are closest and compute avg
+-                       * magnitude
+-                       */
+-                      if (!ar9003_hw_compute_closest_pass_and_avg(coeff->mag_coeff[i][im],
+-                                                                  &magnitude))
+-                              goto disable_txiqcal;
++              /* detect outlier only if nmeasurement > 1 */
++              if (nmeasurement > 1) {
++                      /* Detect magnitude outlier */
++                      ar9003_hw_detect_outlier(coeff->mag_coeff[i],
++                                      nmeasurement, MAX_MAG_DELTA);
++
++                      /* Detect phase outlier */
++                      ar9003_hw_detect_outlier(coeff->phs_coeff[i],
++                                      nmeasurement, MAX_PHS_DELTA);
++              }
+-                      /*
+-                       * Determine which 2 passes are closest and compute avg
+-                       * phase
+-                       */
+-                      if (!ar9003_hw_compute_closest_pass_and_avg(coeff->phs_coeff[i][im],
+-                                                                  &phase))
+-                              goto disable_txiqcal;
++              for (im = 0; im < nmeasurement; im++) {
+-                      coeff->iqc_coeff[0] = (magnitude & 0x7f) |
+-                                            ((phase & 0x7f) << 7);
++                      coeff->iqc_coeff[0] = (coeff->mag_coeff[i][im] & 0x7f) |
++                              ((coeff->phs_coeff[i][im] & 0x7f) << 7);
  
-       /* fall back to the old minstrel for legacy stations */
--      if (!sta->ht_cap.ht_supported) {
--              msp->is_ht = false;
--              memset(&msp->legacy, 0, sizeof(msp->legacy));
--              msp->legacy.r = msp->ratelist;
--              msp->legacy.sample_table = msp->sample_table;
--              return mac80211_minstrel.rate_init(priv, sband, sta, &msp->legacy);
+                       if ((im % 2) == 0)
+                               REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
+@@ -707,141 +710,37 @@ static void ar9003_hw_tx_iqcal_load_avg_
+       return;
+-disable_txiqcal:
+-      REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,
+-                    AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x0);
+-      REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,
+-                    AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x0);
+-
+-      ath_dbg(common, ATH_DBG_CALIBRATE, "TX IQ Cal disabled\n");
+ }
+-static void ar9003_hw_tx_iq_cal(struct ath_hw *ah)
++static bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah)
+ {
+       struct ath_common *common = ath9k_hw_common(ah);
+-      static const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
+-              AR_PHY_TX_IQCAL_STATUS_B0,
+-              AR_PHY_TX_IQCAL_STATUS_B1,
+-              AR_PHY_TX_IQCAL_STATUS_B2,
+-      };
+-      static const u32 chan_info_tab[] = {
+-              AR_PHY_CHAN_INFO_TAB_0,
+-              AR_PHY_CHAN_INFO_TAB_1,
+-              AR_PHY_CHAN_INFO_TAB_2,
+-      };
+-      struct coeff coeff;
+-      s32 iq_res[6];
+-      s32 i, j, ip, im, nmeasurement;
+-      u8 nchains = get_streams(common->tx_chainmask);
+-
+-      for (ip = 0; ip < MPASS; ip++) {
+-              REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1,
+-                            AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT,
+-                            DELPT);
+-              REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START,
+-                            AR_PHY_TX_IQCAL_START_DO_CAL,
+-                            AR_PHY_TX_IQCAL_START_DO_CAL);
+-
+-              if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START,
+-                                 AR_PHY_TX_IQCAL_START_DO_CAL,
+-                                 0, AH_WAIT_TIMEOUT)) {
+-                      ath_dbg(common, ATH_DBG_CALIBRATE,
+-                              "Tx IQ Cal not complete.\n");
+-                      goto TX_IQ_CAL_FAILED;
+-              }
+-
+-              nmeasurement = REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_STATUS_B0,
+-                                            AR_PHY_CALIBRATED_GAINS_0);
+-                      if (nmeasurement > MAX_MEASUREMENT)
+-                              nmeasurement = MAX_MEASUREMENT;
+-
+-              for (i = 0; i < nchains; i++) {
+-                      ath_dbg(common, ATH_DBG_CALIBRATE,
+-                              "Doing Tx IQ Cal for chain %d.\n", i);
+-                      for (im = 0; im < nmeasurement; im++) {
+-                              if (REG_READ(ah, txiqcal_status[i]) &
+-                                           AR_PHY_TX_IQCAL_STATUS_FAILED) {
+-                                      ath_dbg(common, ATH_DBG_CALIBRATE,
+-                                              "Tx IQ Cal failed for chain %d.\n", i);
+-                                      goto TX_IQ_CAL_FAILED;
+-                              }
+-
+-                              for (j = 0; j < 3; j++) {
+-                                      u8 idx = 2 * j,
+-                                         offset = 4 * (3 * im + j);
+-
+-                                      REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY,
+-                                                    AR_PHY_CHAN_INFO_TAB_S2_READ,
+-                                                    0);
+-
+-                                      /* 32 bits */
+-                                      iq_res[idx] = REG_READ(ah,
+-                                                      chan_info_tab[i] +
+-                                                      offset);
+-
+-                                      REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY,
+-                                                    AR_PHY_CHAN_INFO_TAB_S2_READ,
+-                                                    1);
+-
+-                                      /* 16 bits */
+-                                      iq_res[idx+1] = 0xffff & REG_READ(ah,
+-                                                              chan_info_tab[i] +
+-                                                              offset);
+-
+-                                      ath_dbg(common, ATH_DBG_CALIBRATE,
+-                                              "IQ RES[%d]=0x%x IQ_RES[%d]=0x%x\n",
+-                                              idx, iq_res[idx], idx+1, iq_res[idx+1]);
+-                              }
+-
+-                              if (!ar9003_hw_calc_iq_corr(ah, i, iq_res,
+-                                                          coeff.iqc_coeff)) {
+-                                      ath_dbg(common, ATH_DBG_CALIBRATE,
+-                                              "Failed in calculation of IQ correction.\n");
+-                                      goto TX_IQ_CAL_FAILED;
+-                              }
+-                              coeff.mag_coeff[i][im][ip] =
+-                                              coeff.iqc_coeff[0] & 0x7f;
+-                              coeff.phs_coeff[i][im][ip] =
+-                                              (coeff.iqc_coeff[0] >> 7) & 0x7f;
+-
+-                              if (coeff.mag_coeff[i][im][ip] > 63)
+-                                      coeff.mag_coeff[i][im][ip] -= 128;
+-                              if (coeff.phs_coeff[i][im][ip] > 63)
+-                                      coeff.phs_coeff[i][im][ip] -= 128;
+-
+-                      }
+-              }
 -      }
-+      if (!sta->ht_cap.ht_supported)
-+              goto use_legacy;
+-
+-      ar9003_hw_tx_iqcal_load_avg_2_passes(ah, nchains, &coeff);
+-
+-      return;
+-
+-TX_IQ_CAL_FAILED:
+-      ath_dbg(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed\n");
+-}
+-
+-static void ar9003_hw_tx_iq_cal_run(struct ath_hw *ah)
+-{
+       u8 tx_gain_forced;
  
-       BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) !=
-               MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS);
-@@ -725,7 +721,22 @@ minstrel_ht_update_caps(void *priv, stru
+-      REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1_9485,
+-                    AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, DELPT);
+       tx_gain_forced = REG_READ_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
+                                       AR_PHY_TXGAIN_FORCE);
+       if (tx_gain_forced)
+               REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
+                             AR_PHY_TXGAIN_FORCE, 0);
  
-               mi->groups[i].supported =
-                       mcs->rx_mask[minstrel_mcs_groups[i].streams - 1];
+-      REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START_9485,
+-                    AR_PHY_TX_IQCAL_START_DO_CAL_9485, 1);
++      REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START,
++                    AR_PHY_TX_IQCAL_START_DO_CAL, 1);
 +
-+              if (mi->groups[i].supported)
-+                      n_supported++;
++      if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START,
++                      AR_PHY_TX_IQCAL_START_DO_CAL, 0,
++                      AH_WAIT_TIMEOUT)) {
++              ath_dbg(common, ATH_DBG_CALIBRATE,
++                      "Tx IQ Cal is not completed.\n");
++              return false;
++      }
++      return true;
+ }
+ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah)
+ {
+       struct ath_common *common = ath9k_hw_common(ah);
+       const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
+-              AR_PHY_TX_IQCAL_STATUS_B0_9485,
++              AR_PHY_TX_IQCAL_STATUS_B0,
+               AR_PHY_TX_IQCAL_STATUS_B1,
+               AR_PHY_TX_IQCAL_STATUS_B2,
+       };
+@@ -853,7 +752,7 @@ static void ar9003_hw_tx_iq_cal_post_pro
+       struct coeff coeff;
+       s32 iq_res[6];
+       u8 num_chains = 0;
+-      int i, ip, im, j;
++      int i, im, j;
+       int nmeasurement;
+       for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+@@ -861,71 +760,69 @@ static void ar9003_hw_tx_iq_cal_post_pro
+                       num_chains++;
        }
+-      for (ip = 0; ip < MPASS; ip++) {
+-              for (i = 0; i < num_chains; i++) {
+-                      nmeasurement = REG_READ_FIELD(ah,
+-                                      AR_PHY_TX_IQCAL_STATUS_B0_9485,
+-                                      AR_PHY_CALIBRATED_GAINS_0);
+-                      if (nmeasurement > MAX_MEASUREMENT)
+-                              nmeasurement = MAX_MEASUREMENT;
++      for (i = 0; i < num_chains; i++) {
++              nmeasurement = REG_READ_FIELD(ah,
++                              AR_PHY_TX_IQCAL_STATUS_B0,
++                              AR_PHY_CALIBRATED_GAINS_0);
++              if (nmeasurement > MAX_MEASUREMENT)
++                      nmeasurement = MAX_MEASUREMENT;
 +
-+      if (!n_supported)
-+              goto use_legacy;
++              for (im = 0; im < nmeasurement; im++) {
++                      ath_dbg(common, ATH_DBG_CALIBRATE,
++                              "Doing Tx IQ Cal for chain %d.\n", i);
+-                      for (im = 0; im < nmeasurement; im++) {
++                      if (REG_READ(ah, txiqcal_status[i]) &
++                                      AR_PHY_TX_IQCAL_STATUS_FAILED) {
+                               ath_dbg(common, ATH_DBG_CALIBRATE,
+-                                      "Doing Tx IQ Cal for chain %d.\n", i);
+-
+-                              if (REG_READ(ah, txiqcal_status[i]) &
+-                                  AR_PHY_TX_IQCAL_STATUS_FAILED) {
+-                                      ath_dbg(common, ATH_DBG_CALIBRATE,
+                                       "Tx IQ Cal failed for chain %d.\n", i);
+-                                      goto tx_iqcal_fail;
+-                              }
++                              goto tx_iqcal_fail;
++                      }
+-                              for (j = 0; j < 3; j++) {
+-                                      u32 idx = 2 * j, offset = 4 * (3 * im + j);
++                      for (j = 0; j < 3; j++) {
++                              u32 idx = 2 * j, offset = 4 * (3 * im + j);
+-                                      REG_RMW_FIELD(ah,
++                              REG_RMW_FIELD(ah,
+                                               AR_PHY_CHAN_INFO_MEMORY,
+                                               AR_PHY_CHAN_INFO_TAB_S2_READ,
+                                               0);
+-                                      /* 32 bits */
+-                                      iq_res[idx] = REG_READ(ah,
+-                                                      chan_info_tab[i] +
+-                                                      offset);
++                              /* 32 bits */
++                              iq_res[idx] = REG_READ(ah,
++                                              chan_info_tab[i] +
++                                              offset);
+-                                      REG_RMW_FIELD(ah,
++                              REG_RMW_FIELD(ah,
+                                               AR_PHY_CHAN_INFO_MEMORY,
+                                               AR_PHY_CHAN_INFO_TAB_S2_READ,
+                                               1);
+-                                      /* 16 bits */
+-                                      iq_res[idx + 1] = 0xffff & REG_READ(ah,
+-                                                        chan_info_tab[i] + offset);
+-
+-                                      ath_dbg(common, ATH_DBG_CALIBRATE,
+-                                              "IQ RES[%d]=0x%x"
+-                                              "IQ_RES[%d]=0x%x\n",
+-                                              idx, iq_res[idx], idx + 1,
+-                                              iq_res[idx + 1]);
+-                              }
++                              /* 16 bits */
++                              iq_res[idx + 1] = 0xffff & REG_READ(ah,
++                                              chan_info_tab[i] + offset);
+-                              if (!ar9003_hw_calc_iq_corr(ah, i, iq_res,
+-                                                          coeff.iqc_coeff)) {
+-                                      ath_dbg(common, ATH_DBG_CALIBRATE,
+-                                       "Failed in calculation of IQ correction.\n");
+-                                      goto tx_iqcal_fail;
+-                              }
++                              ath_dbg(common, ATH_DBG_CALIBRATE,
++                                      "IQ RES[%d]=0x%x"
++                                      "IQ_RES[%d]=0x%x\n",
++                                      idx, iq_res[idx], idx + 1,
++                                      iq_res[idx + 1]);
++                      }
+-                              coeff.mag_coeff[i][im][ip] =
+-                                              coeff.iqc_coeff[0] & 0x7f;
+-                              coeff.phs_coeff[i][im][ip] =
+-                                              (coeff.iqc_coeff[0] >> 7) & 0x7f;
+-
+-                              if (coeff.mag_coeff[i][im][ip] > 63)
+-                                      coeff.mag_coeff[i][im][ip] -= 128;
+-                              if (coeff.phs_coeff[i][im][ip] > 63)
+-                                      coeff.phs_coeff[i][im][ip] -= 128;
++                      if (!ar9003_hw_calc_iq_corr(ah, i, iq_res,
++                                              coeff.iqc_coeff)) {
++                              ath_dbg(common, ATH_DBG_CALIBRATE,
++                                      "Failed in calculation of \
++                                      IQ correction.\n");
++                              goto tx_iqcal_fail;
+                       }
 +
-+      return;
++                      coeff.mag_coeff[i][im] = coeff.iqc_coeff[0] & 0x7f;
++                      coeff.phs_coeff[i][im] =
++                              (coeff.iqc_coeff[0] >> 7) & 0x7f;
 +
-+use_legacy:
-+      msp->is_ht = false;
-+      memset(&msp->legacy, 0, sizeof(msp->legacy));
-+      msp->legacy.r = msp->ratelist;
-+      msp->legacy.sample_table = msp->sample_table;
-+      return mac80211_minstrel.rate_init(priv, sband, sta, &msp->legacy);
- }
++                      if (coeff.mag_coeff[i][im] > 63)
++                              coeff.mag_coeff[i][im] -= 128;
++                      if (coeff.phs_coeff[i][im] > 63)
++                              coeff.phs_coeff[i][im] -= 128;
+               }
+       }
+       ar9003_hw_tx_iqcal_load_avg_2_passes(ah, num_chains, &coeff);
+@@ -941,6 +838,7 @@ static bool ar9003_hw_init_cal(struct at
+ {
+       struct ath_common *common = ath9k_hw_common(ah);
+       int val;
++      bool txiqcal_done = false;
+       val = REG_READ(ah, AR_ENT_OTP);
+       ath_dbg(common, ATH_DBG_CALIBRATE, "ath9k: AR_ENT_OTP 0x%x\n", val);
+@@ -957,14 +855,22 @@ static bool ar9003_hw_init_cal(struct at
+               ar9003_hw_set_chain_masks(ah, 0x7, 0x7);
+       /* Do Tx IQ Calibration */
+-      if (AR_SREV_9485(ah))
+-              ar9003_hw_tx_iq_cal_run(ah);
+-      else
+-              ar9003_hw_tx_iq_cal(ah);
++      REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1,
++                    AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT,
++                    DELPT);
+-      REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
+-      udelay(5);
+-      REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
++      /*
++       * For AR9485 or later chips, TxIQ cal runs as part of
++       * AGC calibration
++       */
++      if (AR_SREV_9485_OR_LATER(ah))
++              txiqcal_done = true;
++      else {
++              txiqcal_done = ar9003_hw_tx_iq_cal_run(ah);
++              REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
++              udelay(5);
++              REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
++      }
+       /* Calibrate the AGC */
+       REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+@@ -979,7 +885,7 @@ static bool ar9003_hw_init_cal(struct at
+               return false;
+       }
+-      if (AR_SREV_9485(ah))
++      if (txiqcal_done)
+               ar9003_hw_tx_iq_cal_post_proc(ah);
+       /* Revert chainmasks to their original values before NF cal */
+--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
++++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+@@ -548,15 +548,12 @@
+ #define AR_PHY_TXGAIN_TABLE      (AR_SM_BASE + 0x300)
+-#define AR_PHY_TX_IQCAL_START_9485            (AR_SM_BASE + 0x3c4)
+-#define AR_PHY_TX_IQCAL_START_DO_CAL_9485     0x80000000
+-#define AR_PHY_TX_IQCAL_START_DO_CAL_9485_S   31
+-#define AR_PHY_TX_IQCAL_CONTROL_1_9485                (AR_SM_BASE + 0x3c8)
+-#define AR_PHY_TX_IQCAL_STATUS_B0_9485                (AR_SM_BASE + 0x3f0)
+-
+-#define AR_PHY_TX_IQCAL_CONTROL_1   (AR_SM_BASE + 0x448)
+-#define AR_PHY_TX_IQCAL_START       (AR_SM_BASE + 0x440)
+-#define AR_PHY_TX_IQCAL_STATUS_B0   (AR_SM_BASE + 0x48c)
++#define AR_PHY_TX_IQCAL_CONTROL_1   (AR_SM_BASE + AR_SREV_9485(ah) ? \
++                                               0x3c8 : 0x448)
++#define AR_PHY_TX_IQCAL_START       (AR_SM_BASE + AR_SREV_9485(ah) ? \
++                                               0x3c4 : 0x440)
++#define AR_PHY_TX_IQCAL_STATUS_B0   (AR_SM_BASE + AR_SREV_9485(ah) ? \
++                                               0x3f0 : 0x48c)
+ #define AR_PHY_TX_IQCAL_CORR_COEFF_B0(_i)    (AR_SM_BASE + \
+                                            (AR_SREV_9485(ah) ? \
+                                             0x3d0 : 0x450) + ((_i) << 2))
+@@ -758,10 +755,10 @@
+ #define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT   0x01000000
+ #define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24
+ #define AR_PHY_CHANNEL_STATUS_RX_CLEAR      0x00000004
+-#define AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT             0x01fc0000
+-#define AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT_S                   18
+-#define AR_PHY_TX_IQCAL_START_DO_CAL        0x00000001
+-#define AR_PHY_TX_IQCAL_START_DO_CAL_S      0
++#define AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT             0x01fc0000
++#define AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT_S                   18
++#define AR_PHY_TX_IQCAL_START_DO_CAL      0x00000001
++#define AR_PHY_TX_IQCAL_START_DO_CAL_S            0
  
- static void
+ #define AR_PHY_TX_IQCAL_STATUS_FAILED    0x00000001
+ #define AR_PHY_CALIBRATED_GAINS_0      0x3e
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -453,6 +453,7 @@ void ath9k_btcoex_timer_pause(struct ath
+ #define ATH_LED_PIN_DEF               1
+ #define ATH_LED_PIN_9287              8
++#define ATH_LED_PIN_9300              10
+ #define ATH_LED_PIN_9485              6
+ #ifdef CONFIG_MAC80211_LEDS
+--- a/drivers/net/wireless/ath/ath9k/gpio.c
++++ b/drivers/net/wireless/ath/ath9k/gpio.c
+@@ -46,6 +46,8 @@ void ath_init_leds(struct ath_softc *sc)
+                       sc->sc_ah->led_pin = ATH_LED_PIN_9287;
+               else if (AR_SREV_9485(sc->sc_ah))
+                       sc->sc_ah->led_pin = ATH_LED_PIN_9485;
++              else if (AR_SREV_9300(sc->sc_ah))
++                      sc->sc_ah->led_pin = ATH_LED_PIN_9300;
+               else
+                       sc->sc_ah->led_pin = ATH_LED_PIN_DEF;
+       }
+--- a/drivers/net/wireless/ath/ath9k/reg.h
++++ b/drivers/net/wireless/ath/ath9k/reg.h
+@@ -868,6 +868,8 @@
+ #define AR_SREV_9485_11(_ah) \
+       (AR_SREV_9485(_ah) && \
+        ((_ah)->hw_version.macRev == AR_SREV_REVISION_9485_11))
++#define AR_SREV_9485_OR_LATER(_ah) \
++      (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9485))
+ #define AR_SREV_9285E_20(_ah) \
+     (AR_SREV_9285_12_OR_LATER(_ah) && \
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -652,7 +652,7 @@ static void ieee80211_sta_reorder_releas
+  set_release_timer:
+               mod_timer(&tid_agg_rx->reorder_timer,
+-                        tid_agg_rx->reorder_time[j] +
++                        tid_agg_rx->reorder_time[j] + 1 +
+                         HT_RX_REORDER_BUF_TIMEOUT);
+       } else {
+               del_timer(&tid_agg_rx->reorder_timer);
+--- a/drivers/net/wireless/ath/ath9k/calib.c
++++ b/drivers/net/wireless/ath/ath9k/calib.c
+@@ -69,15 +69,21 @@ static void ath9k_hw_update_nfcal_hist_b
+                                             int16_t *nfarray)
+ {
+       struct ath_common *common = ath9k_hw_common(ah);
++      struct ieee80211_conf *conf = &common->hw->conf;
+       struct ath_nf_limits *limit;
+       struct ath9k_nfcal_hist *h;
+       bool high_nf_mid = false;
++      u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
+       int i;
+       h = cal->nfCalHist;
+       limit = ath9k_hw_get_nf_limits(ah, ah->curchan);
+       for (i = 0; i < NUM_NF_READINGS; i++) {
++              if (!(chainmask & (1 << i)) ||
++                  ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf)))
++                      continue;
++
+               h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
+               if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX)
+@@ -225,6 +231,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, 
+       int32_t val;
+       u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
+       struct ath_common *common = ath9k_hw_common(ah);
++      struct ieee80211_conf *conf = &common->hw->conf;
+       s16 default_nf = ath9k_hw_get_default_nf(ah, chan);
+       if (ah->caldata)
+@@ -234,6 +241,9 @@ void ath9k_hw_loadnf(struct ath_hw *ah, 
+               if (chainmask & (1 << i)) {
+                       s16 nfval;
++                      if ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf))
++                              continue;
++
+                       if (h)
+                               nfval = h[i].privNF;
+                       else
+@@ -293,6 +303,9 @@ void ath9k_hw_loadnf(struct ath_hw *ah, 
+       ENABLE_REGWRITE_BUFFER(ah);
+       for (i = 0; i < NUM_NF_READINGS; i++) {
+               if (chainmask & (1 << i)) {
++                      if ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf))
++                              continue;
++
+                       val = REG_READ(ah, ah->nf_regs[i]);
+                       val &= 0xFFFFFE00;
+                       val |= (((u32) (-50) << 1) & 0x1ff);