diff options
Diffstat (limited to 'drivers/net/wireless/ath9k/core.c')
-rw-r--r-- | drivers/net/wireless/ath9k/core.c | 129 |
1 files changed, 122 insertions, 7 deletions
diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c index 5af7dfbd423..c5033f6f42a 100644 --- a/drivers/net/wireless/ath9k/core.c +++ b/drivers/net/wireless/ath9k/core.c | |||
@@ -490,6 +490,122 @@ void ath_update_chainmask(struct ath_softc *sc, int is_ht) | |||
490 | __func__, sc->sc_tx_chainmask, sc->sc_rx_chainmask); | 490 | __func__, sc->sc_tx_chainmask, sc->sc_rx_chainmask); |
491 | } | 491 | } |
492 | 492 | ||
493 | /*******/ | ||
494 | /* ANI */ | ||
495 | /*******/ | ||
496 | |||
497 | /* | ||
498 | * This routine performs the periodic noise floor calibration function | ||
499 | * that is used to adjust and optimize the chip performance. This | ||
500 | * takes environmental changes (location, temperature) into account. | ||
501 | * When the task is complete, it reschedules itself depending on the | ||
502 | * appropriate interval that was calculated. | ||
503 | */ | ||
504 | |||
505 | static void ath_ani_calibrate(unsigned long data) | ||
506 | { | ||
507 | struct ath_softc *sc; | ||
508 | struct ath_hal *ah; | ||
509 | bool longcal = false; | ||
510 | bool shortcal = false; | ||
511 | bool aniflag = false; | ||
512 | unsigned int timestamp = jiffies_to_msecs(jiffies); | ||
513 | u32 cal_interval; | ||
514 | |||
515 | sc = (struct ath_softc *)data; | ||
516 | ah = sc->sc_ah; | ||
517 | |||
518 | /* | ||
519 | * don't calibrate when we're scanning. | ||
520 | * we are most likely not on our home channel. | ||
521 | */ | ||
522 | if (sc->rx_filter & FIF_BCN_PRBRESP_PROMISC) | ||
523 | return; | ||
524 | |||
525 | /* Long calibration runs independently of short calibration. */ | ||
526 | if ((timestamp - sc->sc_ani.sc_longcal_timer) >= ATH_LONG_CALINTERVAL) { | ||
527 | longcal = true; | ||
528 | DPRINTF(sc, ATH_DBG_ANI, "%s: longcal @%lu\n", | ||
529 | __func__, jiffies); | ||
530 | sc->sc_ani.sc_longcal_timer = timestamp; | ||
531 | } | ||
532 | |||
533 | /* Short calibration applies only while sc_caldone is false */ | ||
534 | if (!sc->sc_ani.sc_caldone) { | ||
535 | if ((timestamp - sc->sc_ani.sc_shortcal_timer) >= | ||
536 | ATH_SHORT_CALINTERVAL) { | ||
537 | shortcal = true; | ||
538 | DPRINTF(sc, ATH_DBG_ANI, "%s: shortcal @%lu\n", | ||
539 | __func__, jiffies); | ||
540 | sc->sc_ani.sc_shortcal_timer = timestamp; | ||
541 | sc->sc_ani.sc_resetcal_timer = timestamp; | ||
542 | } | ||
543 | } else { | ||
544 | if ((timestamp - sc->sc_ani.sc_resetcal_timer) >= | ||
545 | ATH_RESTART_CALINTERVAL) { | ||
546 | ath9k_hw_reset_calvalid(ah, ah->ah_curchan, | ||
547 | &sc->sc_ani.sc_caldone); | ||
548 | if (sc->sc_ani.sc_caldone) | ||
549 | sc->sc_ani.sc_resetcal_timer = timestamp; | ||
550 | } | ||
551 | } | ||
552 | |||
553 | /* Verify whether we must check ANI */ | ||
554 | if ((timestamp - sc->sc_ani.sc_checkani_timer) >= | ||
555 | ATH_ANI_POLLINTERVAL) { | ||
556 | aniflag = true; | ||
557 | sc->sc_ani.sc_checkani_timer = timestamp; | ||
558 | } | ||
559 | |||
560 | /* Skip all processing if there's nothing to do. */ | ||
561 | if (longcal || shortcal || aniflag) { | ||
562 | /* Call ANI routine if necessary */ | ||
563 | if (aniflag) | ||
564 | ath9k_hw_ani_monitor(ah, &sc->sc_halstats, | ||
565 | ah->ah_curchan); | ||
566 | |||
567 | /* Perform calibration if necessary */ | ||
568 | if (longcal || shortcal) { | ||
569 | bool iscaldone = false; | ||
570 | |||
571 | if (ath9k_hw_calibrate(ah, ah->ah_curchan, | ||
572 | sc->sc_rx_chainmask, longcal, | ||
573 | &iscaldone)) { | ||
574 | if (longcal) | ||
575 | sc->sc_ani.sc_noise_floor = | ||
576 | ath9k_hw_getchan_noise(ah, | ||
577 | ah->ah_curchan); | ||
578 | |||
579 | DPRINTF(sc, ATH_DBG_ANI, | ||
580 | "%s: calibrate chan %u/%x nf: %d\n", | ||
581 | __func__, | ||
582 | ah->ah_curchan->channel, | ||
583 | ah->ah_curchan->channelFlags, | ||
584 | sc->sc_ani.sc_noise_floor); | ||
585 | } else { | ||
586 | DPRINTF(sc, ATH_DBG_ANY, | ||
587 | "%s: calibrate chan %u/%x failed\n", | ||
588 | __func__, | ||
589 | ah->ah_curchan->channel, | ||
590 | ah->ah_curchan->channelFlags); | ||
591 | } | ||
592 | sc->sc_ani.sc_caldone = iscaldone; | ||
593 | } | ||
594 | } | ||
595 | |||
596 | /* | ||
597 | * Set timer interval based on previous results. | ||
598 | * The interval must be the shortest necessary to satisfy ANI, | ||
599 | * short calibration and long calibration. | ||
600 | */ | ||
601 | |||
602 | cal_interval = ATH_ANI_POLLINTERVAL; | ||
603 | if (!sc->sc_ani.sc_caldone) | ||
604 | cal_interval = min(cal_interval, (u32)ATH_SHORT_CALINTERVAL); | ||
605 | |||
606 | mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(cal_interval)); | ||
607 | } | ||
608 | |||
493 | /******************/ | 609 | /******************/ |
494 | /* VAP management */ | 610 | /* VAP management */ |
495 | /******************/ | 611 | /******************/ |
@@ -676,12 +792,6 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) | |||
676 | if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) | 792 | if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) |
677 | sc->sc_imask |= ATH9K_INT_CST; | 793 | sc->sc_imask |= ATH9K_INT_CST; |
678 | 794 | ||
679 | /* Note: We disable MIB interrupts for now as we don't yet | ||
680 | * handle processing ANI, otherwise you will get an interrupt | ||
681 | * storm after about 7 hours of usage making the system unusable | ||
682 | * with huge latency. Once we do have ANI processing included | ||
683 | * we can re-enable this interrupt. */ | ||
684 | #if 0 | ||
685 | /* | 795 | /* |
686 | * Enable MIB interrupts when there are hardware phy counters. | 796 | * Enable MIB interrupts when there are hardware phy counters. |
687 | * Note we only do this (at the moment) for station mode. | 797 | * Note we only do this (at the moment) for station mode. |
@@ -690,7 +800,6 @@ int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) | |||
690 | ((sc->sc_ah->ah_opmode == ATH9K_M_STA) || | 800 | ((sc->sc_ah->ah_opmode == ATH9K_M_STA) || |
691 | (sc->sc_ah->ah_opmode == ATH9K_M_IBSS))) | 801 | (sc->sc_ah->ah_opmode == ATH9K_M_IBSS))) |
692 | sc->sc_imask |= ATH9K_INT_MIB; | 802 | sc->sc_imask |= ATH9K_INT_MIB; |
693 | #endif | ||
694 | /* | 803 | /* |
695 | * Some hardware processes the TIM IE and fires an | 804 | * Some hardware processes the TIM IE and fires an |
696 | * interrupt when the TIM bit is set. For hardware | 805 | * interrupt when the TIM bit is set. For hardware |
@@ -991,6 +1100,10 @@ int ath_init(u16 devid, struct ath_softc *sc) | |||
991 | } | 1100 | } |
992 | sc->sc_ah = ah; | 1101 | sc->sc_ah = ah; |
993 | 1102 | ||
1103 | /* Initializes the noise floor to a reasonable default value. | ||
1104 | * Later on this will be updated during ANI processing. */ | ||
1105 | sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR; | ||
1106 | |||
994 | /* Get the hardware key cache size. */ | 1107 | /* Get the hardware key cache size. */ |
995 | sc->sc_keymax = ah->ah_caps.keycache_size; | 1108 | sc->sc_keymax = ah->ah_caps.keycache_size; |
996 | if (sc->sc_keymax > ATH_KEYMAX) { | 1109 | if (sc->sc_keymax > ATH_KEYMAX) { |
@@ -1098,6 +1211,8 @@ int ath_init(u16 devid, struct ath_softc *sc) | |||
1098 | goto bad2; | 1211 | goto bad2; |
1099 | } | 1212 | } |
1100 | 1213 | ||
1214 | setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc); | ||
1215 | |||
1101 | sc->sc_rc = ath_rate_attach(ah); | 1216 | sc->sc_rc = ath_rate_attach(ah); |
1102 | if (sc->sc_rc == NULL) { | 1217 | if (sc->sc_rc == NULL) { |
1103 | error = -EIO; | 1218 | error = -EIO; |