ath9k: properly sanitize calibrated noise floor values on all hardware
authorFelix Fietkau <nbd@openwrt.org>
Thu, 1 Jul 2010 19:43:03 +0000 (19:43 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Thu, 1 Jul 2010 19:43:03 +0000 (19:43 +0000)
SVN-Revision: 22035

package/mac80211/patches/530-ath9k_nf_sanitize.patch [new file with mode: 0644]

diff --git a/package/mac80211/patches/530-ath9k_nf_sanitize.patch b/package/mac80211/patches/530-ath9k_nf_sanitize.patch
new file mode 100644 (file)
index 0000000..db87392
--- /dev/null
@@ -0,0 +1,386 @@
+--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+@@ -1678,6 +1678,15 @@ static void ar5008_hw_ani_cache_ini_regs
+       aniState->cycleCount = 0;
+ }
++static void ar5008_hw_set_nf_limits(struct ath_hw *ah)
++{
++      ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_5416_2GHZ;
++      ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_5416_2GHZ;
++      ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_5416_2GHZ;
++      ah->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_5416_5GHZ;
++      ah->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_5416_5GHZ;
++      ah->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_5416_5GHZ;
++}
+ void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
+ {
+@@ -1715,4 +1724,6 @@ void ar5008_hw_attach_phy_ops(struct ath
+               priv_ops->compute_pll_control = ar9160_hw_compute_pll_control;
+       else
+               priv_ops->compute_pll_control = ar5008_hw_compute_pll_control;
++
++      ar5008_hw_set_nf_limits(ah);
+ }
+--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
+@@ -520,6 +520,30 @@ static void ar9002_hw_do_getnf(struct at
+       }
+ }
++static void ar9002_hw_set_nf_limits(struct ath_hw *ah)
++{
++      if (AR_SREV_9285(ah)) {
++              ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9285_2GHZ;
++              ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9285_2GHZ;
++              ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9285_2GHZ;
++      } else if (AR_SREV_9287(ah)) {
++              ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9287_2GHZ;
++              ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9287_2GHZ;
++              ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9287_2GHZ;
++      } else if (AR_SREV_9271(ah)) {
++              ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9271_2GHZ;
++              ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9271_2GHZ;
++              ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9271_2GHZ;
++      } else {
++              ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9280_2GHZ;
++              ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9280_2GHZ;
++              ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9280_2GHZ;
++              ah->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_9280_5GHZ;
++              ah->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_9280_5GHZ;
++              ah->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_9280_5GHZ;
++      }
++}
++
+ void ar9002_hw_attach_phy_ops(struct ath_hw *ah)
+ {
+       struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+@@ -532,4 +556,6 @@ void ar9002_hw_attach_phy_ops(struct ath
+       priv_ops->olc_init = ar9002_olc_init;
+       priv_ops->compute_pll_control = ar9002_hw_compute_pll_control;
+       priv_ops->do_getnf = ar9002_hw_do_getnf;
++
++      ar9002_hw_set_nf_limits(ah);
+ }
+--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h
++++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h
+@@ -576,4 +576,30 @@
+ #define AR_PHY_CH2_EXT_MINCCA_PWR   0xFF800000
+ #define AR_PHY_CH2_EXT_MINCCA_PWR_S 23
++#define AR_PHY_CCA_NOM_VAL_5416_2GHZ            -90
++#define AR_PHY_CCA_NOM_VAL_5416_5GHZ            -100
++#define AR_PHY_CCA_MIN_GOOD_VAL_5416_2GHZ     -100
++#define AR_PHY_CCA_MIN_GOOD_VAL_5416_5GHZ     -110
++#define AR_PHY_CCA_MAX_GOOD_VAL_5416_2GHZ     -80
++#define AR_PHY_CCA_MAX_GOOD_VAL_5416_5GHZ     -90
++
++#define AR_PHY_CCA_NOM_VAL_9280_2GHZ         -112
++#define AR_PHY_CCA_NOM_VAL_9280_5GHZ         -112
++#define AR_PHY_CCA_MIN_GOOD_VAL_9280_2GHZ  -127
++#define AR_PHY_CCA_MIN_GOOD_VAL_9280_5GHZ  -122
++#define AR_PHY_CCA_MAX_GOOD_VAL_9280_2GHZ  -97
++#define AR_PHY_CCA_MAX_GOOD_VAL_9280_5GHZ  -102
++
++#define AR_PHY_CCA_NOM_VAL_9285_2GHZ           -118
++#define AR_PHY_CCA_MIN_GOOD_VAL_9285_2GHZ    -127
++#define AR_PHY_CCA_MAX_GOOD_VAL_9285_2GHZ    -108
++
++#define AR_PHY_CCA_NOM_VAL_9271_2GHZ             -118
++#define AR_PHY_CCA_MIN_GOOD_VAL_9271_2GHZ      -127
++#define AR_PHY_CCA_MAX_GOOD_VAL_9271_2GHZ      -116
++
++#define AR_PHY_CCA_NOM_VAL_9287_2GHZ           -120
++#define AR_PHY_CCA_MIN_GOOD_VAL_9287_2GHZ    -127
++#define AR_PHY_CCA_MAX_GOOD_VAL_9287_2GHZ    -110
++
+ #endif
+--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+@@ -1015,52 +1015,6 @@ static bool ar9003_hw_ani_control(struct
+       return true;
+ }
+-static void ar9003_hw_nf_sanitize_2g(struct ath_hw *ah, s16 *nf)
+-{
+-      struct ath_common *common = ath9k_hw_common(ah);
+-
+-      if (*nf > ah->nf_2g_max) {
+-              ath_print(common, ATH_DBG_CALIBRATE,
+-                        "2 GHz NF (%d) > MAX (%d), "
+-                        "correcting to MAX",
+-                        *nf, ah->nf_2g_max);
+-              *nf = ah->nf_2g_max;
+-      } else if (*nf < ah->nf_2g_min) {
+-              ath_print(common, ATH_DBG_CALIBRATE,
+-                        "2 GHz NF (%d) < MIN (%d), "
+-                        "correcting to MIN",
+-                        *nf, ah->nf_2g_min);
+-              *nf = ah->nf_2g_min;
+-      }
+-}
+-
+-static void ar9003_hw_nf_sanitize_5g(struct ath_hw *ah, s16 *nf)
+-{
+-      struct ath_common *common = ath9k_hw_common(ah);
+-
+-      if (*nf > ah->nf_5g_max) {
+-              ath_print(common, ATH_DBG_CALIBRATE,
+-                        "5 GHz NF (%d) > MAX (%d), "
+-                        "correcting to MAX",
+-                        *nf, ah->nf_5g_max);
+-              *nf = ah->nf_5g_max;
+-      } else if (*nf < ah->nf_5g_min) {
+-              ath_print(common, ATH_DBG_CALIBRATE,
+-                        "5 GHz NF (%d) < MIN (%d), "
+-                        "correcting to MIN",
+-                        *nf, ah->nf_5g_min);
+-              *nf = ah->nf_5g_min;
+-      }
+-}
+-
+-static void ar9003_hw_nf_sanitize(struct ath_hw *ah, s16 *nf)
+-{
+-      if (IS_CHAN_2GHZ(ah->curchan))
+-              ar9003_hw_nf_sanitize_2g(ah, nf);
+-      else
+-              ar9003_hw_nf_sanitize_5g(ah, nf);
+-}
+-
+ static void ar9003_hw_do_getnf(struct ath_hw *ah,
+                             int16_t nfarray[NUM_NF_READINGS])
+ {
+@@ -1070,7 +1024,6 @@ static void ar9003_hw_do_getnf(struct at
+       nf = MS(REG_READ(ah, AR_PHY_CCA_0), AR_PHY_MINCCA_PWR);
+       if (nf & 0x100)
+               nf = 0 - ((nf ^ 0x1ff) + 1);
+-      ar9003_hw_nf_sanitize(ah, &nf);
+       ath_print(common, ATH_DBG_CALIBRATE,
+                 "NF calibrated [ctl] [chain 0] is %d\n", nf);
+       nfarray[0] = nf;
+@@ -1078,7 +1031,6 @@ static void ar9003_hw_do_getnf(struct at
+       nf = MS(REG_READ(ah, AR_PHY_CCA_1), AR_PHY_CH1_MINCCA_PWR);
+       if (nf & 0x100)
+               nf = 0 - ((nf ^ 0x1ff) + 1);
+-      ar9003_hw_nf_sanitize(ah, &nf);
+       ath_print(common, ATH_DBG_CALIBRATE,
+                 "NF calibrated [ctl] [chain 1] is %d\n", nf);
+       nfarray[1] = nf;
+@@ -1086,7 +1038,6 @@ static void ar9003_hw_do_getnf(struct at
+       nf = MS(REG_READ(ah, AR_PHY_CCA_2), AR_PHY_CH2_MINCCA_PWR);
+       if (nf & 0x100)
+               nf = 0 - ((nf ^ 0x1ff) + 1);
+-      ar9003_hw_nf_sanitize(ah, &nf);
+       ath_print(common, ATH_DBG_CALIBRATE,
+                 "NF calibrated [ctl] [chain 2] is %d\n", nf);
+       nfarray[2] = nf;
+@@ -1094,7 +1045,6 @@ static void ar9003_hw_do_getnf(struct at
+       nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), AR_PHY_EXT_MINCCA_PWR);
+       if (nf & 0x100)
+               nf = 0 - ((nf ^ 0x1ff) + 1);
+-      ar9003_hw_nf_sanitize(ah, &nf);
+       ath_print(common, ATH_DBG_CALIBRATE,
+                 "NF calibrated [ext] [chain 0] is %d\n", nf);
+       nfarray[3] = nf;
+@@ -1102,7 +1052,6 @@ static void ar9003_hw_do_getnf(struct at
+       nf = MS(REG_READ(ah, AR_PHY_EXT_CCA_1), AR_PHY_CH1_EXT_MINCCA_PWR);
+       if (nf & 0x100)
+               nf = 0 - ((nf ^ 0x1ff) + 1);
+-      ar9003_hw_nf_sanitize(ah, &nf);
+       ath_print(common, ATH_DBG_CALIBRATE,
+                 "NF calibrated [ext] [chain 1] is %d\n", nf);
+       nfarray[4] = nf;
+@@ -1110,18 +1059,19 @@ static void ar9003_hw_do_getnf(struct at
+       nf = MS(REG_READ(ah, AR_PHY_EXT_CCA_2), AR_PHY_CH2_EXT_MINCCA_PWR);
+       if (nf & 0x100)
+               nf = 0 - ((nf ^ 0x1ff) + 1);
+-      ar9003_hw_nf_sanitize(ah, &nf);
+       ath_print(common, ATH_DBG_CALIBRATE,
+                 "NF calibrated [ext] [chain 2] is %d\n", nf);
+       nfarray[5] = nf;
+ }
+-void ar9003_hw_set_nf_limits(struct ath_hw *ah)
++static void ar9003_hw_set_nf_limits(struct ath_hw *ah)
+ {
+-      ah->nf_2g_max = AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ;
+-      ah->nf_2g_min = AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ;
+-      ah->nf_5g_max = AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ;
+-      ah->nf_5g_min = AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ;
++      ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ;
++      ah->nf_2g.min = AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ;
++      ah->nf_2g.nominal = AR_PHY_CCA_NOM_VAL_9300_2GHZ;
++      ah->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ;
++      ah->nf_5g.min = AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ;
++      ah->nf_5g.nominal = AR_PHY_CCA_NOM_VAL_9300_5GHZ;
+ }
+ /*
+@@ -1309,6 +1259,8 @@ void ar9003_hw_attach_phy_ops(struct ath
+       priv_ops->do_getnf = ar9003_hw_do_getnf;
+       priv_ops->loadnf = ar9003_hw_loadnf;
+       priv_ops->ani_cache_ini_regs = ar9003_hw_ani_cache_ini_regs;
++
++      ar9003_hw_set_nf_limits(ah);
+ }
+ void ar9003_hw_bb_watchdog_config(struct ath_hw *ah)
+--- a/drivers/net/wireless/ath/ath9k/calib.c
++++ b/drivers/net/wireless/ath/ath9k/calib.c
+@@ -74,13 +74,8 @@ static void ath9k_hw_update_nfcal_hist_b
+                       h[i].currIndex = 0;
+               if (h[i].invalidNFcount > 0) {
+-                      if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE ||
+-                          nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) {
+-                              h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX;
+-                      } else {
+-                              h[i].invalidNFcount--;
+-                              h[i].privNF = nfarray[i];
+-                      }
++                      h[i].invalidNFcount--;
++                      h[i].privNF = nfarray[i];
+               } else {
+                       h[i].privNF =
+                               ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer);
+@@ -172,6 +167,35 @@ void ath9k_hw_start_nfcal(struct ath_hw 
+       REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
+ }
++static void ath9k_hw_nf_sanitize(struct ath_hw *ah, s16 *nf)
++{
++      struct ath_common *common = ath9k_hw_common(ah);
++      struct ath_nf_limits *limit;
++      int i;
++
++      if (IS_CHAN_2GHZ(ah->curchan))
++              limit = &ah->nf_2g;
++      else
++              limit = &ah->nf_5g;
++
++      for (i = 0; i < NUM_NF_READINGS; i++) {
++              if (!nf[i])
++                      continue;
++
++              if (nf[i] > limit->max) {
++                      ath_print(common, ATH_DBG_CALIBRATE,
++                                "NF[%d] (%d) > MAX (%d), correcting to MAX",
++                                i, nf[i], limit->max);
++                      nf[i] = limit->max;
++              } else if (nf[i] < limit->min) {
++                      ath_print(common, ATH_DBG_CALIBRATE,
++                                "NF[%d] (%d) < MIN (%d), correcting to NOM",
++                                i, nf[i], limit->min);
++                      nf[i] = limit->nominal;
++              }
++      }
++}
++
+ int16_t ath9k_hw_getnf(struct ath_hw *ah,
+                      struct ath9k_channel *chan)
+ {
+@@ -190,6 +214,7 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah
+               return chan->rawNoiseFloor;
+       } else {
+               ath9k_hw_do_getnf(ah, nfarray);
++              ath9k_hw_nf_sanitize(ah, nfarray);
+               nf = nfarray[0];
+               if (ath9k_hw_get_nf_thresh(ah, c->band, &nfThresh)
+                   && nf > nfThresh) {
+@@ -211,25 +236,21 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah
+ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah)
+ {
++      struct ath_nf_limits *limit;
+       int i, j;
+-      s16 noise_floor;
+-      if (AR_SREV_9280(ah))
+-              noise_floor = AR_PHY_CCA_MAX_AR9280_GOOD_VALUE;
+-      else if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
+-              noise_floor = AR_PHY_CCA_MAX_AR9285_GOOD_VALUE;
+-      else if (AR_SREV_9287(ah))
+-              noise_floor = AR_PHY_CCA_MAX_AR9287_GOOD_VALUE;
++      if (IS_CHAN_2GHZ(ah->curchan))
++              limit = &ah->nf_2g;
+       else
+-              noise_floor = AR_PHY_CCA_MAX_AR5416_GOOD_VALUE;
++              limit = &ah->nf_5g;
+       for (i = 0; i < NUM_NF_READINGS; i++) {
+               ah->nfCalHist[i].currIndex = 0;
+-              ah->nfCalHist[i].privNF = noise_floor;
++              ah->nfCalHist[i].privNF = limit->nominal;
+               ah->nfCalHist[i].invalidNFcount =
+                       AR_PHY_CCA_FILTERWINDOW_LENGTH;
+               for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) {
+-                      ah->nfCalHist[i].nfCalBuffer[j] = noise_floor;
++                      ah->nfCalHist[i].nfCalBuffer[j] = limit->nominal;
+               }
+       }
+ }
+--- a/drivers/net/wireless/ath/ath9k/calib.h
++++ b/drivers/net/wireless/ath/ath9k/calib.h
+@@ -19,12 +19,6 @@
+ #include "hw.h"
+-#define AR_PHY_CCA_MAX_AR5416_GOOD_VALUE      -85
+-#define AR_PHY_CCA_MAX_AR9280_GOOD_VALUE      -112
+-#define AR_PHY_CCA_MAX_AR9285_GOOD_VALUE      -118
+-#define AR_PHY_CCA_MAX_AR9287_GOOD_VALUE      -118
+-#define AR_PHY_CCA_MAX_HIGH_VALUE                     -62
+-#define AR_PHY_CCA_MIN_BAD_VALUE                      -140
+ #define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT     3
+ #define AR_PHY_CCA_FILTERWINDOW_LENGTH          5
+--- a/drivers/net/wireless/ath/ath9k/hw.c
++++ b/drivers/net/wireless/ath/ath9k/hw.c
+@@ -621,9 +621,6 @@ static int __ath9k_hw_init(struct ath_hw
+       else
+               ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S);
+-      if (AR_SREV_9300_20_OR_LATER(ah))
+-              ar9003_hw_set_nf_limits(ah);
+-
+       ath9k_init_nfcal_hist_buffer(ah);
+       ah->bb_watchdog_timeout_ms = 25;
+--- a/drivers/net/wireless/ath/ath9k/hw.h
++++ b/drivers/net/wireless/ath/ath9k/hw.h
+@@ -630,6 +630,12 @@ struct ath_hw_ops {
+       void (*ani_monitor)(struct ath_hw *ah, struct ath9k_channel *chan);
+ };
++struct ath_nf_limits {
++      s16 max;
++      s16 min;
++      s16 nominal;
++};
++
+ struct ath_hw {
+       struct ieee80211_hw *hw;
+       struct ath_common common;
+@@ -651,10 +657,9 @@ struct ath_hw {
+       bool is_pciexpress;
+       bool need_an_top2_fixup;
+       u16 tx_trig_level;
+-      s16 nf_2g_max;
+-      s16 nf_2g_min;
+-      s16 nf_5g_max;
+-      s16 nf_5g_min;
++
++      struct ath_nf_limits nf_2g;
++      struct ath_nf_limits nf_5g;
+       u16 rfsilent;
+       u32 rfkill_gpio;
+       u32 rfkill_polarity;
+@@ -945,7 +950,6 @@ void ar9002_hw_enable_wep_aggregation(st
+  * Code specific to AR9003, we stuff these here to avoid callbacks
+  * for older families
+  */
+-void ar9003_hw_set_nf_limits(struct ath_hw *ah);
+ void ar9003_hw_bb_watchdog_config(struct ath_hw *ah);
+ void ar9003_hw_bb_watchdog_read(struct ath_hw *ah);
+ void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah);