linux/drivers/net/wireless/ath/ath9k/ani.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2008-2011 Atheros Communications Inc.
   3 *
   4 * Permission to use, copy, modify, and/or distribute this software for any
   5 * purpose with or without fee is hereby granted, provided that the above
   6 * copyright notice and this permission notice appear in all copies.
   7 *
   8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15 */
  16
  17#include <linux/kernel.h>
  18#include <linux/export.h>
  19#include "hw.h"
  20#include "hw-ops.h"
  21
  22struct ani_ofdm_level_entry {
  23        int spur_immunity_level;
  24        int fir_step_level;
  25        int ofdm_weak_signal_on;
  26};
  27
  28/* values here are relative to the INI */
  29
  30/*
  31 * Legend:
  32 *
  33 * SI: Spur immunity
  34 * FS: FIR Step
  35 * WS: OFDM / CCK Weak Signal detection
  36 * MRC-CCK: Maximal Ratio Combining for CCK
  37 */
  38
  39static const struct ani_ofdm_level_entry ofdm_level_table[] = {
  40        /* SI  FS  WS */
  41        {  0,  0,  1  }, /* lvl 0 */
  42        {  1,  1,  1  }, /* lvl 1 */
  43        {  2,  2,  1  }, /* lvl 2 */
  44        {  3,  2,  1  }, /* lvl 3  (default) */
  45        {  4,  3,  1  }, /* lvl 4 */
  46        {  5,  4,  1  }, /* lvl 5 */
  47        {  6,  5,  1  }, /* lvl 6 */
  48        {  7,  6,  1  }, /* lvl 7 */
  49        {  7,  7,  1  }, /* lvl 8 */
  50        {  7,  8,  0  }  /* lvl 9 */
  51};
  52#define ATH9K_ANI_OFDM_NUM_LEVEL \
  53        ARRAY_SIZE(ofdm_level_table)
  54#define ATH9K_ANI_OFDM_MAX_LEVEL \
  55        (ATH9K_ANI_OFDM_NUM_LEVEL-1)
  56#define ATH9K_ANI_OFDM_DEF_LEVEL \
  57        3 /* default level - matches the INI settings */
  58
  59/*
  60 * MRC (Maximal Ratio Combining) has always been used with multi-antenna ofdm.
  61 * With OFDM for single stream you just add up all antenna inputs, you're
  62 * only interested in what you get after FFT. Signal aligment is also not
  63 * required for OFDM because any phase difference adds up in the frequency
  64 * domain.
  65 *
  66 * MRC requires extra work for use with CCK. You need to align the antenna
  67 * signals from the different antenna before you can add the signals together.
  68 * You need aligment of signals as CCK is in time domain, so addition can cancel
  69 * your signal completely if phase is 180 degrees (think of adding sine waves).
  70 * You also need to remove noise before the addition and this is where ANI
  71 * MRC CCK comes into play. One of the antenna inputs may be stronger but
  72 * lower SNR, so just adding after alignment can be dangerous.
  73 *
  74 * Regardless of alignment in time, the antenna signals add constructively after
  75 * FFT and improve your reception. For more information:
  76 *
  77 * http://en.wikipedia.org/wiki/Maximal-ratio_combining
  78 */
  79
  80struct ani_cck_level_entry {
  81        int fir_step_level;
  82        int mrc_cck_on;
  83};
  84
  85static const struct ani_cck_level_entry cck_level_table[] = {
  86        /* FS  MRC-CCK  */
  87        {  0,  1  }, /* lvl 0 */
  88        {  1,  1  }, /* lvl 1 */
  89        {  2,  1  }, /* lvl 2  (default) */
  90        {  3,  1  }, /* lvl 3 */
  91        {  4,  0  }, /* lvl 4 */
  92        {  5,  0  }, /* lvl 5 */
  93        {  6,  0  }, /* lvl 6 */
  94        {  7,  0  }, /* lvl 7 (only for high rssi) */
  95        {  8,  0  }  /* lvl 8 (only for high rssi) */
  96};
  97
  98#define ATH9K_ANI_CCK_NUM_LEVEL \
  99        ARRAY_SIZE(cck_level_table)
 100#define ATH9K_ANI_CCK_MAX_LEVEL \
 101        (ATH9K_ANI_CCK_NUM_LEVEL-1)
 102#define ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI \
 103        (ATH9K_ANI_CCK_NUM_LEVEL-3)
 104#define ATH9K_ANI_CCK_DEF_LEVEL \
 105        2 /* default level - matches the INI settings */
 106
 107static bool use_new_ani(struct ath_hw *ah)
 108{
 109        return AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani;
 110}
 111
 112static void ath9k_hw_update_mibstats(struct ath_hw *ah,
 113                                     struct ath9k_mib_stats *stats)
 114{
 115        stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL);
 116        stats->rts_bad += REG_READ(ah, AR_RTS_FAIL);
 117        stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL);
 118        stats->rts_good += REG_READ(ah, AR_RTS_OK);
 119        stats->beacons += REG_READ(ah, AR_BEACON_CNT);
 120}
 121
 122static void ath9k_ani_restart(struct ath_hw *ah)
 123{
 124        struct ar5416AniState *aniState;
 125        struct ath_common *common = ath9k_hw_common(ah);
 126        u32 ofdm_base = 0, cck_base = 0;
 127
 128        if (!DO_ANI(ah))
 129                return;
 130
 131        aniState = &ah->curchan->ani;
 132        aniState->listenTime = 0;
 133
 134        if (!use_new_ani(ah)) {
 135                ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high;
 136                cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high;
 137        }
 138
 139        ath_dbg(common, ANI, "Writing ofdmbase=%u   cckbase=%u\n",
 140                ofdm_base, cck_base);
 141
 142        ENABLE_REGWRITE_BUFFER(ah);
 143
 144        REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base);
 145        REG_WRITE(ah, AR_PHY_ERR_2, cck_base);
 146        REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
 147        REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
 148
 149        REGWRITE_BUFFER_FLUSH(ah);
 150
 151        ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
 152
 153        aniState->ofdmPhyErrCount = 0;
 154        aniState->cckPhyErrCount = 0;
 155}
 156
 157static void ath9k_hw_ani_ofdm_err_trigger_old(struct ath_hw *ah)
 158{
 159        struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
 160        struct ar5416AniState *aniState;
 161        int32_t rssi;
 162
 163        aniState = &ah->curchan->ani;
 164
 165        if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
 166                if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
 167                                         aniState->noiseImmunityLevel + 1)) {
 168                        return;
 169                }
 170        }
 171
 172        if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) {
 173                if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
 174                                         aniState->spurImmunityLevel + 1)) {
 175                        return;
 176                }
 177        }
 178
 179        if (ah->opmode == NL80211_IFTYPE_AP) {
 180                if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
 181                        ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
 182                                             aniState->firstepLevel + 1);
 183                }
 184                return;
 185        }
 186        rssi = BEACON_RSSI(ah);
 187        if (rssi > aniState->rssiThrHigh) {
 188                if (!aniState->ofdmWeakSigDetectOff) {
 189                        if (ath9k_hw_ani_control(ah,
 190                                         ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
 191                                         false)) {
 192                                ath9k_hw_ani_control(ah,
 193                                        ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
 194                                return;
 195                        }
 196                }
 197                if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
 198                        ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
 199                                             aniState->firstepLevel + 1);
 200                        return;
 201                }
 202        } else if (rssi > aniState->rssiThrLow) {
 203                if (aniState->ofdmWeakSigDetectOff)
 204                        ath9k_hw_ani_control(ah,
 205                                     ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
 206                                     true);
 207                if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
 208                        ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
 209                                             aniState->firstepLevel + 1);
 210                return;
 211        } else {
 212                if ((conf->channel->band == IEEE80211_BAND_2GHZ) &&
 213                    !conf_is_ht(conf)) {
 214                        if (!aniState->ofdmWeakSigDetectOff)
 215                                ath9k_hw_ani_control(ah,
 216                                     ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
 217                                     false);
 218                        if (aniState->firstepLevel > 0)
 219                                ath9k_hw_ani_control(ah,
 220                                             ATH9K_ANI_FIRSTEP_LEVEL, 0);
 221                        return;
 222                }
 223        }
 224}
 225
 226static void ath9k_hw_ani_cck_err_trigger_old(struct ath_hw *ah)
 227{
 228        struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
 229        struct ar5416AniState *aniState;
 230        int32_t rssi;
 231
 232        aniState = &ah->curchan->ani;
 233        if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
 234                if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
 235                                         aniState->noiseImmunityLevel + 1)) {
 236                        return;
 237                }
 238        }
 239        if (ah->opmode == NL80211_IFTYPE_AP) {
 240                if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
 241                        ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
 242                                             aniState->firstepLevel + 1);
 243                }
 244                return;
 245        }
 246        rssi = BEACON_RSSI(ah);
 247        if (rssi > aniState->rssiThrLow) {
 248                if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
 249                        ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
 250                                             aniState->firstepLevel + 1);
 251        } else {
 252                if ((conf->channel->band == IEEE80211_BAND_2GHZ) &&
 253                    !conf_is_ht(conf)) {
 254                        if (aniState->firstepLevel > 0)
 255                                ath9k_hw_ani_control(ah,
 256                                             ATH9K_ANI_FIRSTEP_LEVEL, 0);
 257                }
 258        }
 259}
 260
 261/* Adjust the OFDM Noise Immunity Level */
 262static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel)
 263{
 264        struct ar5416AniState *aniState = &ah->curchan->ani;
 265        struct ath_common *common = ath9k_hw_common(ah);
 266        const struct ani_ofdm_level_entry *entry_ofdm;
 267        const struct ani_cck_level_entry *entry_cck;
 268
 269        aniState->noiseFloor = BEACON_RSSI(ah);
 270
 271        ath_dbg(common, ANI, "**** ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
 272                aniState->ofdmNoiseImmunityLevel,
 273                immunityLevel, aniState->noiseFloor,
 274                aniState->rssiThrLow, aniState->rssiThrHigh);
 275
 276        if (aniState->update_ani)
 277                aniState->ofdmNoiseImmunityLevel = immunityLevel;
 278
 279        entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
 280        entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
 281
 282        if (aniState->spurImmunityLevel != entry_ofdm->spur_immunity_level)
 283                ath9k_hw_ani_control(ah,
 284                                     ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
 285                                     entry_ofdm->spur_immunity_level);
 286
 287        if (aniState->firstepLevel != entry_ofdm->fir_step_level &&
 288            entry_ofdm->fir_step_level >= entry_cck->fir_step_level)
 289                ath9k_hw_ani_control(ah,
 290                                     ATH9K_ANI_FIRSTEP_LEVEL,
 291                                     entry_ofdm->fir_step_level);
 292
 293        if ((ah->opmode != NL80211_IFTYPE_STATION &&
 294             ah->opmode != NL80211_IFTYPE_ADHOC) ||
 295            aniState->noiseFloor <= aniState->rssiThrHigh) {
 296                if (aniState->ofdmWeakSigDetectOff)
 297                        /* force on ofdm weak sig detect */
 298                        ath9k_hw_ani_control(ah,
 299                                ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
 300                                             true);
 301                else if (aniState->ofdmWeakSigDetectOff ==
 302                         entry_ofdm->ofdm_weak_signal_on)
 303                        ath9k_hw_ani_control(ah,
 304                                ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
 305                                entry_ofdm->ofdm_weak_signal_on);
 306        }
 307}
 308
 309static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
 310{
 311        struct ar5416AniState *aniState;
 312
 313        if (!DO_ANI(ah))
 314                return;
 315
 316        if (!use_new_ani(ah)) {
 317                ath9k_hw_ani_ofdm_err_trigger_old(ah);
 318                return;
 319        }
 320
 321        aniState = &ah->curchan->ani;
 322
 323        if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL)
 324                ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1);
 325}
 326
 327/*
 328 * Set the ANI settings to match an CCK level.
 329 */
 330static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel)
 331{
 332        struct ar5416AniState *aniState = &ah->curchan->ani;
 333        struct ath_common *common = ath9k_hw_common(ah);
 334        const struct ani_ofdm_level_entry *entry_ofdm;
 335        const struct ani_cck_level_entry *entry_cck;
 336
 337        aniState->noiseFloor = BEACON_RSSI(ah);
 338        ath_dbg(common, ANI, "**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n",
 339                aniState->cckNoiseImmunityLevel, immunityLevel,
 340                aniState->noiseFloor, aniState->rssiThrLow,
 341                aniState->rssiThrHigh);
 342
 343        if ((ah->opmode == NL80211_IFTYPE_STATION ||
 344             ah->opmode == NL80211_IFTYPE_ADHOC) &&
 345            aniState->noiseFloor <= aniState->rssiThrLow &&
 346            immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI)
 347                immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI;
 348
 349        if (aniState->update_ani)
 350                aniState->cckNoiseImmunityLevel = immunityLevel;
 351
 352        entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
 353        entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
 354
 355        if (aniState->firstepLevel != entry_cck->fir_step_level &&
 356            entry_cck->fir_step_level >= entry_ofdm->fir_step_level)
 357                ath9k_hw_ani_control(ah,
 358                                     ATH9K_ANI_FIRSTEP_LEVEL,
 359                                     entry_cck->fir_step_level);
 360
 361        /* Skip MRC CCK for pre AR9003 families */
 362        if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9485(ah))
 363                return;
 364
 365        if (aniState->mrcCCKOff == entry_cck->mrc_cck_on)
 366                ath9k_hw_ani_control(ah,
 367                                     ATH9K_ANI_MRC_CCK,
 368                                     entry_cck->mrc_cck_on);
 369}
 370
 371static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
 372{
 373        struct ar5416AniState *aniState;
 374
 375        if (!DO_ANI(ah))
 376                return;
 377
 378        if (!use_new_ani(ah)) {
 379                ath9k_hw_ani_cck_err_trigger_old(ah);
 380                return;
 381        }
 382
 383        aniState = &ah->curchan->ani;
 384
 385        if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL)
 386                ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1);
 387}
 388
 389static void ath9k_hw_ani_lower_immunity_old(struct ath_hw *ah)
 390{
 391        struct ar5416AniState *aniState;
 392        int32_t rssi;
 393
 394        aniState = &ah->curchan->ani;
 395
 396        if (ah->opmode == NL80211_IFTYPE_AP) {
 397                if (aniState->firstepLevel > 0) {
 398                        if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
 399                                                 aniState->firstepLevel - 1))
 400                                return;
 401                }
 402        } else {
 403                rssi = BEACON_RSSI(ah);
 404                if (rssi > aniState->rssiThrHigh) {
 405                        /* XXX: Handle me */
 406                } else if (rssi > aniState->rssiThrLow) {
 407                        if (aniState->ofdmWeakSigDetectOff) {
 408                                if (ath9k_hw_ani_control(ah,
 409                                         ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
 410                                         true) == true)
 411                                        return;
 412                        }
 413                        if (aniState->firstepLevel > 0) {
 414                                if (ath9k_hw_ani_control(ah,
 415                                         ATH9K_ANI_FIRSTEP_LEVEL,
 416                                         aniState->firstepLevel - 1) == true)
 417                                        return;
 418                        }
 419                } else {
 420                        if (aniState->firstepLevel > 0) {
 421                                if (ath9k_hw_ani_control(ah,
 422                                         ATH9K_ANI_FIRSTEP_LEVEL,
 423                                         aniState->firstepLevel - 1) == true)
 424                                        return;
 425                        }
 426                }
 427        }
 428
 429        if (aniState->spurImmunityLevel > 0) {
 430                if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
 431                                         aniState->spurImmunityLevel - 1))
 432                        return;
 433        }
 434
 435        if (aniState->noiseImmunityLevel > 0) {
 436                ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
 437                                     aniState->noiseImmunityLevel - 1);
 438                return;
 439        }
 440}
 441
 442/*
 443 * only lower either OFDM or CCK errors per turn
 444 * we lower the other one next time
 445 */
 446static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
 447{
 448        struct ar5416AniState *aniState;
 449
 450        aniState = &ah->curchan->ani;
 451
 452        if (!use_new_ani(ah)) {
 453                ath9k_hw_ani_lower_immunity_old(ah);
 454                return;
 455        }
 456
 457        /* lower OFDM noise immunity */
 458        if (aniState->ofdmNoiseImmunityLevel > 0 &&
 459            (aniState->ofdmsTurn || aniState->cckNoiseImmunityLevel == 0)) {
 460                ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel - 1);
 461                return;
 462        }
 463
 464        /* lower CCK noise immunity */
 465        if (aniState->cckNoiseImmunityLevel > 0)
 466                ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel - 1);
 467}
 468
 469static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning)
 470{
 471        struct ar5416AniState *aniState;
 472        struct ath9k_channel *chan = ah->curchan;
 473        struct ath_common *common = ath9k_hw_common(ah);
 474
 475        if (!DO_ANI(ah))
 476                return;
 477
 478        aniState = &ah->curchan->ani;
 479
 480        if (ah->opmode != NL80211_IFTYPE_STATION
 481            && ah->opmode != NL80211_IFTYPE_ADHOC) {
 482                ath_dbg(common, ANI, "Reset ANI state opmode %u\n", ah->opmode);
 483                ah->stats.ast_ani_reset++;
 484
 485                if (ah->opmode == NL80211_IFTYPE_AP) {
 486                        /*
 487                         * ath9k_hw_ani_control() will only process items set on
 488                         * ah->ani_function
 489                         */
 490                        if (IS_CHAN_2GHZ(chan))
 491                                ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
 492                                                    ATH9K_ANI_FIRSTEP_LEVEL);
 493                        else
 494                                ah->ani_function = 0;
 495                }
 496
 497                ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0);
 498                ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
 499                ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0);
 500                ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
 501                                     !ATH9K_ANI_USE_OFDM_WEAK_SIG);
 502                ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
 503                                     ATH9K_ANI_CCK_WEAK_SIG_THR);
 504
 505                ath9k_ani_restart(ah);
 506                return;
 507        }
 508
 509        if (aniState->noiseImmunityLevel != 0)
 510                ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
 511                                     aniState->noiseImmunityLevel);
 512        if (aniState->spurImmunityLevel != 0)
 513                ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
 514                                     aniState->spurImmunityLevel);
 515        if (aniState->ofdmWeakSigDetectOff)
 516                ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
 517                                     !aniState->ofdmWeakSigDetectOff);
 518        if (aniState->cckWeakSigThreshold)
 519                ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
 520                                     aniState->cckWeakSigThreshold);
 521        if (aniState->firstepLevel != 0)
 522                ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
 523                                     aniState->firstepLevel);
 524
 525        ath9k_ani_restart(ah);
 526
 527        ENABLE_REGWRITE_BUFFER(ah);
 528
 529        REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
 530        REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
 531
 532        REGWRITE_BUFFER_FLUSH(ah);
 533}
 534
 535/*
 536 * Restore the ANI parameters in the HAL and reset the statistics.
 537 * This routine should be called for every hardware reset and for
 538 * every channel change.
 539 */
 540void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
 541{
 542        struct ar5416AniState *aniState = &ah->curchan->ani;
 543        struct ath9k_channel *chan = ah->curchan;
 544        struct ath_common *common = ath9k_hw_common(ah);
 545
 546        if (!DO_ANI(ah))
 547                return;
 548
 549        if (!use_new_ani(ah))
 550                return ath9k_ani_reset_old(ah, is_scanning);
 551
 552        BUG_ON(aniState == NULL);
 553        ah->stats.ast_ani_reset++;
 554
 555        /* only allow a subset of functions in AP mode */
 556        if (ah->opmode == NL80211_IFTYPE_AP) {
 557                if (IS_CHAN_2GHZ(chan)) {
 558                        ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
 559                                            ATH9K_ANI_FIRSTEP_LEVEL);
 560                        if (AR_SREV_9300_20_OR_LATER(ah))
 561                                ah->ani_function |= ATH9K_ANI_MRC_CCK;
 562                } else
 563                        ah->ani_function = 0;
 564        }
 565
 566        /* always allow mode (on/off) to be controlled */
 567        ah->ani_function |= ATH9K_ANI_MODE;
 568
 569        if (is_scanning ||
 570            (ah->opmode != NL80211_IFTYPE_STATION &&
 571             ah->opmode != NL80211_IFTYPE_ADHOC)) {
 572                /*
 573                 * If we're scanning or in AP mode, the defaults (ini)
 574                 * should be in place. For an AP we assume the historical
 575                 * levels for this channel are probably outdated so start
 576                 * from defaults instead.
 577                 */
 578                if (aniState->ofdmNoiseImmunityLevel !=
 579                    ATH9K_ANI_OFDM_DEF_LEVEL ||
 580                    aniState->cckNoiseImmunityLevel !=
 581                    ATH9K_ANI_CCK_DEF_LEVEL) {
 582                        ath_dbg(common, ANI,
 583                                "Restore defaults: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n",
 584                                ah->opmode,
 585                                chan->channel,
 586                                chan->channelFlags,
 587                                is_scanning,
 588                                aniState->ofdmNoiseImmunityLevel,
 589                                aniState->cckNoiseImmunityLevel);
 590
 591                        aniState->update_ani = false;
 592                        ath9k_hw_set_ofdm_nil(ah, ATH9K_ANI_OFDM_DEF_LEVEL);
 593                        ath9k_hw_set_cck_nil(ah, ATH9K_ANI_CCK_DEF_LEVEL);
 594                }
 595        } else {
 596                /*
 597                 * restore historical levels for this channel
 598                 */
 599                ath_dbg(common, ANI,
 600                        "Restore history: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n",
 601                        ah->opmode,
 602                        chan->channel,
 603                        chan->channelFlags,
 604                        is_scanning,
 605                        aniState->ofdmNoiseImmunityLevel,
 606                        aniState->cckNoiseImmunityLevel);
 607
 608                        aniState->update_ani = true;
 609                        ath9k_hw_set_ofdm_nil(ah,
 610                                              aniState->ofdmNoiseImmunityLevel);
 611                        ath9k_hw_set_cck_nil(ah,
 612                                             aniState->cckNoiseImmunityLevel);
 613        }
 614
 615        /*
 616         * enable phy counters if hw supports or if not, enable phy
 617         * interrupts (so we can count each one)
 618         */
 619        ath9k_ani_restart(ah);
 620
 621        ENABLE_REGWRITE_BUFFER(ah);
 622
 623        REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
 624        REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
 625
 626        REGWRITE_BUFFER_FLUSH(ah);
 627}
 628
 629static bool ath9k_hw_ani_read_counters(struct ath_hw *ah)
 630{
 631        struct ath_common *common = ath9k_hw_common(ah);
 632        struct ar5416AniState *aniState = &ah->curchan->ani;
 633        u32 ofdm_base = 0;
 634        u32 cck_base = 0;
 635        u32 ofdmPhyErrCnt, cckPhyErrCnt;
 636        u32 phyCnt1, phyCnt2;
 637        int32_t listenTime;
 638
 639        ath_hw_cycle_counters_update(common);
 640        listenTime = ath_hw_get_listen_time(common);
 641
 642        if (listenTime <= 0) {
 643                ah->stats.ast_ani_lneg_or_lzero++;
 644                ath9k_ani_restart(ah);
 645                return false;
 646        }
 647
 648        if (!use_new_ani(ah)) {
 649                ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high;
 650                cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high;
 651        }
 652
 653        aniState->listenTime += listenTime;
 654
 655        ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
 656
 657        phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
 658        phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
 659
 660        if (!use_new_ani(ah) && (phyCnt1 < ofdm_base || phyCnt2 < cck_base)) {
 661                if (phyCnt1 < ofdm_base) {
 662                        ath_dbg(common, ANI,
 663                                "phyCnt1 0x%x, resetting counter value to 0x%x\n",
 664                                phyCnt1, ofdm_base);
 665                        REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base);
 666                        REG_WRITE(ah, AR_PHY_ERR_MASK_1,
 667                                  AR_PHY_ERR_OFDM_TIMING);
 668                }
 669                if (phyCnt2 < cck_base) {
 670                        ath_dbg(common, ANI,
 671                                "phyCnt2 0x%x, resetting counter value to 0x%x\n",
 672                                phyCnt2, cck_base);
 673                        REG_WRITE(ah, AR_PHY_ERR_2, cck_base);
 674                        REG_WRITE(ah, AR_PHY_ERR_MASK_2,
 675                                  AR_PHY_ERR_CCK_TIMING);
 676                }
 677                return false;
 678        }
 679
 680        ofdmPhyErrCnt = phyCnt1 - ofdm_base;
 681        ah->stats.ast_ani_ofdmerrs +=
 682                ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
 683        aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
 684
 685        cckPhyErrCnt = phyCnt2 - cck_base;
 686        ah->stats.ast_ani_cckerrs +=
 687                cckPhyErrCnt - aniState->cckPhyErrCount;
 688        aniState->cckPhyErrCount = cckPhyErrCnt;
 689        return true;
 690}
 691
 692void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan)
 693{
 694        struct ar5416AniState *aniState;
 695        struct ath_common *common = ath9k_hw_common(ah);
 696        u32 ofdmPhyErrRate, cckPhyErrRate;
 697
 698        if (!DO_ANI(ah))
 699                return;
 700
 701        aniState = &ah->curchan->ani;
 702        if (WARN_ON(!aniState))
 703                return;
 704
 705        if (!ath9k_hw_ani_read_counters(ah))
 706                return;
 707
 708        ofdmPhyErrRate = aniState->ofdmPhyErrCount * 1000 /
 709                         aniState->listenTime;
 710        cckPhyErrRate =  aniState->cckPhyErrCount * 1000 /
 711                         aniState->listenTime;
 712
 713        ath_dbg(common, ANI,
 714                "listenTime=%d OFDM:%d errs=%d/s CCK:%d errs=%d/s ofdm_turn=%d\n",
 715                aniState->listenTime,
 716                aniState->ofdmNoiseImmunityLevel,
 717                ofdmPhyErrRate, aniState->cckNoiseImmunityLevel,
 718                cckPhyErrRate, aniState->ofdmsTurn);
 719
 720        if (aniState->listenTime > 5 * ah->aniperiod) {
 721                if (ofdmPhyErrRate <= ah->config.ofdm_trig_low &&
 722                    cckPhyErrRate <= ah->config.cck_trig_low) {
 723                        ath9k_hw_ani_lower_immunity(ah);
 724                        aniState->ofdmsTurn = !aniState->ofdmsTurn;
 725                }
 726                ath9k_ani_restart(ah);
 727        } else if (aniState->listenTime > ah->aniperiod) {
 728                /* check to see if need to raise immunity */
 729                if (ofdmPhyErrRate > ah->config.ofdm_trig_high &&
 730                    (cckPhyErrRate <= ah->config.cck_trig_high ||
 731                     aniState->ofdmsTurn)) {
 732                        ath9k_hw_ani_ofdm_err_trigger(ah);
 733                        ath9k_ani_restart(ah);
 734                        aniState->ofdmsTurn = false;
 735                } else if (cckPhyErrRate > ah->config.cck_trig_high) {
 736                        ath9k_hw_ani_cck_err_trigger(ah);
 737                        ath9k_ani_restart(ah);
 738                        aniState->ofdmsTurn = true;
 739                }
 740        }
 741}
 742EXPORT_SYMBOL(ath9k_hw_ani_monitor);
 743
 744void ath9k_enable_mib_counters(struct ath_hw *ah)
 745{
 746        struct ath_common *common = ath9k_hw_common(ah);
 747
 748        ath_dbg(common, ANI, "Enable MIB counters\n");
 749
 750        ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
 751
 752        ENABLE_REGWRITE_BUFFER(ah);
 753
 754        REG_WRITE(ah, AR_FILT_OFDM, 0);
 755        REG_WRITE(ah, AR_FILT_CCK, 0);
 756        REG_WRITE(ah, AR_MIBC,
 757                  ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS)
 758                  & 0x0f);
 759        REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
 760        REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
 761
 762        REGWRITE_BUFFER_FLUSH(ah);
 763}
 764
 765/* Freeze the MIB counters, get the stats and then clear them */
 766void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
 767{
 768        struct ath_common *common = ath9k_hw_common(ah);
 769
 770        ath_dbg(common, ANI, "Disable MIB counters\n");
 771
 772        REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC);
 773        ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
 774        REG_WRITE(ah, AR_MIBC, AR_MIBC_CMC);
 775        REG_WRITE(ah, AR_FILT_OFDM, 0);
 776        REG_WRITE(ah, AR_FILT_CCK, 0);
 777}
 778EXPORT_SYMBOL(ath9k_hw_disable_mib_counters);
 779
 780/*
 781 * Process a MIB interrupt.  We may potentially be invoked because
 782 * any of the MIB counters overflow/trigger so don't assume we're
 783 * here because a PHY error counter triggered.
 784 */
 785void ath9k_hw_proc_mib_event(struct ath_hw *ah)
 786{
 787        u32 phyCnt1, phyCnt2;
 788
 789        /* Reset these counters regardless */
 790        REG_WRITE(ah, AR_FILT_OFDM, 0);
 791        REG_WRITE(ah, AR_FILT_CCK, 0);
 792        if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
 793                REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
 794
 795        /* Clear the mib counters and save them in the stats */
 796        ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
 797
 798        if (!DO_ANI(ah)) {
 799                /*
 800                 * We must always clear the interrupt cause by
 801                 * resetting the phy error regs.
 802                 */
 803                REG_WRITE(ah, AR_PHY_ERR_1, 0);
 804                REG_WRITE(ah, AR_PHY_ERR_2, 0);
 805                return;
 806        }
 807
 808        /* NB: these are not reset-on-read */
 809        phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
 810        phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
 811        if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
 812            ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
 813
 814                if (!use_new_ani(ah))
 815                        ath9k_hw_ani_read_counters(ah);
 816
 817                /* NB: always restart to insure the h/w counters are reset */
 818                ath9k_ani_restart(ah);
 819        }
 820}
 821EXPORT_SYMBOL(ath9k_hw_proc_mib_event);
 822
 823void ath9k_hw_ani_setup(struct ath_hw *ah)
 824{
 825        int i;
 826
 827        static const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
 828        static const int coarseHigh[] = { -14, -14, -14, -14, -12 };
 829        static const int coarseLow[] = { -64, -64, -64, -64, -70 };
 830        static const int firpwr[] = { -78, -78, -78, -78, -80 };
 831
 832        for (i = 0; i < 5; i++) {
 833                ah->totalSizeDesired[i] = totalSizeDesired[i];
 834                ah->coarse_high[i] = coarseHigh[i];
 835                ah->coarse_low[i] = coarseLow[i];
 836                ah->firpwr[i] = firpwr[i];
 837        }
 838}
 839
 840void ath9k_hw_ani_init(struct ath_hw *ah)
 841{
 842        struct ath_common *common = ath9k_hw_common(ah);
 843        int i;
 844
 845        ath_dbg(common, ANI, "Initialize ANI\n");
 846
 847        if (use_new_ani(ah)) {
 848                ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_NEW;
 849                ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_NEW;
 850
 851                ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_NEW;
 852                ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_NEW;
 853        } else {
 854                ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD;
 855                ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD;
 856
 857                ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD;
 858                ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD;
 859        }
 860
 861        for (i = 0; i < ARRAY_SIZE(ah->channels); i++) {
 862                struct ath9k_channel *chan = &ah->channels[i];
 863                struct ar5416AniState *ani = &chan->ani;
 864
 865                if (use_new_ani(ah)) {
 866                        ani->spurImmunityLevel =
 867                                ATH9K_ANI_SPUR_IMMUNE_LVL_NEW;
 868
 869                        ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW;
 870
 871                        if (AR_SREV_9300_20_OR_LATER(ah))
 872                                ani->mrcCCKOff =
 873                                        !ATH9K_ANI_ENABLE_MRC_CCK;
 874                        else
 875                                ani->mrcCCKOff = true;
 876
 877                        ani->ofdmsTurn = true;
 878                } else {
 879                        ani->spurImmunityLevel =
 880                                ATH9K_ANI_SPUR_IMMUNE_LVL_OLD;
 881                        ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_OLD;
 882
 883                        ani->cckWeakSigThreshold =
 884                                ATH9K_ANI_CCK_WEAK_SIG_THR;
 885                }
 886
 887                ani->rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
 888                ani->rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
 889                ani->ofdmWeakSigDetectOff =
 890                        !ATH9K_ANI_USE_OFDM_WEAK_SIG;
 891                ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
 892                ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL;
 893                ani->update_ani = false;
 894        }
 895
 896        /*
 897         * since we expect some ongoing maintenance on the tables, let's sanity
 898         * check here default level should not modify INI setting.
 899         */
 900        if (use_new_ani(ah)) {
 901                ah->aniperiod = ATH9K_ANI_PERIOD_NEW;
 902                ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_NEW;
 903        } else {
 904                ah->aniperiod = ATH9K_ANI_PERIOD_OLD;
 905                ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_OLD;
 906        }
 907
 908        if (ah->config.enable_ani)
 909                ah->proc_phyerr |= HAL_PROCESS_ANI;
 910
 911        ath9k_ani_restart(ah);
 912        ath9k_enable_mib_counters(ah);
 913}
 914