aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath
diff options
context:
space:
mode:
authorNick Kossifidis <mick@madwifi-project.org>2009-08-09 20:31:31 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-14 09:13:56 -0400
commit6e220662bf9a2ba284e88a8c8867340c9f6da27e (patch)
treee834249db58d19ef374c6a4f01e6974055186e2e /drivers/net/wireless/ath
parentb55a5de114dcdc03f2f18c3bd98bbabb13ee53ef (diff)
ath5k: Use SWI to trigger calibration
* Get rid of calibration timer, instead use a software interrupt to schedule the calibration tasklet. a) We don't need a timer for this, there is no need for accuracy even with round_jiffies i think this is a waste of resources. Also we don't need to run calibration if we are idle (no interrupts). b) When we add ANI support we 'll just extend the poll function and calibration tasklet and handle all periodic phy calibration on one place (much cleaner). c) Having calibration on a tasklet is better since during calibration we can't transmit or receive (antennas are detached to measure noise floor), previously calibration could run in parallel with tx/rx and interfere (packet loss). v2: kill tasklet on stop_hw, stop/wake queues v3: use time_is_before_eq_jiffies to compare timestamp with current time Signed-off-by: Nick Kossifidis <mickflemm@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h16
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c36
-rw-r--r--drivers/net/wireless/ath/ath5k/base.h3
-rw-r--r--drivers/net/wireless/ath/ath5k/phy.c23
4 files changed, 67 insertions, 11 deletions
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 1047a6cb1d92..c09402eea7f3 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -919,6 +919,12 @@ enum ath5k_int {
919 AR5K_INT_NOCARD = 0xffffffff 919 AR5K_INT_NOCARD = 0xffffffff
920}; 920};
921 921
922/* Software interrupts used for calibration */
923enum ath5k_software_interrupt {
924 AR5K_SWI_FULL_CALIBRATION = 0x01,
925 AR5K_SWI_SHORT_CALIBRATION = 0x02,
926};
927
922/* 928/*
923 * Power management 929 * Power management
924 */ 930 */
@@ -1123,6 +1129,15 @@ struct ath5k_hw {
1123 /* noise floor from last periodic calibration */ 1129 /* noise floor from last periodic calibration */
1124 s32 ah_noise_floor; 1130 s32 ah_noise_floor;
1125 1131
1132 /* Calibration timestamp */
1133 unsigned long ah_cal_tstamp;
1134
1135 /* Calibration interval (secs) */
1136 u8 ah_cal_intval;
1137
1138 /* Software interrupt mask */
1139 u8 ah_swi_mask;
1140
1126 /* 1141 /*
1127 * Function pointers 1142 * Function pointers
1128 */ 1143 */
@@ -1276,6 +1291,7 @@ extern int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *chann
1276/* PHY calibration */ 1291/* PHY calibration */
1277extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel); 1292extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel);
1278extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq); 1293extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq);
1294extern void ath5k_hw_calibration_poll(struct ath5k_hw *ah);
1279/* Spur mitigation */ 1295/* Spur mitigation */
1280bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, 1296bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
1281 struct ieee80211_channel *channel); 1297 struct ieee80211_channel *channel);
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 0370cba8356c..acbcfc2a9f71 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -59,7 +59,7 @@
59#include "reg.h" 59#include "reg.h"
60#include "debug.h" 60#include "debug.h"
61 61
62static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */ 62static u8 ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */
63static int modparam_nohwcrypt; 63static int modparam_nohwcrypt;
64module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); 64module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
65MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); 65MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
@@ -376,7 +376,7 @@ static int ath5k_stop_hw(struct ath5k_softc *sc);
376static irqreturn_t ath5k_intr(int irq, void *dev_id); 376static irqreturn_t ath5k_intr(int irq, void *dev_id);
377static void ath5k_tasklet_reset(unsigned long data); 377static void ath5k_tasklet_reset(unsigned long data);
378 378
379static void ath5k_calibrate(unsigned long data); 379static void ath5k_tasklet_calibrate(unsigned long data);
380 380
381/* 381/*
382 * Module init/exit functions 382 * Module init/exit functions
@@ -799,8 +799,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
799 tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc); 799 tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc);
800 tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc); 800 tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc);
801 tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc); 801 tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc);
802 tasklet_init(&sc->calib, ath5k_tasklet_calibrate, (unsigned long)sc);
802 tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc); 803 tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc);
803 setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc);
804 804
805 ret = ath5k_eeprom_read_mac(ah, mac); 805 ret = ath5k_eeprom_read_mac(ah, mac);
806 if (ret) { 806 if (ret) {
@@ -2364,7 +2364,7 @@ ath5k_init(struct ath5k_softc *sc)
2364 sc->curband = &sc->sbands[sc->curchan->band]; 2364 sc->curband = &sc->sbands[sc->curchan->band];
2365 sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | 2365 sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL |
2366 AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | 2366 AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL |
2367 AR5K_INT_FATAL | AR5K_INT_GLOBAL; 2367 AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_SWI;
2368 ret = ath5k_reset(sc, NULL); 2368 ret = ath5k_reset(sc, NULL);
2369 if (ret) 2369 if (ret)
2370 goto done; 2370 goto done;
@@ -2381,8 +2381,8 @@ ath5k_init(struct ath5k_softc *sc)
2381 /* Set ack to be sent at low bit-rates */ 2381 /* Set ack to be sent at low bit-rates */
2382 ath5k_hw_set_ack_bitrate_high(ah, false); 2382 ath5k_hw_set_ack_bitrate_high(ah, false);
2383 2383
2384 mod_timer(&sc->calib_tim, round_jiffies(jiffies + 2384 /* Set PHY calibration inteval */
2385 msecs_to_jiffies(ath5k_calinterval * 1000))); 2385 ah->ah_cal_intval = ath5k_calinterval;
2386 2386
2387 ret = 0; 2387 ret = 0;
2388done: 2388done:
@@ -2475,10 +2475,10 @@ ath5k_stop_hw(struct ath5k_softc *sc)
2475 mmiowb(); 2475 mmiowb();
2476 mutex_unlock(&sc->lock); 2476 mutex_unlock(&sc->lock);
2477 2477
2478 del_timer_sync(&sc->calib_tim);
2479 tasklet_kill(&sc->rxtq); 2478 tasklet_kill(&sc->rxtq);
2480 tasklet_kill(&sc->txtq); 2479 tasklet_kill(&sc->txtq);
2481 tasklet_kill(&sc->restq); 2480 tasklet_kill(&sc->restq);
2481 tasklet_kill(&sc->calib);
2482 tasklet_kill(&sc->beacontq); 2482 tasklet_kill(&sc->beacontq);
2483 2483
2484 ath5k_rfkill_hw_stop(sc->ah); 2484 ath5k_rfkill_hw_stop(sc->ah);
@@ -2534,6 +2534,9 @@ ath5k_intr(int irq, void *dev_id)
2534 if (status & AR5K_INT_BMISS) { 2534 if (status & AR5K_INT_BMISS) {
2535 /* TODO */ 2535 /* TODO */
2536 } 2536 }
2537 if (status & AR5K_INT_SWI) {
2538 tasklet_schedule(&sc->calib);
2539 }
2537 if (status & AR5K_INT_MIB) { 2540 if (status & AR5K_INT_MIB) {
2538 /* 2541 /*
2539 * These stats are also used for ANI i think 2542 * These stats are also used for ANI i think
@@ -2550,6 +2553,8 @@ ath5k_intr(int irq, void *dev_id)
2550 if (unlikely(!counter)) 2553 if (unlikely(!counter))
2551 ATH5K_WARN(sc, "too many interrupts, giving up for now\n"); 2554 ATH5K_WARN(sc, "too many interrupts, giving up for now\n");
2552 2555
2556 ath5k_hw_calibration_poll(ah);
2557
2553 return IRQ_HANDLED; 2558 return IRQ_HANDLED;
2554} 2559}
2555 2560
@@ -2566,11 +2571,19 @@ ath5k_tasklet_reset(unsigned long data)
2566 * for temperature/environment changes. 2571 * for temperature/environment changes.
2567 */ 2572 */
2568static void 2573static void
2569ath5k_calibrate(unsigned long data) 2574ath5k_tasklet_calibrate(unsigned long data)
2570{ 2575{
2571 struct ath5k_softc *sc = (void *)data; 2576 struct ath5k_softc *sc = (void *)data;
2572 struct ath5k_hw *ah = sc->ah; 2577 struct ath5k_hw *ah = sc->ah;
2573 2578
2579 /* Only full calibration for now */
2580 if (ah->ah_swi_mask != AR5K_SWI_FULL_CALIBRATION)
2581 return;
2582
2583 /* Stop queues so that calibration
2584 * doesn't interfere with tx */
2585 ieee80211_stop_queues(sc->hw);
2586
2574 ATH5K_DBG(sc, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n", 2587 ATH5K_DBG(sc, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n",
2575 ieee80211_frequency_to_channel(sc->curchan->center_freq), 2588 ieee80211_frequency_to_channel(sc->curchan->center_freq),
2576 sc->curchan->hw_value); 2589 sc->curchan->hw_value);
@@ -2588,8 +2601,11 @@ ath5k_calibrate(unsigned long data)
2588 ieee80211_frequency_to_channel( 2601 ieee80211_frequency_to_channel(
2589 sc->curchan->center_freq)); 2602 sc->curchan->center_freq));
2590 2603
2591 mod_timer(&sc->calib_tim, round_jiffies(jiffies + 2604 ah->ah_swi_mask = 0;
2592 msecs_to_jiffies(ath5k_calinterval * 1000))); 2605
2606 /* Wake queues */
2607 ieee80211_wake_queues(sc->hw);
2608
2593} 2609}
2594 2610
2595 2611
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index 778e422946ab..667bd9dc1900 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -177,6 +177,8 @@ struct ath5k_softc {
177 177
178 struct ath5k_rfkill rf_kill; 178 struct ath5k_rfkill rf_kill;
179 179
180 struct tasklet_struct calib; /* calibration tasklet */
181
180 spinlock_t block; /* protects beacon */ 182 spinlock_t block; /* protects beacon */
181 struct tasklet_struct beacontq; /* beacon intr tasklet */ 183 struct tasklet_struct beacontq; /* beacon intr tasklet */
182 struct ath5k_buf *bbuf; /* beacon buffer */ 184 struct ath5k_buf *bbuf; /* beacon buffer */
@@ -187,7 +189,6 @@ struct ath5k_softc {
187 unsigned int nexttbtt; /* next beacon time in TU */ 189 unsigned int nexttbtt; /* next beacon time in TU */
188 struct ath5k_txq *cabq; /* content after beacon */ 190 struct ath5k_txq *cabq; /* content after beacon */
189 191
190 struct timer_list calib_tim; /* calibration timer */
191 int power_level; /* Requested tx power in dbm */ 192 int power_level; /* Requested tx power in dbm */
192 bool assoc; /* assocate state */ 193 bool assoc; /* assocate state */
193 bool enable_beacon; /* true if beacons are on */ 194 bool enable_beacon; /* true if beacons are on */
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index 6afba98f6adb..298fcf015227 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -1104,6 +1104,29 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
1104 PHY calibration 1104 PHY calibration
1105\*****************/ 1105\*****************/
1106 1106
1107void
1108ath5k_hw_calibration_poll(struct ath5k_hw *ah)
1109{
1110 /* Calibration interval in jiffies */
1111 unsigned long cal_intval;
1112
1113 cal_intval = msecs_to_jiffies(ah->ah_cal_intval * 1000);
1114
1115 /* Initialize timestamp if needed */
1116 if (!ah->ah_cal_tstamp)
1117 ah->ah_cal_tstamp = jiffies;
1118
1119 /* For now we always do full calibration
1120 * Mark software interrupt mask and fire software
1121 * interrupt (bit gets auto-cleared) */
1122 if (time_is_before_eq_jiffies(ah->ah_cal_tstamp + cal_intval)) {
1123 ah->ah_cal_tstamp = jiffies;
1124 ah->ah_swi_mask = AR5K_SWI_FULL_CALIBRATION;
1125 AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI);
1126 }
1127
1128}
1129
1107/** 1130/**
1108 * ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration 1131 * ath5k_hw_noise_floor_calibration - perform PHY noise floor calibration
1109 * 1132 *