ath9k_hw: allow for spliting up ANI operations by family
[pandora-kernel.git] / drivers / net / wireless / ath / ath9k / ani.c
index 2a0cd64..28a1dc3 100644 (file)
  */
 
 #include "hw.h"
+#include "hw-ops.h"
+
+/* Private to ani.c */
+static inline void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
+{
+       ath9k_hw_private_ops(ah)->ani_lower_immunity(ah);
+}
 
 static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
                                        struct ath9k_channel *chan)
@@ -37,190 +44,6 @@ static int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah,
        return 0;
 }
 
-static bool ath9k_hw_ani_control(struct ath_hw *ah,
-                                enum ath9k_ani_cmd cmd, int param)
-{
-       struct ar5416AniState *aniState = ah->curani;
-       struct ath_common *common = ath9k_hw_common(ah);
-
-       switch (cmd & ah->ani_function) {
-       case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{
-               u32 level = param;
-
-               if (level >= ARRAY_SIZE(ah->totalSizeDesired)) {
-                       ath_print(common, ATH_DBG_ANI,
-                                 "level out of range (%u > %u)\n",
-                                 level,
-                                 (unsigned)ARRAY_SIZE(ah->totalSizeDesired));
-                       return false;
-               }
-
-               REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
-                             AR_PHY_DESIRED_SZ_TOT_DES,
-                             ah->totalSizeDesired[level]);
-               REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
-                             AR_PHY_AGC_CTL1_COARSE_LOW,
-                             ah->coarse_low[level]);
-               REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
-                             AR_PHY_AGC_CTL1_COARSE_HIGH,
-                             ah->coarse_high[level]);
-               REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
-                             AR_PHY_FIND_SIG_FIRPWR,
-                             ah->firpwr[level]);
-
-               if (level > aniState->noiseImmunityLevel)
-                       ah->stats.ast_ani_niup++;
-               else if (level < aniState->noiseImmunityLevel)
-                       ah->stats.ast_ani_nidown++;
-               aniState->noiseImmunityLevel = level;
-               break;
-       }
-       case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{
-               const int m1ThreshLow[] = { 127, 50 };
-               const int m2ThreshLow[] = { 127, 40 };
-               const int m1Thresh[] = { 127, 0x4d };
-               const int m2Thresh[] = { 127, 0x40 };
-               const int m2CountThr[] = { 31, 16 };
-               const int m2CountThrLow[] = { 63, 48 };
-               u32 on = param ? 1 : 0;
-
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
-                             AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
-                             m1ThreshLow[on]);
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
-                             AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
-                             m2ThreshLow[on]);
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR,
-                             AR_PHY_SFCORR_M1_THRESH,
-                             m1Thresh[on]);
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR,
-                             AR_PHY_SFCORR_M2_THRESH,
-                             m2Thresh[on]);
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR,
-                             AR_PHY_SFCORR_M2COUNT_THR,
-                             m2CountThr[on]);
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
-                             AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
-                             m2CountThrLow[on]);
-
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
-                             AR_PHY_SFCORR_EXT_M1_THRESH_LOW,
-                             m1ThreshLow[on]);
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
-                             AR_PHY_SFCORR_EXT_M2_THRESH_LOW,
-                             m2ThreshLow[on]);
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
-                             AR_PHY_SFCORR_EXT_M1_THRESH,
-                             m1Thresh[on]);
-               REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
-                             AR_PHY_SFCORR_EXT_M2_THRESH,
-                             m2Thresh[on]);
-
-               if (on)
-                       REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
-                                   AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
-               else
-                       REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
-                                   AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
-
-               if (!on != aniState->ofdmWeakSigDetectOff) {
-                       if (on)
-                               ah->stats.ast_ani_ofdmon++;
-                       else
-                               ah->stats.ast_ani_ofdmoff++;
-                       aniState->ofdmWeakSigDetectOff = !on;
-               }
-               break;
-       }
-       case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{
-               const int weakSigThrCck[] = { 8, 6 };
-               u32 high = param ? 1 : 0;
-
-               REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
-                             AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK,
-                             weakSigThrCck[high]);
-               if (high != aniState->cckWeakSigThreshold) {
-                       if (high)
-                               ah->stats.ast_ani_cckhigh++;
-                       else
-                               ah->stats.ast_ani_ccklow++;
-                       aniState->cckWeakSigThreshold = high;
-               }
-               break;
-       }
-       case ATH9K_ANI_FIRSTEP_LEVEL:{
-               const int firstep[] = { 0, 4, 8 };
-               u32 level = param;
-
-               if (level >= ARRAY_SIZE(firstep)) {
-                       ath_print(common, ATH_DBG_ANI,
-                                 "level out of range (%u > %u)\n",
-                                 level,
-                                 (unsigned) ARRAY_SIZE(firstep));
-                       return false;
-               }
-               REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
-                             AR_PHY_FIND_SIG_FIRSTEP,
-                             firstep[level]);
-               if (level > aniState->firstepLevel)
-                       ah->stats.ast_ani_stepup++;
-               else if (level < aniState->firstepLevel)
-                       ah->stats.ast_ani_stepdown++;
-               aniState->firstepLevel = level;
-               break;
-       }
-       case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{
-               const int cycpwrThr1[] =
-                       { 2, 4, 6, 8, 10, 12, 14, 16 };
-               u32 level = param;
-
-               if (level >= ARRAY_SIZE(cycpwrThr1)) {
-                       ath_print(common, ATH_DBG_ANI,
-                                 "level out of range (%u > %u)\n",
-                                 level,
-                                 (unsigned) ARRAY_SIZE(cycpwrThr1));
-                       return false;
-               }
-               REG_RMW_FIELD(ah, AR_PHY_TIMING5,
-                             AR_PHY_TIMING5_CYCPWR_THR1,
-                             cycpwrThr1[level]);
-               if (level > aniState->spurImmunityLevel)
-                       ah->stats.ast_ani_spurup++;
-               else if (level < aniState->spurImmunityLevel)
-                       ah->stats.ast_ani_spurdown++;
-               aniState->spurImmunityLevel = level;
-               break;
-       }
-       case ATH9K_ANI_PRESENT:
-               break;
-       default:
-               ath_print(common, ATH_DBG_ANI,
-                         "invalid cmd %u\n", cmd);
-               return false;
-       }
-
-       ath_print(common, ATH_DBG_ANI, "ANI parameters:\n");
-       ath_print(common, ATH_DBG_ANI,
-                 "noiseImmunityLevel=%d, spurImmunityLevel=%d, "
-                 "ofdmWeakSigDetectOff=%d\n",
-                 aniState->noiseImmunityLevel,
-                 aniState->spurImmunityLevel,
-                 !aniState->ofdmWeakSigDetectOff);
-       ath_print(common, ATH_DBG_ANI,
-                 "cckWeakSigThreshold=%d, "
-                 "firstepLevel=%d, listenTime=%d\n",
-                 aniState->cckWeakSigThreshold,
-                 aniState->firstepLevel,
-                 aniState->listenTime);
-       ath_print(common, ATH_DBG_ANI,
-               "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
-               aniState->cycleCount,
-               aniState->ofdmPhyErrCount,
-               aniState->cckPhyErrCount);
-
-       return true;
-}
-
 static void ath9k_hw_update_mibstats(struct ath_hw *ah,
                                     struct ath9k_mib_stats *stats)
 {
@@ -262,11 +85,17 @@ static void ath9k_ani_restart(struct ath_hw *ah)
                  "Writing ofdmbase=%u   cckbase=%u\n",
                  aniState->ofdmPhyErrBase,
                  aniState->cckPhyErrBase);
