summaryrefslogtreecommitdiffstats
path: root/package/mac80211
diff options
context:
space:
mode:
authornbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>2011-04-26 01:23:23 +0000
committernbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>2011-04-26 01:23:23 +0000
commit542d043d67e72f8944ceaee7fbd83c7fbb82373e (patch)
tree899b4e38ff51b8800149de77372daf67ce8e5638 /package/mac80211
parent0318dc07368b86c885d736a0a611144c919ffcd5 (diff)
mac80211: replace the regd revert patch with a proper fix, add some more pending patches
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@26761 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'package/mac80211')
-rw-r--r--package/mac80211/patches/300-pending_work.patch567
-rw-r--r--package/mac80211/patches/300-revert_regd_breakage.patch63
2 files changed, 567 insertions, 63 deletions
diff --git a/package/mac80211/patches/300-pending_work.patch b/package/mac80211/patches/300-pending_work.patch
new file mode 100644
index 000000000..d4a2f4ed5
--- /dev/null
+++ b/package/mac80211/patches/300-pending_work.patch
@@ -0,0 +1,567 @@
+--- 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));
+ }
+
+--- 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];
+ };
+
+@@ -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;
++ }
++ }
+
+- 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);
++
++ /* 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;
+ }
+
+ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
+ u8 num_chains,
+ struct coeff *coeff)
+ {
+- 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);
+
+ 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;
+-
+- }
+- }
+- }
+-
+- 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;
+
+- 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);
+
+- 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 (!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;
++
++ 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;
+ }
++
++ coeff.mag_coeff[i][im] = coeff.iqc_coeff[0] & 0x7f;
++ coeff.phs_coeff[i][im] =
++ (coeff.iqc_coeff[0] >> 7) & 0x7f;
++
++ 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
+
+ #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);
diff --git a/package/mac80211/patches/300-revert_regd_breakage.patch b/package/mac80211/patches/300-revert_regd_breakage.patch
deleted file mode 100644
index 03dd926be..000000000
--- a/package/mac80211/patches/300-revert_regd_breakage.patch
+++ /dev/null
@@ -1,63 +0,0 @@
---- a/net/wireless/reg.c
-+++ b/net/wireless/reg.c
-@@ -107,9 +107,6 @@ struct reg_beacon {
- static void reg_todo(struct work_struct *work);
- static DECLARE_WORK(reg_work, reg_todo);
-
--static void reg_timeout_work(struct work_struct *work);
--static DECLARE_DELAYED_WORK(reg_timeout, reg_timeout_work);
--
- /* We keep a static world regulatory domain in case of the absence of CRDA */
- static const struct ieee80211_regdomain world_regdom = {
- .n_reg_rules = 5,
-@@ -1334,9 +1331,6 @@ static void reg_set_request_processed(vo
- need_more_processing = true;
- spin_unlock(&reg_requests_lock);
-
-- if (last_request->initiator == NL80211_REGDOM_SET_BY_USER)
-- cancel_delayed_work_sync(&reg_timeout);
--
- if (need_more_processing)
- schedule_work(&reg_work);
- }
-@@ -1447,17 +1441,8 @@ static void reg_process_hint(struct regu
- r = __regulatory_hint(wiphy, reg_request);
- /* This is required so that the orig_* parameters are saved */
- if (r == -EALREADY && wiphy &&
-- wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) {
-+ wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY)
- wiphy_update_regulatory(wiphy, initiator);
-- return;
-- }
--
-- /*
-- * 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)
-- schedule_delayed_work(&reg_timeout, msecs_to_jiffies(3142));
- }
-
- /*
-@@ -2185,13 +2170,6 @@ out:
- mutex_unlock(&reg_mutex);
- }
-
--static void reg_timeout_work(struct work_struct *work)
--{
-- REG_DBG_PRINT("Timeout while waiting for CRDA to reply, "
-- "restoring regulatory settings");
-- restore_regulatory_settings(true);
--}
--
- int __init regulatory_init(void)
- {
- int err = 0;
-@@ -2245,7 +2223,6 @@ void /* __init_or_exit */ regulatory_exi
- struct reg_beacon *reg_beacon, *btmp;
-
- cancel_work_sync(&reg_work);
-- cancel_delayed_work_sync(&reg_timeout);
-
- mutex_lock(&cfg80211_mutex);
- mutex_lock(&reg_mutex);