diff options
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r-- | drivers/net/wireless/ath/ath5k/ath5k.h | 16 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/base.c | 36 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/base.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath5k/phy.c | 23 |
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 */ | ||
923 | enum 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 */ |
1277 | extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel); | 1292 | extern int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, struct ieee80211_channel *channel); |
1278 | extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq); | 1293 | extern int ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq); |
1294 | extern void ath5k_hw_calibration_poll(struct ath5k_hw *ah); | ||
1279 | /* Spur mitigation */ | 1295 | /* Spur mitigation */ |
1280 | bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah, | 1296 | bool 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 | ||
62 | static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */ | 62 | static u8 ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */ |
63 | static int modparam_nohwcrypt; | 63 | static int modparam_nohwcrypt; |
64 | module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); | 64 | module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); |
65 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); | 65 | MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); |
@@ -376,7 +376,7 @@ static int ath5k_stop_hw(struct ath5k_softc *sc); | |||
376 | static irqreturn_t ath5k_intr(int irq, void *dev_id); | 376 | static irqreturn_t ath5k_intr(int irq, void *dev_id); |
377 | static void ath5k_tasklet_reset(unsigned long data); | 377 | static void ath5k_tasklet_reset(unsigned long data); |
378 | 378 | ||
379 | static void ath5k_calibrate(unsigned long data); | 379 | static 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; |
2388 | done: | 2388 | done: |
@@ -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 | */ |
2568 | static void | 2573 | static void |
2569 | ath5k_calibrate(unsigned long data) | 2574 | ath5k_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 | ||
1107 | void | ||
1108 | ath5k_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 | * |