aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorLuis R. Rodriguez <lrodriguez@atheros.com>2008-10-03 18:45:27 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-10-06 18:14:56 -0400
commit6f255425ac3b10c3352c926e7b53e5ea1c364ca4 (patch)
tree529cf0d1d1e9d9fdd8e9d6da67f5d99072872dc4 /drivers/net
parenta477e4e6d48d3ac7c7a75bad40585cb391e5c237 (diff)
ath9k: enable ANI to help with noisy environments
This enables Adaptive Noise Immunity (ANI) on ath9k. ANI is as algorithm designed to minimize the detrimental effects of time-varying interferences. This should help with throughput in noisy environments. To use ANI we re-enable the MIB interrupt. Since ANI works on a timer and updates the noise floor we take advantage of this and also report a non-static noise floor now to mac80211. Signed-off-by: Sujith Manoharan <Sujith.Manoharan@atheros.com> Signed-off-by: Jouni Malinen <Jouni.Malinen@Atheros.com> Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/ath9k/ath9k.h2
-rw-r--r--drivers/net/wireless/ath9k/core.c129
-rw-r--r--drivers/net/wireless/ath9k/core.h25
-rw-r--r--drivers/net/wireless/ath9k/hw.c35
-rw-r--r--drivers/net/wireless/ath9k/main.c18
-rw-r--r--drivers/net/wireless/ath9k/recv.c13
6 files changed, 197 insertions, 25 deletions
diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h
index 0e897c276858..accace5f7efb 100644
--- a/drivers/net/wireless/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath9k/ath9k.h
@@ -854,7 +854,7 @@ bool ath9k_hw_calibrate(struct ath_hal *ah,
854 u8 rxchainmask, 854 u8 rxchainmask,
855 bool longcal, 855 bool longcal,
856 bool *isCalDone); 856 bool *isCalDone);
857int16_t ath9k_hw_getchan_noise(struct ath_hal *ah, 857s16 ath9k_hw_getchan_noise(struct ath_hal *ah,
858 struct ath9k_channel *chan); 858 struct ath9k_channel *chan);
859void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, 859void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid,
860 u16 assocId); 860 u16 assocId);
diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c
index 5af7dfbd423d..c5033f6f42ac 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
505static 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;
diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h
index 5b4f1c48a618..cb3e61e57c4d 100644
--- a/drivers/net/wireless/ath9k/core.h
+++ b/drivers/net/wireless/ath9k/core.h
@@ -800,6 +800,28 @@ void ath_slow_ant_div(struct ath_antdiv *antdiv,
800 struct ath_rx_status *rx_stats); 800 struct ath_rx_status *rx_stats);
801void ath_setdefantenna(void *sc, u32 antenna); 801void ath_setdefantenna(void *sc, u32 antenna);
802 802
803/*******/
804/* ANI */
805/*******/
806
807/* ANI values for STA only.
808 FIXME: Add appropriate values for AP later */
809
810#define ATH_ANI_POLLINTERVAL 100 /* 100 milliseconds between ANI poll */
811#define ATH_SHORT_CALINTERVAL 1000 /* 1 second between calibrations */
812#define ATH_LONG_CALINTERVAL 30000 /* 30 seconds between calibrations */
813#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes between calibrations */
814
815struct ath_ani {
816 bool sc_caldone;
817 int16_t sc_noise_floor;
818 unsigned int sc_longcal_timer;
819 unsigned int sc_shortcal_timer;
820 unsigned int sc_resetcal_timer;
821 unsigned int sc_checkani_timer;
822 struct timer_list timer;
823};
824
803/********************/ 825/********************/
804/* LED Control */ 826/* LED Control */
805/********************/ 827/********************/
@@ -1028,6 +1050,9 @@ struct ath_softc {
1028 1050
1029 /* Rfkill */ 1051 /* Rfkill */
1030 struct ath_rfkill rf_kill; 1052 struct ath_rfkill rf_kill;
1053
1054 /* ANI */
1055 struct ath_ani sc_ani;
1031}; 1056};
1032 1057
1033int ath_init(u16 devid, struct ath_softc *sc); 1058int ath_init(u16 devid, struct ath_softc *sc);
diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c
index 272c75816609..62e44a0ef996 100644
--- a/drivers/net/wireless/ath9k/hw.c
+++ b/drivers/net/wireless/ath9k/hw.c
@@ -329,7 +329,7 @@ static void ath9k_hw_set_defaults(struct ath_hal *ah)
329 ah->ah_config.ofdm_trig_high = 500; 329 ah->ah_config.ofdm_trig_high = 500;
330 ah->ah_config.cck_trig_high = 200; 330 ah->ah_config.cck_trig_high = 200;
331 ah->ah_config.cck_trig_low = 100; 331 ah->ah_config.cck_trig_low = 100;
332 ah->ah_config.enable_ani = 0; 332 ah->ah_config.enable_ani = 1;
333 ah->ah_config.noise_immunity_level = 4; 333 ah->ah_config.noise_immunity_level = 4;
334 ah->ah_config.ofdm_weaksignal_det = 1; 334 ah->ah_config.ofdm_weaksignal_det = 1;
335 ah->ah_config.cck_weaksignal_thr = 0; 335 ah->ah_config.cck_weaksignal_thr = 0;
@@ -8405,23 +8405,48 @@ u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags)
8405 } 8405 }
8406} 8406}
8407 8407
8408int16_t 8408/* We can tune this as we go by monitoring really low values */
8409#define ATH9K_NF_TOO_LOW -60
8410
8411/* AR5416 may return very high value (like -31 dBm), in those cases the nf
8412 * is incorrect and we should use the static NF value. Later we can try to
8413 * find out why they are reporting these values */
8414static bool ath9k_hw_nf_in_range(struct ath_hal *ah, s16 nf)
8415{
8416 if (nf > ATH9K_NF_TOO_LOW) {
8417 DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
8418 "%s: noise floor value detected (%d) is "
8419 "lower than what we think is a "
8420 "reasonable value (%d)\n",
8421 __func__, nf, ATH9K_NF_TOO_LOW);
8422 return false;
8423 }
8424 return true;
8425}
8426
8427s16
8409ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan) 8428ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan)
8410{ 8429{
8411 struct ath9k_channel *ichan; 8430 struct ath9k_channel *ichan;
8431 s16 nf;
8412 8432
8413 ichan = ath9k_regd_check_channel(ah, chan); 8433 ichan = ath9k_regd_check_channel(ah, chan);
8414 if (ichan == NULL) { 8434 if (ichan == NULL) {
8415 DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, 8435 DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL,
8416 "%s: invalid channel %u/0x%x; no mapping\n", 8436 "%s: invalid channel %u/0x%x; no mapping\n",
8417 __func__, chan->channel, chan->channelFlags); 8437 __func__, chan->channel, chan->channelFlags);
8418 return 0; 8438 return ATH_DEFAULT_NOISE_FLOOR;
8419 } 8439 }
8420 if (ichan->rawNoiseFloor == 0) { 8440 if (ichan->rawNoiseFloor == 0) {
8421 enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan); 8441 enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan);
8422 return NOISE_FLOOR[mode]; 8442 nf = NOISE_FLOOR[mode];
8423 } else 8443 } else
8424 return ichan->rawNoiseFloor; 8444 nf = ichan->rawNoiseFloor;
8445
8446 if (!ath9k_hw_nf_in_range(ah, nf))
8447 nf = ATH_DEFAULT_NOISE_FLOOR;
8448
8449 return nf;
8425} 8450}
8426 8451
8427bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting) 8452bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting)
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index 2caba4403167..74726990d59e 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -274,10 +274,12 @@ static void ath9k_rx_prepare(struct ath_softc *sc,
274 rx_status->mactime = status->tsf; 274 rx_status->mactime = status->tsf;
275 rx_status->band = curchan->band; 275 rx_status->band = curchan->band;
276 rx_status->freq = curchan->center_freq; 276 rx_status->freq = curchan->center_freq;
277 rx_status->noise = ATH_DEFAULT_NOISE_FLOOR; 277 rx_status->noise = sc->sc_ani.sc_noise_floor;
278 rx_status->signal = rx_status->noise + status->rssi; 278 rx_status->signal = rx_status->noise + status->rssi;
279 rx_status->rate_idx = ath_rate2idx(sc, (status->rateKbps / 100)); 279 rx_status->rate_idx = ath_rate2idx(sc, (status->rateKbps / 100));
280 rx_status->antenna = status->antenna; 280 rx_status->antenna = status->antenna;
281
282 /* XXX Fix me, 64 cannot be the max rssi value, rigure it out */
281 rx_status->qual = status->rssi * 100 / 64; 283 rx_status->qual = status->rssi * 100 / 64;
282 284
283 if (status->flags & ATH_RX_MIC_ERROR) 285 if (status->flags & ATH_RX_MIC_ERROR)
@@ -427,6 +429,11 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
427 ath_rate_newstate(sc, avp); 429 ath_rate_newstate(sc, avp);
428 /* Update ratectrl about the new state */ 430 /* Update ratectrl about the new state */
429 ath_rc_node_update(hw, avp->rc_node); 431 ath_rc_node_update(hw, avp->rc_node);
432
433 /* Start ANI */
434 mod_timer(&sc->sc_ani.timer,
435 jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
436
430 } else { 437 } else {
431 DPRINTF(sc, ATH_DBG_CONFIG, 438 DPRINTF(sc, ATH_DBG_CONFIG,
432 "%s: Bss Info DISSOC\n", __func__); 439 "%s: Bss Info DISSOC\n", __func__);
@@ -1173,6 +1180,13 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
1173 return error; 1180 return error;
1174 } 1181 }
1175 1182
1183 if (conf->type == NL80211_IFTYPE_AP) {
1184 /* TODO: is this a suitable place to start ANI for AP mode? */
1185 /* Start ANI */
1186 mod_timer(&sc->sc_ani.timer,
1187 jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
1188 }
1189
1176 return 0; 1190 return 0;
1177} 1191}
1178 1192
@@ -1195,6 +1209,8 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
1195#ifdef CONFIG_SLOW_ANT_DIV 1209#ifdef CONFIG_SLOW_ANT_DIV
1196 ath_slow_ant_div_stop(&sc->sc_antdiv); 1210 ath_slow_ant_div_stop(&sc->sc_antdiv);
1197#endif 1211#endif
1212 /* Stop ANI */
1213 del_timer_sync(&sc->sc_ani.timer);
1198 1214
1199 /* Update ratectrl */ 1215 /* Update ratectrl */
1200 ath_rate_newstate(sc, avp); 1216 ath_rate_newstate(sc, avp);
diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c
index f4be5d11c9d5..4983402af559 100644
--- a/drivers/net/wireless/ath9k/recv.c
+++ b/drivers/net/wireless/ath9k/recv.c
@@ -999,20 +999,11 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
999 rx_status.flags |= ATH_RX_SHORT_GI; 999 rx_status.flags |= ATH_RX_SHORT_GI;
1000 } 1000 }
1001 1001
1002 /* sc->sc_noise_floor is only available when the station 1002 /* sc_noise_floor is only available when the station
1003 attaches to an AP, so we use a default value 1003 attaches to an AP, so we use a default value
1004 if we are not yet attached. */ 1004 if we are not yet attached. */
1005
1006 /* XXX we should use either sc->sc_noise_floor or
1007 * ath_hal_getChanNoise(ah, &sc->sc_curchan)
1008 * to calculate the noise floor.
1009 * However, the value returned by ath_hal_getChanNoise
1010 * seems to be incorrect (-31dBm on the last test),
1011 * so we will use a hard-coded value until we
1012 * figure out what is going on.
1013 */
1014 rx_status.abs_rssi = 1005 rx_status.abs_rssi =
1015 ds->ds_rxstat.rs_rssi + ATH_DEFAULT_NOISE_FLOOR; 1006 ds->ds_rxstat.rs_rssi + sc->sc_ani.sc_noise_floor;
1016 1007
1017 pci_dma_sync_single_for_cpu(sc->pdev, 1008 pci_dma_sync_single_for_cpu(sc->pdev,
1018 bf->bf_buf_addr, 1009 bf->bf_buf_addr,