1 /*
   2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
   3  * Use is subject to license terms.
   4  */
   5 
   6 /*
   7  * Copyright (c) 2008 Atheros Communications Inc.
   8  *
   9  * Permission to use, copy, modify, and/or distribute this software for any
  10  * purpose with or without fee is hereby granted, provided that the above
  11  * copyright notice and this permission notice appear in all copies.
  12  *
  13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  20  */
  21 
  22 #include "arn_core.h"
  23 #include "arn_hw.h"
  24 #include "arn_reg.h"
  25 #include "arn_phy.h"
  26 
  27 static int
  28 ath9k_hw_get_ani_channel_idx(struct ath_hal *ah, struct ath9k_channel *chan)
  29 {
  30         struct ath_hal_5416 *ahp = AH5416(ah);
  31         int i;
  32 
  33         for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) {
  34                 if (ahp->ah_ani[i].c.channel == chan->channel)
  35                         return (i);
  36                 if (ahp->ah_ani[i].c.channel == 0) {
  37                         ahp->ah_ani[i].c.channel = chan->channel;
  38                         ahp->ah_ani[i].c.channelFlags = chan->channelFlags;
  39                         return (i);
  40                 }
  41         }
  42 
  43         ARN_DBG((ARN_DBG_ANI, "arn: ath9k_hw_get_ani_channel_idx(): "
  44             "No more channel states left. Using channel 0\n"));
  45 
  46         return (0);
  47 }
  48 
  49 static boolean_t
  50 ath9k_hw_ani_control(struct ath_hal *ah, enum ath9k_ani_cmd cmd, int param)
  51 {
  52         struct ath_hal_5416 *ahp = AH5416(ah);
  53         struct ar5416AniState *aniState = ahp->ah_curani;
  54 
  55         switch (cmd & ahp->ah_ani_function) {
  56         case ATH9K_ANI_NOISE_IMMUNITY_LEVEL: {
  57                 uint32_t level = param;
  58 
  59                 if (level >= ARRAY_SIZE(ahp->ah_totalSizeDesired)) {
  60                         ARN_DBG((ARN_DBG_ANI, "arn: "
  61                             "ah->ah_sc, ATH_DBG_ANI",
  62                             "%s: level out of range (%u > %u)\n",
  63                             __func__, level,
  64                             (unsigned)ARRAY_SIZE(ahp->ah_totalSizeDesired)));
  65 
  66                         return (B_FALSE);
  67                 }
  68 
  69                 REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ,
  70                     AR_PHY_DESIRED_SZ_TOT_DES,
  71                     ahp->ah_totalSizeDesired[level]);
  72                 REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
  73                     AR_PHY_AGC_CTL1_COARSE_LOW,
  74                     ahp->ah_coarseLow[level]);
  75                 REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1,
  76                     AR_PHY_AGC_CTL1_COARSE_HIGH,
  77                     ahp->ah_coarseHigh[level]);
  78                 REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
  79                     AR_PHY_FIND_SIG_FIRPWR,
  80                     ahp->ah_firpwr[level]);
  81 
  82                 if (level > aniState->noiseImmunityLevel)
  83                         ahp->ah_stats.ast_ani_niup++;
  84                 else if (level < aniState->noiseImmunityLevel)
  85                         ahp->ah_stats.ast_ani_nidown++;
  86                 aniState->noiseImmunityLevel = (uint8_t)level; /* LINT */
  87                 break;
  88         }
  89         case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION: {
  90                 const int m1ThreshLow[] = { 127, 50 };
  91                 const int m2ThreshLow[] = { 127, 40 };
  92                 const int m1Thresh[] = { 127, 0x4d };
  93                 const int m2Thresh[] = { 127, 0x40 };
  94                 const int m2CountThr[] = { 31, 16 };
  95                 const int m2CountThrLow[] = { 63, 48 };
  96                 uint32_t on = param ? 1 : 0;
  97 
  98                 REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
  99                     AR_PHY_SFCORR_LOW_M1_THRESH_LOW,
 100                     m1ThreshLow[on]);
 101                 REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
 102                     AR_PHY_SFCORR_LOW_M2_THRESH_LOW,
 103                     m2ThreshLow[on]);
 104                 REG_RMW_FIELD(ah, AR_PHY_SFCORR,
 105                     AR_PHY_SFCORR_M1_THRESH,
 106                     m1Thresh[on]);
 107                 REG_RMW_FIELD(ah, AR_PHY_SFCORR,
 108                     AR_PHY_SFCORR_M2_THRESH,
 109                     m2Thresh[on]);
 110                 REG_RMW_FIELD(ah, AR_PHY_SFCORR,
 111                     AR_PHY_SFCORR_M2COUNT_THR,
 112                     m2CountThr[on]);
 113                 REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW,
 114                     AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW,
 115                     m2CountThrLow[on]);
 116 
 117                 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
 118                     AR_PHY_SFCORR_EXT_M1_THRESH_LOW,
 119                     m1ThreshLow[on]);
 120                 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
 121                     AR_PHY_SFCORR_EXT_M2_THRESH_LOW,
 122                     m2ThreshLow[on]);
 123                 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
 124                     AR_PHY_SFCORR_EXT_M1_THRESH,
 125                     m1Thresh[on]);
 126                 REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT,
 127                     AR_PHY_SFCORR_EXT_M2_THRESH,
 128                     m2Thresh[on]);
 129 
 130                 if (on)
 131                         REG_SET_BIT(ah, AR_PHY_SFCORR_LOW,
 132                             AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
 133                 else
 134                         REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW,
 135                             AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW);
 136 
 137                 if (!on != aniState->ofdmWeakSigDetectOff) {
 138                         if (on)
 139                                 ahp->ah_stats.ast_ani_ofdmon++;
 140                         else
 141                                 ahp->ah_stats.ast_ani_ofdmoff++;
 142                         aniState->ofdmWeakSigDetectOff = !on;
 143                 }
 144                 break;
 145         }
 146         case ATH9K_ANI_CCK_WEAK_SIGNAL_THR: {
 147                 const int weakSigThrCck[] = { 8, 6 };
 148                 uint32_t high = param ? 1 : 0;
 149 
 150                 REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT,
 151                     AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK,
 152                     weakSigThrCck[high]);
 153                 if (high != aniState->cckWeakSigThreshold) {
 154                         if (high)
 155                                 ahp->ah_stats.ast_ani_cckhigh++;
 156                         else
 157                                 ahp->ah_stats.ast_ani_ccklow++;
 158                         /* LINT */
 159                         aniState->cckWeakSigThreshold = (uint8_t)high;
 160                 }
 161                 break;
 162         }
 163         case ATH9K_ANI_FIRSTEP_LEVEL: {
 164                 const int firstep[] = { 0, 4, 8 };
 165                 uint32_t level = param;
 166 
 167                 if (level >= ARRAY_SIZE(firstep)) {
 168                         ARN_DBG((ARN_DBG_ANI, "arn: "
 169                             "%s: level out of range (%u > %u)\n",
 170                             __func__, level,
 171                             (unsigned)ARRAY_SIZE(firstep)));
 172 
 173                         return (B_FALSE);
 174                 }
 175                 REG_RMW_FIELD(ah, AR_PHY_FIND_SIG,
 176                     AR_PHY_FIND_SIG_FIRSTEP, firstep[level]);
 177                 if (level > aniState->firstepLevel)
 178                         ahp->ah_stats.ast_ani_stepup++;
 179                 else if (level < aniState->firstepLevel)
 180                         ahp->ah_stats.ast_ani_stepdown++;
 181                 aniState->firstepLevel = (uint8_t)level; /* LINT */
 182                 break;
 183         }
 184         case ATH9K_ANI_SPUR_IMMUNITY_LEVEL: {
 185                 const int cycpwrThr1[] =
 186                         { 2, 4, 6, 8, 10, 12, 14, 16 };
 187                 uint32_t level = param;
 188 
 189                 if (level >= ARRAY_SIZE(cycpwrThr1)) {
 190                         ARN_DBG((ARN_DBG_ANI, "arn: "
 191                             "%s: level out of range (%u > %u)\n",
 192                             __func__, level,
 193                             (unsigned)ARRAY_SIZE(cycpwrThr1)));
 194 
 195                         return (B_FALSE);
 196                 }
 197                 REG_RMW_FIELD(ah, AR_PHY_TIMING5,
 198                     AR_PHY_TIMING5_CYCPWR_THR1, cycpwrThr1[level]);
 199                 if (level > aniState->spurImmunityLevel)
 200                         ahp->ah_stats.ast_ani_spurup++;
 201                 else if (level < aniState->spurImmunityLevel)
 202                         ahp->ah_stats.ast_ani_spurdown++;
 203                 aniState->spurImmunityLevel = (uint8_t)level; /* LINT */
 204                 break;
 205         }
 206         case ATH9K_ANI_PRESENT:
 207                 break;
 208         default:
 209                 ARN_DBG((ARN_DBG_ANI, "arn: "
 210                     "%s: invalid cmd %u\n", __func__, cmd));
 211                 return (B_FALSE);
 212         }
 213 
 214         ARN_DBG((ARN_DBG_ANI, "arn: "
 215             "%s: ANI parameters:\n", __func__));
 216         ARN_DBG((ARN_DBG_ANI, "arn: "
 217             "noiseImmunityLevel=%d, spurImmunityLevel=%d, "
 218             "ofdmWeakSigDetectOff=%d\n",
 219             aniState->noiseImmunityLevel, aniState->spurImmunityLevel,
 220             !aniState->ofdmWeakSigDetectOff));
 221         ARN_DBG((ARN_DBG_ANI, "arn: "
 222             "cckWeakSigThreshold=%d, "
 223             "firstepLevel=%d, listenTime=%d\n",
 224             aniState->cckWeakSigThreshold, aniState->firstepLevel,
 225             aniState->listenTime));
 226         ARN_DBG((ARN_DBG_ANI, "arn: "
 227             "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n",
 228             aniState->cycleCount, aniState->ofdmPhyErrCount,
 229             aniState->cckPhyErrCount));
 230 
 231         return (B_TRUE);
 232 }
 233 
 234 static void
 235 ath9k_hw_update_mibstats(struct ath_hal *ah, struct ath9k_mib_stats *stats)
 236 {
 237         stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL);
 238         stats->rts_bad += REG_READ(ah, AR_RTS_FAIL);
 239         stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL);
 240         stats->rts_good += REG_READ(ah, AR_RTS_OK);
 241         stats->beacons += REG_READ(ah, AR_BEACON_CNT);
 242 }
 243 
 244 static void
 245 ath9k_ani_restart(struct ath_hal *ah)
 246 {
 247         struct ath_hal_5416 *ahp = AH5416(ah);
 248         struct ar5416AniState *aniState;
 249 
 250         if (!DO_ANI(ah))
 251                 return;
 252 
 253         aniState = ahp->ah_curani;
 254 
 255         aniState->listenTime = 0;
 256         if (ahp->ah_hasHwPhyCounters) {
 257                 if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) {
 258                         aniState->ofdmPhyErrBase = 0;
 259                         ARN_DBG((ARN_DBG_ANI, "arn: "
 260                             "OFDM Trigger is too high for hw counters\n"));
 261                 } else {
 262                         aniState->ofdmPhyErrBase =
 263                             AR_PHY_COUNTMAX - aniState->ofdmTrigHigh;
 264                 }
 265                 if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) {
 266                         aniState->cckPhyErrBase = 0;
 267                         ARN_DBG((ARN_DBG_ANI, "arn: "
 268                             "CCK Trigger is too high for hw counters\n"));
 269                 } else {
 270                         aniState->cckPhyErrBase =
 271                             AR_PHY_COUNTMAX - aniState->cckTrigHigh;
 272                 }
 273 
 274                 ARN_DBG((ARN_DBG_ANI, "arn: "
 275                     "%s: Writing ofdmbase=%u   cckbase=%u\n",
 276                     __func__, aniState->ofdmPhyErrBase,
 277                     aniState->cckPhyErrBase));
 278 
 279                 REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase);
 280                 REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase);
 281                 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
 282                 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
 283 
 284                 ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
 285         }
 286         aniState->ofdmPhyErrCount = 0;
 287         aniState->cckPhyErrCount = 0;
 288 }
 289 
 290 static void
 291 ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah)
 292 {
 293         struct ath_hal_5416 *ahp = AH5416(ah);
 294         struct ath9k_channel *chan = ah->ah_curchan;
 295         struct ar5416AniState *aniState;
 296         enum wireless_mode mode;
 297         int32_t rssi;
 298 
 299         if (!DO_ANI(ah))
 300                 return;
 301 
 302         aniState = ahp->ah_curani;
 303 
 304         if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
 305                 if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
 306                     aniState->noiseImmunityLevel + 1)) {
 307                         return;
 308                 }
 309         }
 310 
 311         if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) {
 312                 if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
 313                     aniState->spurImmunityLevel + 1)) {
 314                         return;
 315                 }
 316         }
 317 
 318         if (ah->ah_opmode == ATH9K_M_HOSTAP) {
 319                 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
 320                         (void) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
 321                             aniState->firstepLevel + 1);
 322                 }
 323                 return;
 324         }
 325         rssi = BEACON_RSSI(ahp);
 326         if (rssi > aniState->rssiThrHigh) {
 327                 if (!aniState->ofdmWeakSigDetectOff) {
 328                         if (ath9k_hw_ani_control(ah,
 329                             ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
 330                             B_FALSE)) {
 331                                 (void) ath9k_hw_ani_control(ah,
 332                                     ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
 333                                 return;
 334                         }
 335                 }
 336                 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
 337                         (void) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
 338                             aniState->firstepLevel + 1);
 339                         return;
 340                 }
 341         } else if (rssi > aniState->rssiThrLow) {
 342                 if (aniState->ofdmWeakSigDetectOff)
 343                         (void) ath9k_hw_ani_control(ah,
 344                             ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
 345                             B_TRUE);
 346                 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
 347                         (void) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
 348                             aniState->firstepLevel + 1);
 349                 return;
 350         } else {
 351                 mode = ath9k_hw_chan2wmode(ah, chan);
 352                 if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) {
 353                         if (!aniState->ofdmWeakSigDetectOff)
 354                                 (void) ath9k_hw_ani_control(ah,
 355                                     ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
 356                                     B_FALSE);
 357                         if (aniState->firstepLevel > 0)
 358                                 (void) ath9k_hw_ani_control(ah,
 359                                     ATH9K_ANI_FIRSTEP_LEVEL, 0);
 360                         return;
 361                 }
 362         }
 363 }
 364 
 365 static void
 366 ath9k_hw_ani_cck_err_trigger(struct ath_hal *ah)
 367 {
 368         struct ath_hal_5416 *ahp = AH5416(ah);
 369         struct ath9k_channel *chan = ah->ah_curchan;
 370         struct ar5416AniState *aniState;
 371         enum wireless_mode mode;
 372         int32_t rssi;
 373 
 374         if (!DO_ANI(ah))
 375                 return;
 376 
 377         aniState = ahp->ah_curani;
 378         if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) {
 379                 if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
 380                     aniState->noiseImmunityLevel + 1)) {
 381                         return;
 382                 }
 383         }
 384         if (ah->ah_opmode == ATH9K_M_HOSTAP) {
 385                 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) {
 386                         (void) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
 387                             aniState->firstepLevel + 1);
 388                 }
 389                 return;
 390         }
 391         rssi = BEACON_RSSI(ahp);
 392         if (rssi > aniState->rssiThrLow) {
 393                 if (aniState->firstepLevel < HAL_FIRST_STEP_MAX)
 394                         (void) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
 395                             aniState->firstepLevel + 1);
 396         } else {
 397                 mode = ath9k_hw_chan2wmode(ah, chan);
 398                 if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) {
 399                         if (aniState->firstepLevel > 0)
 400                                 (void) ath9k_hw_ani_control(ah,
 401                                     ATH9K_ANI_FIRSTEP_LEVEL, 0);
 402                 }
 403         }
 404 }
 405 
 406 static void
 407 ath9k_hw_ani_lower_immunity(struct ath_hal *ah)
 408 {
 409         struct ath_hal_5416 *ahp = AH5416(ah);
 410         struct ar5416AniState *aniState;
 411         int32_t rssi;
 412 
 413         aniState = ahp->ah_curani;
 414 
 415         if (ah->ah_opmode == ATH9K_M_HOSTAP) {
 416                 if (aniState->firstepLevel > 0) {
 417                         if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
 418                             aniState->firstepLevel - 1))
 419                                 return;
 420                 }
 421         } else {
 422                 rssi = BEACON_RSSI(ahp);
 423                 if (rssi > aniState->rssiThrHigh) {
 424                         /* XXX: Handle me */
 425                         ARN_DBG((ARN_DBG_ANI, "arn: ath9k_ani_reset():\n"));
 426                 } else if (rssi > aniState->rssiThrLow) {
 427                         if (aniState->ofdmWeakSigDetectOff) {
 428                                 if (ath9k_hw_ani_control(ah,
 429                                     ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
 430                                     B_TRUE) == B_TRUE)
 431                                         return;
 432                         }
 433                         if (aniState->firstepLevel > 0) {
 434                                 if (ath9k_hw_ani_control(ah,
 435                                     ATH9K_ANI_FIRSTEP_LEVEL,
 436                                     aniState->firstepLevel - 1) == B_TRUE)
 437                                         return;
 438                         }
 439                 } else {
 440                         if (aniState->firstepLevel > 0) {
 441                                 if (ath9k_hw_ani_control(ah,
 442                                     ATH9K_ANI_FIRSTEP_LEVEL,
 443                                     aniState->firstepLevel - 1) == B_TRUE)
 444                                         return;
 445                         }
 446                 }
 447         }
 448 
 449         if (aniState->spurImmunityLevel > 0) {
 450                 if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
 451                     aniState->spurImmunityLevel - 1))
 452                         return;
 453         }
 454 
 455         if (aniState->noiseImmunityLevel > 0) {
 456                 (void) ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
 457                     aniState->noiseImmunityLevel - 1);
 458                 return;
 459         }
 460 }
 461 
 462 static int32_t
 463 ath9k_hw_ani_get_listen_time(struct ath_hal *ah)
 464 {
 465         struct ath_hal_5416 *ahp = AH5416(ah);
 466         struct ar5416AniState *aniState;
 467         uint32_t txFrameCount, rxFrameCount, cycleCount;
 468         int32_t listenTime;
 469 
 470         txFrameCount = REG_READ(ah, AR_TFCNT);
 471         rxFrameCount = REG_READ(ah, AR_RFCNT);
 472         cycleCount = REG_READ(ah, AR_CCCNT);
 473 
 474         aniState = ahp->ah_curani;
 475         if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) {
 476 
 477                 listenTime = 0;
 478                 ahp->ah_stats.ast_ani_lzero++;
 479         } else {
 480                 int32_t ccdelta = cycleCount - aniState->cycleCount;
 481                 int32_t rfdelta = rxFrameCount - aniState->rxFrameCount;
 482                 int32_t tfdelta = txFrameCount - aniState->txFrameCount;
 483                 listenTime = (ccdelta - rfdelta - tfdelta) / 44000;
 484         }
 485         aniState->cycleCount = cycleCount;
 486         aniState->txFrameCount = txFrameCount;
 487         aniState->rxFrameCount = rxFrameCount;
 488 
 489         return (listenTime);
 490 }
 491 
 492 void
 493 ath9k_ani_reset(struct ath_hal *ah)
 494 {
 495         struct ath_hal_5416 *ahp = AH5416(ah);
 496         struct ar5416AniState *aniState;
 497         struct ath9k_channel *chan = ah->ah_curchan;
 498         int index;
 499 
 500         /* For Lint Reasons */
 501         boolean_t ANI_USE_OFDM_WEAK_SIG = ATH9K_ANI_USE_OFDM_WEAK_SIG;
 502 
 503         if (!DO_ANI(ah))
 504                 return;
 505 
 506         index = ath9k_hw_get_ani_channel_idx(ah, chan);
 507         aniState = &ahp->ah_ani[index];
 508         ahp->ah_curani = aniState;
 509 
 510         if (DO_ANI(ah) && ah->ah_opmode != ATH9K_M_STA &&
 511             ah->ah_opmode != ATH9K_M_IBSS) {
 512                 ARN_DBG((ARN_DBG_ANI, "arn: ath9k_ani_reset(): "
 513                     "Reset ANI state opmode %u\n", ah->ah_opmode));
 514                 ahp->ah_stats.ast_ani_reset++;
 515 
 516                 (void) ath9k_hw_ani_control(ah,
 517                     ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0);
 518                 (void) ath9k_hw_ani_control(ah,
 519                     ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0);
 520                 (void) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0);
 521                 (void) ath9k_hw_ani_control
 522                     (ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
 523                     !ANI_USE_OFDM_WEAK_SIG /* !ATH9K_ANI_USE_OFDM_WEAK_SIG */);
 524                 (void) ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
 525                     ATH9K_ANI_CCK_WEAK_SIG_THR);
 526 
 527                 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
 528                     ATH9K_RX_FILTER_PHYERR);
 529 
 530                 if (ah->ah_opmode == ATH9K_M_HOSTAP) {
 531                         ahp->ah_curani->ofdmTrigHigh =
 532                             ah->ah_config.ofdm_trig_high;
 533                         ahp->ah_curani->ofdmTrigLow =
 534                             ah->ah_config.ofdm_trig_low;
 535                         ahp->ah_curani->cckTrigHigh =
 536                             ah->ah_config.cck_trig_high;
 537                         ahp->ah_curani->cckTrigLow =
 538                             ah->ah_config.cck_trig_low;
 539                 }
 540                 ath9k_ani_restart(ah);
 541                 return;
 542         }
 543 
 544         if (aniState->noiseImmunityLevel != 0)
 545                 (void) ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL,
 546                     aniState->noiseImmunityLevel);
 547         if (aniState->spurImmunityLevel != 0)
 548                 (void) ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL,
 549                     aniState->spurImmunityLevel);
 550         if (aniState->ofdmWeakSigDetectOff)
 551                 (void) ath9k_hw_ani_control
 552                     (ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION,
 553                     !aniState->ofdmWeakSigDetectOff);
 554         if (aniState->cckWeakSigThreshold)
 555                 (void) ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR,
 556                     aniState->cckWeakSigThreshold);
 557         if (aniState->firstepLevel != 0)
 558                 (void) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL,
 559                     aniState->firstepLevel);
 560         if (ahp->ah_hasHwPhyCounters) {
 561                 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) &
 562                     ~ATH9K_RX_FILTER_PHYERR);
 563                 ath9k_ani_restart(ah);
 564                 REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
 565                 REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
 566 
 567         } else {
 568                 ath9k_ani_restart(ah);
 569                 ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) |
 570                     ATH9K_RX_FILTER_PHYERR);
 571         }
 572 }
 573 
 574 /* ARGSUSED */
 575 void
 576 ath9k_hw_ani_monitor(struct ath_hal *ah, const struct ath9k_node_stats *stats,
 577     struct ath9k_channel *chan)
 578 {
 579         struct ath_hal_5416 *ahp = AH5416(ah);
 580         struct ar5416AniState *aniState;
 581         int32_t listenTime;
 582 
 583         aniState = ahp->ah_curani;
 584         ahp->ah_stats.ast_nodestats = *stats;
 585 
 586         listenTime = ath9k_hw_ani_get_listen_time(ah);
 587         if (listenTime < 0) {
 588                 ahp->ah_stats.ast_ani_lneg++;
 589                 ath9k_ani_restart(ah);
 590                 return;
 591         }
 592 
 593         aniState->listenTime += listenTime;
 594 
 595         if (ahp->ah_hasHwPhyCounters) {
 596                 uint32_t phyCnt1, phyCnt2;
 597                 uint32_t ofdmPhyErrCnt, cckPhyErrCnt;
 598 
 599                 ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
 600 
 601                 phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
 602                 phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
 603 
 604                 if (phyCnt1 < aniState->ofdmPhyErrBase ||
 605                     phyCnt2 < aniState->cckPhyErrBase) {
 606                         if (phyCnt1 < aniState->ofdmPhyErrBase) {
 607                                 ARN_DBG((ARN_DBG_ANI, "arn: "
 608                                     "%s: phyCnt1 0x%x, resetting "
 609                                     "counter value to 0x%x\n",
 610                                     __func__, phyCnt1,
 611                                     aniState->ofdmPhyErrBase));
 612                                 REG_WRITE(ah, AR_PHY_ERR_1,
 613                                     aniState->ofdmPhyErrBase);
 614                                 REG_WRITE(ah, AR_PHY_ERR_MASK_1,
 615                                     AR_PHY_ERR_OFDM_TIMING);
 616                         }
 617                         if (phyCnt2 < aniState->cckPhyErrBase) {
 618                                 ARN_DBG((ARN_DBG_ANI, "arn: "
 619                                     "%s: phyCnt2 0x%x, resetting "
 620                                     "counter value to 0x%x\n",
 621                                     __func__, phyCnt2,
 622                                     aniState->cckPhyErrBase));
 623                                 REG_WRITE(ah, AR_PHY_ERR_2,
 624                                     aniState->cckPhyErrBase);
 625                                 REG_WRITE(ah, AR_PHY_ERR_MASK_2,
 626                                     AR_PHY_ERR_CCK_TIMING);
 627                         }
 628                         return;
 629                 }
 630 
 631                 ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
 632                 ahp->ah_stats.ast_ani_ofdmerrs +=
 633                     ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
 634                 aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
 635 
 636                 cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
 637                 ahp->ah_stats.ast_ani_cckerrs +=
 638                     cckPhyErrCnt - aniState->cckPhyErrCount;
 639                 aniState->cckPhyErrCount = cckPhyErrCnt;
 640         }
 641 
 642         if (!DO_ANI(ah))
 643                 return;
 644 
 645         if (aniState->listenTime > 5 * ahp->ah_aniPeriod) {
 646                 if (aniState->ofdmPhyErrCount <= aniState->listenTime *
 647                     aniState->ofdmTrigLow / 1000 &&
 648                     aniState->cckPhyErrCount <= aniState->listenTime *
 649                     aniState->cckTrigLow / 1000)
 650                         ath9k_hw_ani_lower_immunity(ah);
 651                 ath9k_ani_restart(ah);
 652         } else if (aniState->listenTime > ahp->ah_aniPeriod) {
 653                 if (aniState->ofdmPhyErrCount > aniState->listenTime *
 654                     aniState->ofdmTrigHigh / 1000) {
 655                         ath9k_hw_ani_ofdm_err_trigger(ah);
 656                         ath9k_ani_restart(ah);
 657                 } else if (aniState->cckPhyErrCount >
 658                     aniState->listenTime * aniState->cckTrigHigh / 1000) {
 659                         ath9k_hw_ani_cck_err_trigger(ah);
 660                         ath9k_ani_restart(ah);
 661                 }
 662         }
 663 }
 664 
 665 boolean_t
 666 ath9k_hw_phycounters(struct ath_hal *ah)
 667 {
 668         struct ath_hal_5416 *ahp = AH5416(ah);
 669 
 670         return (ahp->ah_hasHwPhyCounters ? B_TRUE : B_FALSE);
 671 }
 672 
 673 void
 674 ath9k_enable_mib_counters(struct ath_hal *ah)
 675 {
 676         struct ath_hal_5416 *ahp = AH5416(ah);
 677 
 678         ARN_DBG((ARN_DBG_ANI, "arn: ath9k_enable_mib_counters(): "
 679             "Enable MIB counters\n"));
 680 
 681         ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
 682 
 683         REG_WRITE(ah, AR_FILT_OFDM, 0);
 684         REG_WRITE(ah, AR_FILT_CCK, 0);
 685         REG_WRITE(ah, AR_MIBC,
 686             ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f);
 687         REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING);
 688         REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
 689 }
 690 
 691 void
 692 ath9k_hw_disable_mib_counters(struct ath_hal *ah)
 693 {
 694         struct ath_hal_5416 *ahp = AH5416(ah);
 695 
 696         ARN_DBG((ARN_DBG_ANI,
 697             "arn: ath9k_hw_disable_mib_counters(): "
 698             "Disable MIB counters\n"));
 699 
 700         REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC);
 701 
 702         ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
 703 
 704         REG_WRITE(ah, AR_FILT_OFDM, 0);
 705         REG_WRITE(ah, AR_FILT_CCK, 0);
 706 }
 707 
 708 uint32_t
 709 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah, uint32_t *rxc_pcnt,
 710     uint32_t *rxf_pcnt, uint32_t *txf_pcnt)
 711 {
 712         static uint32_t cycles, rx_clear, rx_frame, tx_frame;
 713         uint32_t good = 1;
 714 
 715         uint32_t rc = REG_READ(ah, AR_RCCNT);
 716         uint32_t rf = REG_READ(ah, AR_RFCNT);
 717         uint32_t tf = REG_READ(ah, AR_TFCNT);
 718         uint32_t cc = REG_READ(ah, AR_CCCNT);
 719 
 720         if (cycles == 0 || cycles > cc) {
 721                 ARN_DBG((ARN_DBG_CHANNEL,
 722                     "arn: ath9k_hw_GetMibCycleCountsPct(): "
 723                     "cycle counter wrap. ExtBusy = 0\n"));
 724                 good = 0;
 725         } else {
 726                 uint32_t cc_d = cc - cycles;
 727                 uint32_t rc_d = rc - rx_clear;
 728                 uint32_t rf_d = rf - rx_frame;
 729                 uint32_t tf_d = tf - tx_frame;
 730 
 731                 if (cc_d != 0) {
 732                         *rxc_pcnt = rc_d * 100 / cc_d;
 733                         *rxf_pcnt = rf_d * 100 / cc_d;
 734                         *txf_pcnt = tf_d * 100 / cc_d;
 735                 } else {
 736                         good = 0;
 737                 }
 738         }
 739 
 740         cycles = cc;
 741         rx_frame = rf;
 742         rx_clear = rc;
 743         tx_frame = tf;
 744 
 745         return (good);
 746 }
 747 
 748 /*
 749  * Process a MIB interrupt.  We may potentially be invoked because
 750  * any of the MIB counters overflow/trigger so don't assume we're
 751  * here because a PHY error counter triggered.
 752  */
 753 void
 754 ath9k_hw_procmibevent(struct ath_hal *ah,
 755     const struct ath9k_node_stats *stats)
 756 {
 757         struct ath_hal_5416 *ahp = AH5416(ah);
 758         uint32_t phyCnt1, phyCnt2;
 759 
 760         /* Reset these counters regardless */
 761         REG_WRITE(ah, AR_FILT_OFDM, 0);
 762         REG_WRITE(ah, AR_FILT_CCK, 0);
 763         if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING))
 764                 REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR);
 765 
 766         /* Clear the mib counters and save them in the stats */
 767         ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats);
 768         ahp->ah_stats.ast_nodestats = *stats;
 769 
 770         if (!DO_ANI(ah))
 771                 return;
 772 
 773         /* NB: these are not reset-on-read */
 774         phyCnt1 = REG_READ(ah, AR_PHY_ERR_1);
 775         phyCnt2 = REG_READ(ah, AR_PHY_ERR_2);
 776         if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) ||
 777             ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) {
 778                 struct ar5416AniState *aniState = ahp->ah_curani;
 779                 uint32_t ofdmPhyErrCnt, cckPhyErrCnt;
 780 
 781                 /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */
 782                 ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase;
 783                 ahp->ah_stats.ast_ani_ofdmerrs +=
 784                     ofdmPhyErrCnt - aniState->ofdmPhyErrCount;
 785                 aniState->ofdmPhyErrCount = ofdmPhyErrCnt;
 786 
 787                 cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase;
 788                 ahp->ah_stats.ast_ani_cckerrs +=
 789                     cckPhyErrCnt - aniState->cckPhyErrCount;
 790                 aniState->cckPhyErrCount = cckPhyErrCnt;
 791 
 792                 /*
 793                  * NB: figure out which counter triggered.  If both
 794                  * trigger we'll only deal with one as the processing
 795                  * clobbers the error counter so the trigger threshold
 796                  * check will never be true.
 797                  */
 798                 if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh)
 799                         ath9k_hw_ani_ofdm_err_trigger(ah);
 800                 if (aniState->cckPhyErrCount > aniState->cckTrigHigh)
 801                         ath9k_hw_ani_cck_err_trigger(ah);
 802                 /* NB: always restart to insure the h/w counters are reset */
 803                 ath9k_ani_restart(ah);
 804         }
 805 }
 806 
 807 void
 808 ath9k_hw_ani_setup(struct ath_hal *ah)
 809 {
 810         struct ath_hal_5416 *ahp = AH5416(ah);
 811         int i;
 812 
 813         const int totalSizeDesired[] = { -55, -55, -55, -55, -62 };
 814         const int coarseHigh[] = { -14, -14, -14, -14, -12 };
 815         const int coarseLow[] = { -64, -64, -64, -64, -70 };
 816         const int firpwr[] = { -78, -78, -78, -78, -80 };
 817 
 818         for (i = 0; i < 5; i++) {
 819                 ahp->ah_totalSizeDesired[i] = totalSizeDesired[i];
 820                 ahp->ah_coarseHigh[i] = coarseHigh[i];
 821                 ahp->ah_coarseLow[i] = coarseLow[i];
 822                 ahp->ah_firpwr[i] = firpwr[i];
 823         }
 824 }
 825 
 826 void
 827 ath9k_hw_ani_attach(struct ath_hal *ah)
 828 {
 829         struct ath_hal_5416 *ahp = AH5416(ah);
 830         int i;
 831 
 832         /* For Lint Reasons */
 833         boolean_t ANI_USE_OFDM_WEAK_SIG = ATH9K_ANI_USE_OFDM_WEAK_SIG;
 834 
 835         ARN_DBG((ARN_DBG_ANI, "arn: ath9k_hw_ani_attach(): "
 836             "Attach ANI\n"));
 837 
 838         ahp->ah_hasHwPhyCounters = 1;
 839 
 840         (void) memset(ahp->ah_ani, 0, sizeof (ahp->ah_ani));
 841         for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) {
 842                 ahp->ah_ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH;
 843                 ahp->ah_ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW;
 844                 ahp->ah_ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH;
 845                 ahp->ah_ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW;
 846                 ahp->ah_ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH;
 847                 ahp->ah_ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW;
 848                 ahp->ah_ani[i].ofdmWeakSigDetectOff =
 849                     !ANI_USE_OFDM_WEAK_SIG /* !ATH9K_ANI_USE_OFDM_WEAK_SIG */;
 850                 ahp->ah_ani[i].cckWeakSigThreshold =
 851                     ATH9K_ANI_CCK_WEAK_SIG_THR;
 852                 ahp->ah_ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL;
 853                 ahp->ah_ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL;
 854                 if (ahp->ah_hasHwPhyCounters) {
 855                         ahp->ah_ani[i].ofdmPhyErrBase =
 856                             AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH;
 857                         ahp->ah_ani[i].cckPhyErrBase =
 858                             AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH;
 859                 }
 860         }
 861         if (ahp->ah_hasHwPhyCounters) {
 862                 ARN_DBG((ARN_DBG_ANI, "arn: ath9k_hw_ani_attach(): "
 863                     "Setting OfdmErrBase = 0x%08x\n",
 864                     ahp->ah_ani[0].ofdmPhyErrBase));
 865                 ARN_DBG((ARN_DBG_ANI, "arn: ath9k_hw_ani_attach(): "
 866                     "Setting cckErrBase = 0x%08x\n",
 867                     ahp->ah_ani[0].cckPhyErrBase));
 868 
 869                 REG_WRITE(ah, AR_PHY_ERR_1, ahp->ah_ani[0].ofdmPhyErrBase);
 870                 REG_WRITE(ah, AR_PHY_ERR_2, ahp->ah_ani[0].cckPhyErrBase);
 871                 ath9k_enable_mib_counters(ah);
 872         }
 873         ahp->ah_aniPeriod = ATH9K_ANI_PERIOD;
 874         if (ah->ah_config.enable_ani)
 875                 ahp->ah_procPhyErr |= HAL_PROCESS_ANI;
 876 }
 877 
 878 void
 879 ath9k_hw_ani_detach(struct ath_hal *ah)
 880 {
 881         struct ath_hal_5416 *ahp = AH5416(ah);
 882 
 883         ARN_DBG((ARN_DBG_ANI, "arn: ath9k_hw_ani_detach(): "
 884             "Detach ANI\n"));
 885 
 886         if (ahp->ah_hasHwPhyCounters) {
 887                 ath9k_hw_disable_mib_counters(ah);
 888                 REG_WRITE(ah, AR_PHY_ERR_1, 0);
 889                 REG_WRITE(ah, AR_PHY_ERR_2, 0);
 890         }
 891 }