summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath5k/base.c
diff options
context:
space:
mode:
authorNick Kossifidis <mick@madwifi-project.org>2009-08-10 03:31:31 +0300
committerJohn W. Linville <linville@tuxdriver.com>2009-08-14 09:13:56 -0400
commit6e220662bf9a2ba284e88a8c8867340c9f6da27e (patch)
treee834249db58d19ef374c6a4f01e6974055186e2e /drivers/net/wireless/ath/ath5k/base.c
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/ath5k/base.c')
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c36
1 files changed, 26 insertions, 10 deletions
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 0370cba8356..acbcfc2a9f7 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -59,7 +59,7 @@
#include "reg.h"
#include "debug.h"
-static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */
+static u8 ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */
static int modparam_nohwcrypt;
module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
@@ -376,7 +376,7 @@ static int ath5k_stop_hw(struct ath5k_softc *sc);
static irqreturn_t ath5k_intr(int irq, void *dev_id);
static void ath5k_tasklet_reset(unsigned long data);
-static void ath5k_calibrate(unsigned long data);
+static void ath5k_tasklet_calibrate(unsigned long data);
/*
* Module init/exit functions
@@ -799,8 +799,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc);
tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc);
tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc);
+ tasklet_init(&sc->calib, ath5k_tasklet_calibrate, (unsigned long)sc);
tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc);
- setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc);
ret = ath5k_eeprom_read_mac(ah, mac);
if (ret) {
@@ -2364,7 +2364,7 @@ ath5k_init(struct ath5k_softc *sc)
sc->curband = &sc->sbands[sc->curchan->band];
sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL |
AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL |
- AR5K_INT_FATAL | AR5K_INT_GLOBAL;
+ AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_SWI;
ret = ath5k_reset(sc, NULL);
if (ret)
goto done;
@@ -2381,8 +2381,8 @@ ath5k_init(struct ath5k_softc *sc)
/* Set ack to be sent at low bit-rates */
ath5k_hw_set_ack_bitrate_high(ah, false);
- mod_timer(&sc->calib_tim, round_jiffies(jiffies +
- msecs_to_jiffies(ath5k_calinterval * 1000)));
+ /* Set PHY calibration inteval */
+ ah->ah_cal_intval = ath5k_calinterval;
ret = 0;
done:
@@ -2475,10 +2475,10 @@ ath5k_stop_hw(struct ath5k_softc *sc)
mmiowb();
mutex_unlock(&sc->lock);
- del_timer_sync(&sc->calib_tim);
tasklet_kill(&sc->rxtq);
tasklet_kill(&sc->txtq);
tasklet_kill(&sc->restq);
+ tasklet_kill(&sc->calib);
tasklet_kill(&sc->beacontq);
ath5k_rfkill_hw_stop(sc->ah);
@@ -2534,6 +2534,9 @@ ath5k_intr(int irq, void *dev_id)
if (status & AR5K_INT_BMISS) {
/* TODO */
}
+ if (status & AR5K_INT_SWI) {
+ tasklet_schedule(&sc->calib);
+ }
if (status & AR5K_INT_MIB) {
/*
* These stats are also used for ANI i think
@@ -2550,6 +2553,8 @@ ath5k_intr(int irq, void *dev_id)
if (unlikely(!counter))
ATH5K_WARN(sc, "too many interrupts, giving up for now\n");
+ ath5k_hw_calibration_poll(ah);
+
return IRQ_HANDLED;
}
@@ -2566,11 +2571,19 @@ ath5k_tasklet_reset(unsigned long data)
* for temperature/environment changes.
*/
static void
-ath5k_calibrate(unsigned long data)
+ath5k_tasklet_calibrate(unsigned long data)
{
struct ath5k_softc *sc = (void *)data;
struct ath5k_hw *ah = sc->ah;
+ /* Only full calibration for now */
+ if (ah->ah_swi_mask != AR5K_SWI_FULL_CALIBRATION)
+ return;
+
+ /* Stop queues so that calibration
+ * doesn't interfere with tx */
+ ieee80211_stop_queues(sc->hw);
+
ATH5K_DBG(sc, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n",
ieee80211_frequency_to_channel(sc->curchan->center_freq),
sc->curchan->hw_value);
@@ -2588,8 +2601,11 @@ ath5k_calibrate(unsigned long data)
ieee80211_frequency_to_channel(
sc->curchan->center_freq));
- mod_timer(&sc->calib_tim, round_jiffies(jiffies +
- msecs_to_jiffies(ath5k_calinterval * 1000)));
+ ah->ah_swi_mask = 0;
+
+ /* Wake queues */
+ ieee80211_wake_queues(sc->hw);
+
}