Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
[pandora-kernel.git] / drivers / net / wireless / ath9k / hw.c
index 0251e59..98bc25c 100644 (file)
@@ -329,7 +329,7 @@ static void ath9k_hw_set_defaults(struct ath_hal *ah)
        ah->ah_config.ofdm_trig_high = 500;
        ah->ah_config.cck_trig_high = 200;
        ah->ah_config.cck_trig_low = 100;
-       ah->ah_config.enable_ani = 0;
+       ah->ah_config.enable_ani = 1;
        ah->ah_config.noise_immunity_level = 4;
        ah->ah_config.ofdm_weaksignal_det = 1;
        ah->ah_config.cck_weaksignal_thr = 0;
@@ -2526,6 +2526,11 @@ static void ath9k_ani_reset(struct ath_hal *ah)
        }
 }
 
+/*
+ * Process a MIB interrupt.  We may potentially be invoked because
+ * 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_hal *ah,
                           const struct ath9k_node_stats *stats)
 {
@@ -2533,18 +2538,20 @@ void ath9k_hw_procmibevent(struct ath_hal *ah,
        u32 phyCnt1, phyCnt2;
 
        DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Processing Mib Intr\n");
-
+       /* Reset these counters regardless */
        REG_WRITE(ah, AR_FILT_OFDM, 0);
        REG_WRITE(ah, AR_FILT_CCK, 0);
        if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
                REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
 
+       /* Clear the mib counters and save them in the stats */
        ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
        ahp->ah_stats.ast_nodestats = *stats;
 
        if (!DO_ANI(ah))
                return;
 
+       /* NB: these are not reset-on-read */
        phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
        phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
        if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
@@ -2552,6 +2559,7 @@ void ath9k_hw_procmibevent(struct ath_hal *ah,
                struct ar5416AniState *aniState = ahp->ah_curani;
                u32 ofdmPhyErrCnt, cckPhyErrCnt;
 
+               /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
                ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
                ahp->ah_stats.ast_ani_ofdmerrs +=
                        ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
@@ -2562,11 +2570,17 @@ void ath9k_hw_procmibevent(struct ath_hal *ah,
                        cckPhyErrCnt - aniState->cckPhyErrCount;
                aniState->cckPhyErrCount = cckPhyErrCnt;
 
+               /*
+                * NB: figure out which counter triggered.  If both
+                * trigger we'll only deal with one as the processing
+                * clobbers the error counter so the trigger threshold
+                * check will never be true.
+                */
                if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
                        ath9k_hw_ani_ofdm_err_trigger(ah);
                if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
                        ath9k_hw_ani_cck_err_trigger(ah);
-
+               /* NB: always restart to insure the h/w counters are reset */
                ath9k_ani_restart(ah);
        }
 }
@@ -5853,7 +5867,6 @@ bool ath9k_hw_reset(struct ath_hal *ah,
                    bool bChannelChange,
                    int *status)
 {
-#define FAIL(_code)     do { ecode = _code; goto bad; } while (0)
        u32 saveLedState;
        struct ath_hal_5416 *ahp = AH5416(ah);
        struct ath9k_channel *curchan = ah->ah_curchan;
@@ -5875,11 +5888,14 @@ bool ath9k_hw_reset(struct ath_hal *ah,
                DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
                         "%s: invalid channel %u/0x%x; no mapping\n",
                         __func__, chan->channel, chan->channelFlags);
-               FAIL(-EINVAL);
+               ecode = -EINVAL;
+               goto bad;
        }
 
-       if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
-               return false;
+       if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) {
+               ecode = -EIO;
+               goto bad;
+       }
 
        if (curchan)
                ath9k_hw_getnf(ah, curchan);
