aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2014-10-25 11:19:30 -0400
committerJohn W. Linville <linville@tuxdriver.com>2014-10-27 14:16:18 -0400
commit7b8aaead958e38b1eb8944c5f9c90ce066500268 (patch)
tree1854b2009b0af5f7e5fca49313861cc2fb626c02 /drivers/net/wireless/ath
parent70e535ed00290ed415ccfb200695ea30b6af51e5 (diff)
ath9k: restart hardware after noise floor calibration failure
When NF calibration fails, the radio often becomes deaf. The usual hardware hang checks do not detect this, so it's better to issue a reset when that happens. Signed-off-by: Felix Fietkau <nbd@openwrt.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath')
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_calib.c11
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_calib.c11
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.c6
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/hw-ops.h7
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h6
-rw-r--r--drivers/net/wireless/ath/ath9k/link.c12
9 files changed, 33 insertions, 24 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
index cdc74005650c..6bfdebfcdeef 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
@@ -657,14 +657,13 @@ static void ar9002_hw_olc_temp_compensation(struct ath_hw *ah)
657 ar9280_hw_olc_temp_compensation(ah); 657 ar9280_hw_olc_temp_compensation(ah);
658} 658}
659 659
660static bool ar9002_hw_calibrate(struct ath_hw *ah, 660static int ar9002_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
661 struct ath9k_channel *chan, 661 u8 rxchainmask, bool longcal)
662 u8 rxchainmask,
663 bool longcal)
664{ 662{
665 bool iscaldone = true; 663 bool iscaldone = true;
666 struct ath9k_cal_list *currCal = ah->cal_list_curr; 664 struct ath9k_cal_list *currCal = ah->cal_list_curr;
667 bool nfcal, nfcal_pending = false; 665 bool nfcal, nfcal_pending = false;
666 int ret;
668 667
669 nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF); 668 nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF);
670 if (ah->caldata) 669 if (ah->caldata)
@@ -698,7 +697,9 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah,
698 * NF is slow time-variant, so it is OK to use a 697 * NF is slow time-variant, so it is OK to use a
699 * historical value. 698 * historical value.
700 */ 699 */
701 ath9k_hw_loadnf(ah, ah->curchan); 700 ret = ath9k_hw_loadnf(ah, ah->curchan);
701 if (ret < 0)
702 return ret;
702 } 703 }
703 704
704 if (longcal) { 705 if (longcal) {
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index ac8301ef5242..06ab71db6e80 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -121,13 +121,12 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah,
121 return iscaldone; 121 return iscaldone;
122} 122}
123 123
124static bool ar9003_hw_calibrate(struct ath_hw *ah, 124static int ar9003_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
125 struct ath9k_channel *chan, 125 u8 rxchainmask, bool longcal)
126 u8 rxchainmask,
127 bool longcal)
128{ 126{
129 bool iscaldone = true; 127 bool iscaldone = true;
130 struct ath9k_cal_list *currCal = ah->cal_list_curr; 128 struct ath9k_cal_list *currCal = ah->cal_list_curr;
129 int ret;
131 130
132 /* 131 /*
133 * For given calibration: 132 * For given calibration:
@@ -163,7 +162,9 @@ static bool ar9003_hw_calibrate(struct ath_hw *ah,
163 * NF is slow time-variant, so it is OK to use a historical 162 * NF is slow time-variant, so it is OK to use a historical
164 * value. 163 * value.
165 */ 164 */
166 ath9k_hw_loadnf(ah, ah->curchan); 165 ret = ath9k_hw_loadnf(ah, ah->curchan);
166 if (ret < 0)
167 return ret;
167 168
168 /* start NF calibration, without updating BB NF register */ 169 /* start NF calibration, without updating BB NF register */
169 ath9k_hw_start_nfcal(ah, false); 170 ath9k_hw_start_nfcal(ah, false);
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index 278365b8a895..e200a6e3aca5 100644
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -234,7 +234,7 @@ void ath9k_hw_start_nfcal(struct ath_hw *ah, bool update)
234 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); 234 REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
235} 235}
236 236
237void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan) 237int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
238{ 238{
239 struct ath9k_nfcal_hist *h = NULL; 239 struct ath9k_nfcal_hist *h = NULL;
240 unsigned i, j; 240 unsigned i, j;
@@ -301,7 +301,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
301 ath_dbg(common, ANY, 301 ath_dbg(common, ANY,
302 "Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n", 302 "Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n",
303 REG_READ(ah, AR_PHY_AGC_CONTROL)); 303 REG_READ(ah, AR_PHY_AGC_CONTROL));
304 return; 304 return -ETIMEDOUT;
305 } 305 }
306 306
307 /* 307 /*
@@ -322,6 +322,8 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
322 } 322 }
323 } 323 }
324 REGWRITE_BUFFER_FLUSH(ah); 324 REGWRITE_BUFFER_FLUSH(ah);
325
326 return 0;
325} 327}
326 328
327 329
diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h
index b8ed95e9a335..87badf4bb8a4 100644
--- a/drivers/net/wireless/ath/ath9k/calib.h
+++ b/drivers/net/wireless/ath/ath9k/calib.h
@@ -109,7 +109,7 @@ struct ath9k_pacal_info{
109 109
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); 112int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
113bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan); 113bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan);
114void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah, 114void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
115 struct ath9k_channel *chan); 115 struct ath9k_channel *chan);
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index cf4a98b98cf3..2a2a17df5fb3 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -863,6 +863,7 @@ static ssize_t read_file_reset(struct file *file, char __user *user_buf,
863 [RESET_TYPE_MAC_HANG] = "MAC Hang", 863 [RESET_TYPE_MAC_HANG] = "MAC Hang",
864 [RESET_TYPE_BEACON_STUCK] = "Stuck Beacon", 864 [RESET_TYPE_BEACON_STUCK] = "Stuck Beacon",
865 [RESET_TYPE_MCI] = "MCI Reset", 865 [RESET_TYPE_MCI] = "MCI Reset",
866 [RESET_TYPE_CALIBRATION] = "Calibration error",
866 }; 867 };
867 char buf[512]; 868 char buf[512];
868 unsigned int len = 0; 869 unsigned int len = 0;
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 53ae15bd0c9d..bd75b1f716db 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -49,6 +49,7 @@ enum ath_reset_type {
49 RESET_TYPE_MAC_HANG, 49 RESET_TYPE_MAC_HANG,
50 RESET_TYPE_BEACON_STUCK, 50 RESET_TYPE_BEACON_STUCK,
51 RESET_TYPE_MCI, 51 RESET_TYPE_MCI,
52 RESET_TYPE_CALIBRATION,
52 __RESET_TYPE_MAX 53 __RESET_TYPE_MAX
53}; 54};
54 55
diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h
index 8e85efeaeffc..88769b64b20b 100644
--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
@@ -41,10 +41,9 @@ static inline void ath9k_hw_set_desc_link(struct ath_hw *ah, void *ds,
41 ath9k_hw_ops(ah)->set_desc_link(ds, link); 41 ath9k_hw_ops(ah)->set_desc_link(ds, link);
42} 42}
43 43
44static inline bool ath9k_hw_calibrate(struct ath_hw *ah, 44static inline int ath9k_hw_calibrate(struct ath_hw *ah,
45 struct ath9k_channel *chan, 45 struct ath9k_channel *chan,
46 u8 rxchainmask, 46 u8 rxchainmask, bool longcal)
47 bool longcal)
48{ 47{
49 return ath9k_hw_ops(ah)->calibrate(ah, chan, rxchainmask, longcal); 48 return ath9k_hw_ops(ah)->calibrate(ah, chan, rxchainmask, longcal);
50} 49}
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 7a81f5b864c7..f204099c38b8 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -688,10 +688,8 @@ struct ath_hw_ops {
688 bool power_off); 688 bool power_off);
689 void (*rx_enable)(struct ath_hw *ah); 689 void (*rx_enable)(struct ath_hw *ah);
690 void (*set_desc_link)(void *ds, u32 link); 690 void (*set_desc_link)(void *ds, u32 link);
691 bool (*calibrate)(struct ath_hw *ah, 691 int (*calibrate)(struct ath_hw *ah, struct ath9k_channel *chan,
692 struct ath9k_channel *chan, 692 u8 rxchainmask, bool longcal);
693 u8 rxchainmask,
694 bool longcal);
695 bool (*get_isr)(struct ath_hw *ah, enum ath9k_int *masked, 693 bool (*get_isr)(struct ath_hw *ah, enum ath9k_int *masked,
696 u32 *sync_cause_p); 694 u32 *sync_cause_p);
697 void (*set_txdesc)(struct ath_hw *ah, void *ds, 695 void (*set_txdesc)(struct ath_hw *ah, void *ds,
diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c
index 2343f56e6498..b829263e3d0a 100644
--- a/drivers/net/wireless/ath/ath9k/link.c
+++ b/drivers/net/wireless/ath/ath9k/link.c
@@ -371,9 +371,15 @@ void ath_ani_calibrate(unsigned long data)
371 371
372 /* Perform calibration if necessary */ 372 /* Perform calibration if necessary */
373 if (longcal || shortcal) { 373 if (longcal || shortcal) {
374 common->ani.caldone = 374 int ret = ath9k_hw_calibrate(ah, ah->curchan, ah->rxchainmask,
375 ath9k_hw_calibrate(ah, ah->curchan, 375 longcal);
376 ah->rxchainmask, longcal); 376 if (ret < 0) {
377 common->ani.caldone = 0;
378 ath9k_queue_reset(sc, RESET_TYPE_CALIBRATION);
379 return;
380 }
381
382 common->ani.caldone = ret;
377 } 383 }
378 384
379 ath_dbg(common, ANI, 385 ath_dbg(common, ANI,