+
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
        REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
        REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
        REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
 
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
        ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
 
        aniState->ofdmPhyErrCount = 0;
@@ -383,7 +212,7 @@ static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
        }
 }
 
-static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
+static void ath9k_hw_ani_lower_immunity_old(struct ath_hw *ah)
 {
        struct ar5416AniState *aniState;
        int32_t rssi;
@@ -436,6 +265,27 @@ static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
        }
 }
 
+static u8 ath9k_hw_chan_2_clockrate_mhz(struct ath_hw *ah)
+{
+       struct ath9k_channel *chan = ah->curchan;
+       struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
+       u8 clockrate; /* in MHz */
+
+       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;
+       else if (IS_CHAN_A_FAST_CLOCK(ah, chan))
+               clockrate = ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM;
+       else
+               clockrate = ATH9K_CLOCK_RATE_5GHZ_OFDM;
+
+       if (conf_is_ht40(conf))
+               return clockrate * 2;
+
+       return clockrate * 2;
+}
+
 static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah)
 {
        struct ar5416AniState *aniState;
@@ -455,7 +305,15 @@ static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah)
                int32_t ccdelta = cycleCount - aniState->cycleCount;
                int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
                int32_t tfdelta = txFrameCount - aniState->txFrameCount;
-               listenTime = (ccdelta - rfdelta - tfdelta) / 44000;
+               int32_t clock_rate = ath9k_hw_chan_2_clockrate_mhz(ah) * 1000;;
+
+               /*
+                * convert HW counter values to ms using mode
+                * specifix clock rate
+                */
+               clock_rate = ath9k_hw_chan_2_clockrate_mhz(ah) * 1000;;
+
+               listenTime = (ccdelta - rfdelta - tfdelta) / clock_rate;
        }
        aniState->cycleCount = cycleCount;
        aniState->txFrameCount = txFrameCount;
@@ -464,7 +322,7 @@ static int32_t ath9k_hw_ani_get_listen_time(struct ath_hw *ah)
        return listenTime;
 }
 