@@ -5916,7 +5932,8 @@ bool ath9k_hw_reset(struct ath_hal *ah,
        if (!ath9k_hw_chip_reset(ah, chan)) {
                DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: chip reset failed\n",
                         __func__);
-               FAIL(-EIO);
+               ecode = -EINVAL;
+               goto bad;
        }
 
        if (AR_SREV_9280(ah)) {
@@ -5933,8 +5950,10 @@ bool ath9k_hw_reset(struct ath_hal *ah,
        }
 
        ecode = ath9k_hw_process_ini(ah, chan, macmode);
-       if (ecode != 0)
+       if (ecode != 0) {
+               ecode = -EINVAL;
                goto bad;
+       }
 
        if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
                ath9k_hw_set_delta_slope(ah, chan);
@@ -5947,7 +5966,8 @@ bool ath9k_hw_reset(struct ath_hal *ah,
        if (!ath9k_hw_eeprom_set_board_values(ah, chan)) {
                DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
                         "%s: error setting board options\n", __func__);
-               FAIL(-EIO);
+               ecode = -EIO;
+               goto bad;
        }
 
        ath9k_hw_decrease_chain_power(ah, chan);
@@ -5975,11 +5995,15 @@ bool ath9k_hw_reset(struct ath_hal *ah,
        REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);
 
        if (AR_SREV_9280_10_OR_LATER(ah)) {
-               if (!(ath9k_hw_ar9280_set_channel(ah, chan)))
-                       FAIL(-EIO);
+               if (!(ath9k_hw_ar9280_set_channel(ah, chan))) {
+                       ecode = -EIO;
+                       goto bad;
+               }
        } else {
-               if (!(ath9k_hw_set_channel(ah, chan)))
-                       FAIL(-EIO);
+               if (!(ath9k_hw_set_channel(ah, chan))) {
+                       ecode = -EIO;
+                       goto bad;
+               }
        }
 
        for (i = 0; i < AR_NUM_DCU; i++)
@@ -6013,8 +6037,10 @@ bool ath9k_hw_reset(struct ath_hal *ah,
 
        ath9k_hw_init_bb(ah, chan);
 
-       if (!ath9k_hw_init_cal(ah, chan))
-               FAIL(-ENODEV);
+       if (!ath9k_hw_init_cal(ah, chan)){
+               ecode = -EIO;;
+               goto bad;
+       }
 
        rx_chainmask = ahp->ah_rxchainmask;
        if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) {
@@ -6050,7 +6076,6 @@ bad:
        if (status)
                *status = ecode;
        return false;
-#undef FAIL
 }
 
 bool ath9k_hw_phy_disable(struct ath_hal *ah)
@@ -8391,23 +8416,48 @@ u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags)
        }
 }
 
-int16_t
+/* We can tune this as we go by monitoring really low values */
+#define ATH9K_NF_TOO_LOW       -60
+
+/* AR5416 may return very high value (like -31 dBm), in those cases the nf
+ * is incorrect and we should use the static NF value. Later we can try to
+ * find out why they are reporting these values */
+static bool ath9k_hw_nf_in_range(struct ath_hal *ah, s16 nf)
+{
+       if (nf > ATH9K_NF_TOO_LOW) {
+               DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
+                        "%s: noise floor value detected (%d) is "
+                       "lower than what we think is a "
+                       "reasonable value (%d)\n",
+                        __func__, nf, ATH9K_NF_TOO_LOW);
+               return false;
+       }
+       return true;
+}
+
+s16
 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan)
 {
        struct ath9k_channel *ichan;
+       s16 nf;
 
        ichan = ath9k_regd_check_channel(ah, chan);
        if (ichan == NULL) {
                DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
                         "%s: invalid channel %u/0x%x; no mapping\n",
                         __func__, chan->channel, chan->channelFlags);
-               return 0;
+               return ATH_DEFAULT_NOISE_FLOOR;
        }
        if (ichan->rawNoiseFloor == 0) {
                enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan);
-               return NOISE_FLOOR[mode];
+               nf = NOISE_FLOOR[mode];
        } else
-               return ichan->rawNoiseFloor;
+               nf = ichan->rawNoiseFloor;
+
+       if (!ath9k_hw_nf_in_range(ah, nf))
+               nf = ATH_DEFAULT_NOISE_FLOOR;
+
+       return nf;
 }
 
 bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting)