aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2010-07-30 18:12:01 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-08-04 15:27:37 -0400
commit4254bc1c4d7b53ac10e558dfe015725fdd693da4 (patch)
tree51c95b3f0f24ff8e1fabf698524c9ddd9f069879 /drivers/net/wireless
parent20bd2a0952d01ba82a99b3f22d46e3832c255529 (diff)
ath9k_hw: fix a noise floor calibration related race condition
On AR5008-AR9002, other forms of calibration must not be started while the noise floor calibration is running, as this can create invalid readings which were sometimes not even recoverable by any further calibration attempts. This patch also ensures that the result of noise floor measurements are processed faster and also allows the result of the initial calibration on reset to make it into the NF history buffer Signed-off-by: Felix Fietkau <nbd@openwrt.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_calib.c32
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.c15
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h1
4 files changed, 31 insertions, 20 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
index d28a8d37f01f..fe7418aefc4a 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
@@ -687,8 +687,13 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah,
687{ 687{
688 bool iscaldone = true; 688 bool iscaldone = true;
689 struct ath9k_cal_list *currCal = ah->cal_list_curr; 689 struct ath9k_cal_list *currCal = ah->cal_list_curr;
690 bool nfcal, nfcal_pending = false;
690 691
691 if (currCal && 692 nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF);
693 if (ah->caldata)
694 nfcal_pending = ah->caldata->nfcal_pending;
695
696 if (currCal && !nfcal &&
692 (currCal->calState == CAL_RUNNING || 697 (currCal->calState == CAL_RUNNING ||
693 currCal->calState == CAL_WAITING)) { 698 currCal->calState == CAL_WAITING)) {
694 iscaldone = ar9002_hw_per_calibration(ah, chan, 699 iscaldone = ar9002_hw_per_calibration(ah, chan,
@@ -704,7 +709,7 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah,
704 } 709 }
705 710
706 /* Do NF cal only at longer intervals */ 711 /* Do NF cal only at longer intervals */
707 if (longcal) { 712 if (longcal || nfcal_pending) {
708 /* Do periodic PAOffset Cal */ 713 /* Do periodic PAOffset Cal */
709 ar9002_hw_pa_cal(ah, false); 714 ar9002_hw_pa_cal(ah, false);
710 ar9002_hw_olc_temp_compensation(ah); 715 ar9002_hw_olc_temp_compensation(ah);
@@ -713,16 +718,18 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah,
713 * Get the value from the previous NF cal and update 718 * Get the value from the previous NF cal and update
714 * history buffer. 719 * history buffer.
715 */ 720 */
716 ath9k_hw_getnf(ah, chan); 721 if (ath9k_hw_getnf(ah, chan)) {
717 722 /*
718 /* 723 * Load the NF from history buffer of the current
719 * Load the NF from history buffer of the current channel. 724 * channel.
720 * NF is slow time-variant, so it is OK to use a historical 725 * NF is slow time-variant, so it is OK to use a
721 * value. 726 * historical value.
722 */ 727 */
723 ath9k_hw_loadnf(ah, ah->curchan); 728 ath9k_hw_loadnf(ah, ah->curchan);
729 }
724 730
725 ath9k_hw_start_nfcal(ah, false); 731 if (longcal)
732 ath9k_hw_start_nfcal(ah, false);
726 } 733 }
727 734
728 return iscaldone; 735 return iscaldone;
@@ -872,6 +879,9 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
872 /* Do NF Calibration after DC offset and other calibrations */ 879 /* Do NF Calibration after DC offset and other calibrations */
873 ath9k_hw_start_nfcal(ah, true); 880 ath9k_hw_start_nfcal(ah, true);
874 881
882 if (ah->caldata)
883 ah->caldata->nfcal_pending = true;
884
875 ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; 885 ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
876 886
877 /* Enable IQ, ADC Gain and ADC DC offset CALs */ 887 /* Enable IQ, ADC Gain and ADC DC offset CALs */
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index 18b5c0dcc1fc..45208690c0ec 100644
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -156,6 +156,9 @@ EXPORT_SYMBOL(ath9k_hw_reset_calvalid);
156 156
157void ath9k_hw_start_nfcal(struct ath_hw *ah, bool update) 157void ath9k_hw_start_nfcal(struct ath_hw *ah, bool update)
158{ 158{
159 if (ah->caldata)
160 ah->caldata->nfcal_pending = true;
161
159 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, 162 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
160 AR_PHY_AGC_CONTROL_ENABLE_NF); 163 AR_PHY_AGC_CONTROL_ENABLE_NF);
161 164
@@ -288,8 +291,7 @@ static void ath9k_hw_nf_sanitize(struct ath_hw *ah, s16 *nf)
288 } 291 }
289} 292}
290 293
291int16_t ath9k_hw_getnf(struct ath_hw *ah, 294bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
292 struct ath9k_channel *chan)
293{ 295{
294 struct ath_common *common = ath9k_hw_common(ah); 296 struct ath_common *common = ath9k_hw_common(ah);
295 int16_t nf, nfThresh; 297 int16_t nf, nfThresh;
@@ -299,7 +301,7 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
299 struct ath9k_hw_cal_data *caldata = ah->caldata; 301 struct ath9k_hw_cal_data *caldata = ah->caldata;
300 302
301 if (!caldata) 303 if (!caldata)
302 return ath9k_hw_get_default_nf(ah, chan); 304 return false;
303 305
304 chan->channelFlags &= (~CHANNEL_CW_INT); 306 chan->channelFlags &= (~CHANNEL_CW_INT);
305 if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { 307 if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
@@ -307,7 +309,7 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
307 "NF did not complete in calibration window\n"); 309 "NF did not complete in calibration window\n");
308 nf = 0; 310 nf = 0;
309 caldata->rawNoiseFloor = nf; 311 caldata->rawNoiseFloor = nf;
310 return caldata->rawNoiseFloor; 312 return false;
311 } else { 313 } else {
312 ath9k_hw_do_getnf(ah, nfarray); 314 ath9k_hw_do_getnf(ah, nfarray);
313 ath9k_hw_nf_sanitize(ah, nfarray); 315 ath9k_hw_nf_sanitize(ah, nfarray);
@@ -323,11 +325,10 @@ int16_t ath9k_hw_getnf(struct ath_hw *ah,
323 } 325 }
324 326
325 h = caldata->nfCalHist; 327 h = caldata->nfCalHist;
326 328 caldata->nfcal_pending = false;
327 ath9k_hw_update_nfcal_hist_buffer(h, nfarray); 329 ath9k_hw_update_nfcal_hist_buffer(h, nfarray);
328 caldata->rawNoiseFloor = h[0].privNF; 330 caldata->rawNoiseFloor = h[0].privNF;
329 331 return true;
330 return ah->caldata->rawNoiseFloor;
331} 332}
332 333
333void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah, 334void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h
index ca2e6b39c1d4..0a304b3eeeb6 100644
--- a/drivers/net/wireless/ath/ath9k/calib.h
+++ b/drivers/net/wireless/ath/ath9k/calib.h
@@ -110,8 +110,7 @@ struct ath9k_pacal_info{
110bool ath9k_hw_reset_calvalid(struct ath_hw *ah); 110bool ath9k_hw_reset_calvalid(struct ath_hw *ah);
111void ath9k_hw_start_nfcal(struct ath_hw *ah, bool update); 111void ath9k_hw_start_nfcal(struct ath_hw *ah, bool update);
112void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan); 112void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
113int16_t ath9k_hw_getnf(struct ath_hw *ah, 113bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan);
114 struct ath9k_channel *chan);
115void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah, 114void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
116 struct ath9k_channel *chan); 115 struct ath9k_channel *chan);
117s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan); 116s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan);
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index c1b701119d88..399f7c1283cd 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -354,6 +354,7 @@ struct ath9k_hw_cal_data {
354 int8_t qCoff; 354 int8_t qCoff;
355 int16_t rawNoiseFloor; 355 int16_t rawNoiseFloor;
356 bool paprd_done; 356 bool paprd_done;
357 bool nfcal_pending;
357 u16 small_signal_gain[AR9300_MAX_CHAINS]; 358 u16 small_signal_gain[AR9300_MAX_CHAINS];
358 u32 pa_table[AR9300_MAX_CHAINS][PAPRD_TABLE_SZ]; 359 u32 pa_table[AR9300_MAX_CHAINS][PAPRD_TABLE_SZ];
359 struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS]; 360 struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];