-void ath9k_ani_reset(struct ath_hw *ah)
+static void ath9k_ani_reset_old(struct ath_hw *ah)
 {
        struct ar5416AniState *aniState;
        struct ath9k_channel *chan = ah->curchan;
@@ -540,12 +398,18 @@ void ath9k_ani_reset(struct ath_hw *ah)
        ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
                             ~ATH9K_RX_FILTER_PHYERR);
        ath9k_ani_restart(ah);
+
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
        REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
 }
 
-void ath9k_hw_ani_monitor(struct ath_hw *ah,
-                         struct ath9k_channel *chan)
+static void ath9k_hw_ani_monitor_old(struct ath_hw *ah,
+                                    struct ath9k_channel *chan)
 {
        struct ar5416AniState *aniState;
        struct ath_common *common = ath9k_hw_common(ah);
@@ -629,7 +493,6 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah,
                }
        }
 }
-EXPORT_SYMBOL(ath9k_hw_ani_monitor);
 
 void ath9k_enable_mib_counters(struct ath_hw *ah)
 {
@@ -639,6 +502,8 @@ void ath9k_enable_mib_counters(struct ath_hw *ah)
 
        ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
 
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_FILT_OFDM, 0);
        REG_WRITE(ah, AR_FILT_CCK, 0);
        REG_WRITE(ah, AR_MIBC,
@@ -646,6 +511,9 @@ void ath9k_enable_mib_counters(struct ath_hw *ah)
                  & 0x0f);
        REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
        REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
 }
 
 /* Freeze the MIB counters, get the stats and then clear them */
@@ -661,6 +529,7 @@ void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
        REG_WRITE(ah, AR_FILT_OFDM, 0);
        REG_WRITE(ah, AR_FILT_CCK, 0);
 }
+EXPORT_SYMBOL(ath9k_hw_disable_mib_counters);
 
 u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah,
                                  u32 *rxc_pcnt,
@@ -708,7 +577,7 @@ u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah,
  * any of the MIB counters overflow/trigger so don't assume we're
  * here because a PHY error counter triggered.
  */
-void ath9k_hw_procmibevent(struct ath_hw *ah)
+static void ath9k_hw_proc_mib_event_old(struct ath_hw *ah)
 {
        u32 phyCnt1, phyCnt2;
 
@@ -721,8 +590,15 @@ void ath9k_hw_procmibevent(struct ath_hw *ah)
        /* Clear the mib counters and save them in the stats */
        ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
 
-       if (!DO_ANI(ah))
+       if (!DO_ANI(ah)) {
+               /*
+                * We must always clear the interrupt cause by
+                * resetting the phy error regs.
+                */
+               REG_WRITE(ah, AR_PHY_ERR_1, 0);
+               REG_WRITE(ah, AR_PHY_ERR_2, 0);
                return;
+       }
 
        /* NB: these are not reset-on-read */
        phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
@@ -757,7 +633,6 @@ void ath9k_hw_procmibevent(struct ath_hw *ah)
                ath9k_ani_restart(ah);
        }
 }
-EXPORT_SYMBOL(ath9k_hw_procmibevent);
 
 void ath9k_hw_ani_setup(struct ath_hw *ah)
 {
@@ -809,8 +684,14 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
        ath_print(common, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n",
                  ah->ani[0].cckPhyErrBase);
 
+       ENABLE_REGWRITE_BUFFER(ah);
+
        REG_WRITE(ah, AR_PHY_ERR_1, ah->ani[0].ofdmPhyErrBase);
        REG_WRITE(ah, AR_PHY_ERR_2, ah->ani[0].cckPhyErrBase);
+
+       REGWRITE_BUFFER_FLUSH(ah);
+       DISABLE_REGWRITE_BUFFER(ah);
+
        ath9k_enable_mib_counters(ah);
 
        ah->aniperiod = ATH9K_ANI_PERIOD;
@@ -818,11 +699,14 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
                ah->proc_phyerr |= HAL_PROCESS_ANI;
 }
 
-void ath9k_hw_ani_disable(struct ath_hw *ah)
+void ath9k_hw_attach_ani_ops_old(struct ath_hw *ah)
 {
-       ath_print(ath9k_hw_common(ah), ATH_DBG_ANI, "Disabling ANI\n");
+       struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+       struct ath_hw_ops *ops = ath9k_hw_ops(ah);
+
+       priv_ops->ani_reset = ath9k_ani_reset_old;
+       priv_ops->ani_lower_immunity = ath9k_hw_ani_lower_immunity_old;
 
-       ath9k_hw_disable_mib_counters(ah);
-       REG_WRITE(ah, AR_PHY_ERR_1, 0);
-       REG_WRITE(ah, AR_PHY_ERR_2, 0);
+       ops->ani_proc_mib_event = ath9k_hw_proc_mib_event_old;
+       ops->ani_monitor = ath9k_hw_ani_monitor_old;
 }