diff options
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/beacon.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/calib.c | 66 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/calib.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hw.h | 1 |
4 files changed, 65 insertions, 4 deletions
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 102f1234f794..081192e78a46 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c | |||
@@ -362,6 +362,7 @@ void ath_beacon_tasklet(unsigned long data) | |||
362 | ath_print(common, ATH_DBG_BSTUCK, | 362 | ath_print(common, ATH_DBG_BSTUCK, |
363 | "missed %u consecutive beacons\n", | 363 | "missed %u consecutive beacons\n", |
364 | sc->beacon.bmisscnt); | 364 | sc->beacon.bmisscnt); |
365 | ath9k_hw_bstuck_nfcal(ah); | ||
365 | } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { | 366 | } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { |
366 | ath_print(common, ATH_DBG_BSTUCK, | 367 | ath_print(common, ATH_DBG_BSTUCK, |
367 | "beacon is officially stuck\n"); | 368 | "beacon is officially stuck\n"); |
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index ccb1b2eae85e..67ee5d735cc1 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c | |||
@@ -65,12 +65,16 @@ static s16 ath9k_hw_get_default_nf(struct ath_hw *ah, | |||
65 | 65 | ||
66 | 66 | ||
67 | static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah, | 67 | static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah, |
68 | struct ath9k_nfcal_hist *h, | 68 | struct ath9k_hw_cal_data *cal, |
69 | int16_t *nfarray) | 69 | int16_t *nfarray) |
70 | { | 70 | { |
71 | struct ath_common *common = ath9k_hw_common(ah); | ||
71 | struct ath_nf_limits *limit; | 72 | struct ath_nf_limits *limit; |
73 | struct ath9k_nfcal_hist *h; | ||
74 | bool high_nf_mid = false; | ||
72 | int i; | 75 | int i; |
73 | 76 | ||
77 | h = cal->nfCalHist; | ||
74 | limit = ath9k_hw_get_nf_limits(ah, ah->curchan); | 78 | limit = ath9k_hw_get_nf_limits(ah, ah->curchan); |
75 | 79 | ||
76 | for (i = 0; i < NUM_NF_READINGS; i++) { | 80 | for (i = 0; i < NUM_NF_READINGS; i++) { |
@@ -87,9 +91,38 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah, | |||
87 | ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer); | 91 | ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer); |
88 | } | 92 | } |
89 | 93 | ||
90 | if (h[i].privNF > limit->max) | 94 | if (!h[i].privNF) |
91 | h[i].privNF = limit->max; | 95 | continue; |
96 | |||
97 | if (h[i].privNF > limit->max) { | ||
98 | high_nf_mid = true; | ||
99 | |||
100 | ath_print(common, ATH_DBG_CALIBRATE, | ||
101 | "NFmid[%d] (%d) > MAX (%d), %s\n", | ||
102 | i, h[i].privNF, limit->max, | ||
103 | (cal->nfcal_interference ? | ||
104 | "not corrected (due to interference)" : | ||
105 | "correcting to MAX")); | ||
106 | |||
107 | /* | ||
108 | * Normally we limit the average noise floor by the | ||
109 | * hardware specific maximum here. However if we have | ||
110 | * encountered stuck beacons because of interference, | ||
111 | * we bypass this limit here in order to better deal | ||
112 | * with our environment. | ||
113 | */ | ||
114 | if (!cal->nfcal_interference) | ||
115 | h[i].privNF = limit->max; | ||
116 | } | ||
92 | } | 117 | } |
118 | |||
119 | /* | ||
120 | * If the noise floor seems normal for all chains, assume that | ||
121 | * there is no significant interference in the environment anymore. | ||
122 | * Re-enable the enforcement of the NF maximum again. | ||
123 | */ | ||
124 | if (!high_nf_mid) | ||
125 | cal->nfcal_interference = false; | ||
93 | } | 126 | } |
94 | 127 | ||
95 | static bool ath9k_hw_get_nf_thresh(struct ath_hw *ah, | 128 | static bool ath9k_hw_get_nf_thresh(struct ath_hw *ah, |
@@ -339,7 +372,7 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan) | |||
339 | 372 | ||
340 | h = caldata->nfCalHist; | 373 | h = caldata->nfCalHist; |
341 | caldata->nfcal_pending = false; | 374 | caldata->nfcal_pending = false; |
342 | ath9k_hw_update_nfcal_hist_buffer(ah, h, nfarray); | 375 | ath9k_hw_update_nfcal_hist_buffer(ah, caldata, nfarray); |
343 | caldata->rawNoiseFloor = h[0].privNF; | 376 | caldata->rawNoiseFloor = h[0].privNF; |
344 | return true; | 377 | return true; |
345 | } | 378 | } |
@@ -374,3 +407,28 @@ s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan) | |||
374 | return ah->caldata->rawNoiseFloor; | 407 | return ah->caldata->rawNoiseFloor; |
375 | } | 408 | } |
376 | EXPORT_SYMBOL(ath9k_hw_getchan_noise); | 409 | EXPORT_SYMBOL(ath9k_hw_getchan_noise); |
410 | |||
411 | void ath9k_hw_bstuck_nfcal(struct ath_hw *ah) | ||
412 | { | ||
413 | struct ath9k_hw_cal_data *caldata = ah->caldata; | ||
414 | |||
415 | if (unlikely(!caldata)) | ||
416 | return; | ||
417 | |||
418 | /* | ||
419 | * If beacons are stuck, the most likely cause is interference. | ||
420 | * Triggering a noise floor calibration at this point helps the | ||
421 | * hardware adapt to a noisy environment much faster. | ||
422 | * To ensure that we recover from stuck beacons quickly, let | ||
423 | * the baseband update the internal NF value itself, similar to | ||
424 | * what is being done after a full reset. | ||
425 | */ | ||
426 | if (!caldata->nfcal_pending) | ||
427 | ath9k_hw_start_nfcal(ah, true); | ||
428 | else if (!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF)) | ||
429 | ath9k_hw_getnf(ah, ah->curchan); | ||
430 | |||
431 | caldata->nfcal_interference = true; | ||
432 | } | ||
433 | EXPORT_SYMBOL(ath9k_hw_bstuck_nfcal); | ||
434 | |||
diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h index 0a304b3eeeb6..5b053a6260b2 100644 --- a/drivers/net/wireless/ath/ath9k/calib.h +++ b/drivers/net/wireless/ath/ath9k/calib.h | |||
@@ -113,6 +113,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan); | |||
113 | bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan); | 113 | bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan); |
114 | void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah, | 114 | void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah, |
115 | struct ath9k_channel *chan); | 115 | struct ath9k_channel *chan); |
116 | void ath9k_hw_bstuck_nfcal(struct ath_hw *ah); | ||
116 | s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan); | 117 | s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan); |
117 | void ath9k_hw_reset_calibration(struct ath_hw *ah, | 118 | void ath9k_hw_reset_calibration(struct ath_hw *ah, |
118 | struct ath9k_cal_list *currCal); | 119 | struct ath9k_cal_list *currCal); |
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 399f7c1283cd..1601dd439890 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h | |||
@@ -355,6 +355,7 @@ struct ath9k_hw_cal_data { | |||
355 | int16_t rawNoiseFloor; | 355 | int16_t rawNoiseFloor; |
356 | bool paprd_done; | 356 | bool paprd_done; |
357 | bool nfcal_pending; | 357 | bool nfcal_pending; |
358 | bool nfcal_interference; | ||
358 | u16 small_signal_gain[AR9300_MAX_CHAINS]; | 359 | u16 small_signal_gain[AR9300_MAX_CHAINS]; |
359 | u32 pa_table[AR9300_MAX_CHAINS][PAPRD_TABLE_SZ]; | 360 | u32 pa_table[AR9300_MAX_CHAINS][PAPRD_TABLE_SZ]; |
360 | struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS]; | 361 | struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS]; |