aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath
diff options
context:
space:
mode:
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 *