aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath5k/base.c
diff options
context:
space:
mode:
authorNick Kossifidis <mickflemm@gmail.com>2011-11-25 13:40:23 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-11-28 14:44:14 -0500
commitce169aca0d823d38465127023e3d571816e6666c (patch)
tree784171700f21de30a04f6154832ce6aca96f2f72 /drivers/net/wireless/ath/ath5k/base.c
parent34ce644aa8342f95eb1e187178f83febade4af37 (diff)
ath5k: Calibration re-work
Noise floor calibration does not interfere with traffic and should run more often as part of our "short calibration". The full calibration is not the noise floor calibration but the AGC + Gain_F (on RF5111 and RF5112) calibration and should run less often because it does interfere with traffic. So Short calibration -> I/Q & NF Calibration Long calibration -> Short + AGC + Gain_F This patch was for some time on my pub/ dir on www.kernel.org and has been tested by a few people and me. I think it's O.K. to go in. I also changed ah_calibration to ah_iq_cal_needed to make more sense. v2 Use a workqueue instead of a tasklet for calibration 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.c112
1 files changed, 78 insertions, 34 deletions
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 47194a4e3652..a8cb1c7f4bfe 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -2112,16 +2112,29 @@ static void
2112ath5k_intr_calibration_poll(struct ath5k_hw *ah) 2112ath5k_intr_calibration_poll(struct ath5k_hw *ah)
2113{ 2113{
2114 if (time_is_before_eq_jiffies(ah->ah_cal_next_ani) && 2114 if (time_is_before_eq_jiffies(ah->ah_cal_next_ani) &&
2115 !(ah->ah_cal_mask & AR5K_CALIBRATION_FULL)) { 2115 !(ah->ah_cal_mask & AR5K_CALIBRATION_FULL) &&
2116 /* run ANI only when full calibration is not active */ 2116 !(ah->ah_cal_mask & AR5K_CALIBRATION_SHORT)) {
2117
2118 /* Run ANI only when calibration is not active */
2119
2117 ah->ah_cal_next_ani = jiffies + 2120 ah->ah_cal_next_ani = jiffies +
2118 msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_ANI); 2121 msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_ANI);
2119 tasklet_schedule(&ah->ani_tasklet); 2122 tasklet_schedule(&ah->ani_tasklet);
2120 2123
2121 } else if (time_is_before_eq_jiffies(ah->ah_cal_next_full)) { 2124 } else if (time_is_before_eq_jiffies(ah->ah_cal_next_short) &&
2122 ah->ah_cal_next_full = jiffies + 2125 !(ah->ah_cal_mask & AR5K_CALIBRATION_FULL) &&
2123 msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_FULL); 2126 !(ah->ah_cal_mask & AR5K_CALIBRATION_SHORT)) {
2124 tasklet_schedule(&ah->calib); 2127
2128 /* Run calibration only when another calibration
2129 * is not running.
2130 *
2131 * Note: This is for both full/short calibration,
2132 * if it's time for a full one, ath5k_calibrate_work will deal
2133 * with it. */
2134
2135 ah->ah_cal_next_short = jiffies +
2136 msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_SHORT);
2137 ieee80211_queue_work(ah->hw, &ah->calib_work);
2125 } 2138 }
2126 /* we could use SWI to generate enough interrupts to meet our 2139 /* we could use SWI to generate enough interrupts to meet our
2127 * calibration interval requirements, if necessary: 2140 * calibration interval requirements, if necessary:
@@ -2286,41 +2299,58 @@ ath5k_intr(int irq, void *dev_id)
2286 * for temperature/environment changes. 2299 * for temperature/environment changes.
2287 */ 2300 */
2288static void 2301static void
2289ath5k_tasklet_calibrate(unsigned long data) 2302ath5k_calibrate_work(struct work_struct *work)
2290{ 2303{
2291 struct ath5k_hw *ah = (void *)data; 2304 struct ath5k_hw *ah = container_of(work, struct ath5k_hw,
2305 calib_work);
2306
2307 /* Should we run a full calibration ? */
2308 if (time_is_before_eq_jiffies(ah->ah_cal_next_full)) {
2309
2310 ah->ah_cal_next_full = jiffies +
2311 msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_FULL);
2312 ah->ah_cal_mask |= AR5K_CALIBRATION_FULL;
2313
2314 ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE,
2315 "running full calibration\n");
2316
2317 if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) {
2318 /*
2319 * Rfgain is out of bounds, reset the chip
2320 * to load new gain values.
2321 */
2322 ATH5K_DBG(ah, ATH5K_DEBUG_RESET,
2323 "got new rfgain, resetting\n");
2324 ieee80211_queue_work(ah->hw, &ah->reset_work);
2325 }
2326
2327 /* TODO: On full calibration we should stop TX here,
2328 * so that it doesn't interfere (mostly due to gain_f
2329 * calibration that messes with tx packets -see phy.c).
2330 *
2331 * NOTE: Stopping the queues from above is not enough
2332 * to stop TX but saves us from disconecting (at least
2333 * we don't lose packets). */
2334 ieee80211_stop_queues(ah->hw);
2335 } else
2336 ah->ah_cal_mask |= AR5K_CALIBRATION_SHORT;
2292 2337
2293 /* Only full calibration for now */
2294 ah->ah_cal_mask |= AR5K_CALIBRATION_FULL;
2295 2338
2296 ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n", 2339 ATH5K_DBG(ah, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n",
2297 ieee80211_frequency_to_channel(ah->curchan->center_freq), 2340 ieee80211_frequency_to_channel(ah->curchan->center_freq),
2298 ah->curchan->hw_value); 2341 ah->curchan->hw_value);
2299 2342
2300 if (ath5k_hw_gainf_calibrate(ah) == AR5K_RFGAIN_NEED_CHANGE) {
2301 /*
2302 * Rfgain is out of bounds, reset the chip
2303 * to load new gain values.
2304 */
2305 ATH5K_DBG(ah, ATH5K_DEBUG_RESET, "calibration, resetting\n");
2306 ieee80211_queue_work(ah->hw, &ah->reset_work);
2307 }
2308 if (ath5k_hw_phy_calibrate(ah, ah->curchan)) 2343 if (ath5k_hw_phy_calibrate(ah, ah->curchan))
2309 ATH5K_ERR(ah, "calibration of channel %u failed\n", 2344 ATH5K_ERR(ah, "calibration of channel %u failed\n",
2310 ieee80211_frequency_to_channel( 2345 ieee80211_frequency_to_channel(
2311 ah->curchan->center_freq)); 2346 ah->curchan->center_freq));
2312 2347
2313 /* Noise floor calibration interrupts rx/tx path while I/Q calibration 2348 /* Clear calibration flags */
2314 * doesn't. 2349 if (ah->ah_cal_mask & AR5K_CALIBRATION_FULL) {
2315 * TODO: We should stop TX here, so that it doesn't interfere. 2350 ieee80211_wake_queues(ah->hw);
2316 * Note that stopping the queues is not enough to stop TX! */ 2351 ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL;
2317 if (time_is_before_eq_jiffies(ah->ah_cal_next_nf)) { 2352 } else if (ah->ah_cal_mask & AR5K_CALIBRATION_SHORT)
2318 ah->ah_cal_next_nf = jiffies + 2353 ah->ah_cal_mask &= ~AR5K_CALIBRATION_SHORT;
2319 msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_NF);
2320 ath5k_hw_update_noise_floor(ah);
2321 }
2322
2323 ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL;
2324} 2354}
2325 2355
2326 2356
@@ -2639,7 +2669,6 @@ static void ath5k_stop_tasklets(struct ath5k_hw *ah)
2639 ah->tx_pending = false; 2669 ah->tx_pending = false;
2640 tasklet_kill(&ah->rxtq); 2670 tasklet_kill(&ah->rxtq);
2641 tasklet_kill(&ah->txtq); 2671 tasklet_kill(&ah->txtq);
2642 tasklet_kill(&ah->calib);
2643 tasklet_kill(&ah->beacontq); 2672 tasklet_kill(&ah->beacontq);
2644 tasklet_kill(&ah->ani_tasklet); 2673 tasklet_kill(&ah->ani_tasklet);
2645} 2674}
@@ -2743,9 +2772,24 @@ ath5k_reset(struct ath5k_hw *ah, struct ieee80211_channel *chan,
2743 2772
2744 ath5k_ani_init(ah, ani_mode); 2773 ath5k_ani_init(ah, ani_mode);
2745 2774
2746 ah->ah_cal_next_full = jiffies + msecs_to_jiffies(100); 2775 /*
2747 ah->ah_cal_next_ani = jiffies; 2776 * Set calibration intervals
2748 ah->ah_cal_next_nf = jiffies; 2777 *
2778 * Note: We don't need to run calibration imediately
2779 * since some initial calibration is done on reset
2780 * even for fast channel switching. Also on scanning
2781 * this will get set again and again and it won't get
2782 * executed unless we connect somewhere and spend some
2783 * time on the channel (that's what calibration needs
2784 * anyway to be accurate).
2785 */
2786 ah->ah_cal_next_full = jiffies +
2787 msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_FULL);
2788 ah->ah_cal_next_ani = jiffies +
2789 msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_ANI);
2790 ah->ah_cal_next_short = jiffies +
2791 msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_SHORT);
2792
2749 ewma_init(&ah->ah_beacon_rssi_avg, 1024, 8); 2793 ewma_init(&ah->ah_beacon_rssi_avg, 1024, 8);
2750 2794
2751 /* clear survey data and cycle counters */ 2795 /* clear survey data and cycle counters */
@@ -2895,11 +2939,11 @@ ath5k_init(struct ieee80211_hw *hw)
2895 2939
2896 tasklet_init(&ah->rxtq, ath5k_tasklet_rx, (unsigned long)ah); 2940 tasklet_init(&ah->rxtq, ath5k_tasklet_rx, (unsigned long)ah);
2897 tasklet_init(&ah->txtq, ath5k_tasklet_tx, (unsigned long)ah); 2941 tasklet_init(&ah->txtq, ath5k_tasklet_tx, (unsigned long)ah);
2898 tasklet_init(&ah->calib, ath5k_tasklet_calibrate, (unsigned long)ah);
2899 tasklet_init(&ah->beacontq, ath5k_tasklet_beacon, (unsigned long)ah); 2942 tasklet_init(&ah->beacontq, ath5k_tasklet_beacon, (unsigned long)ah);
2900 tasklet_init(&ah->ani_tasklet, ath5k_tasklet_ani, (unsigned long)ah); 2943 tasklet_init(&ah->ani_tasklet, ath5k_tasklet_ani, (unsigned long)ah);
2901 2944
2902 INIT_WORK(&ah->reset_work, ath5k_reset_work); 2945 INIT_WORK(&ah->reset_work, ath5k_reset_work);
2946 INIT_WORK(&ah->calib_work, ath5k_calibrate_work);
2903 INIT_DELAYED_WORK(&ah->tx_complete_work, ath5k_tx_complete_poll_work); 2947 INIT_DELAYED_WORK(&ah->tx_complete_work, ath5k_tx_complete_poll_work);
2904 2948
2905 ret = ath5k_hw_common(ah)->bus_ops->eeprom_read_mac(ah, mac); 2949 ret = ath5k_hw_common(ah)->bus_ops->eeprom_read_mac(ah, mac);