330-ath9k-restart-hardware-after-noise-floor-calibration.patch 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. From: Felix Fietkau <[email protected]>
  2. Date: Sat, 18 Oct 2014 13:37:32 +0200
  3. Subject: [PATCH] ath9k: restart hardware after noise floor calibration
  4. failure
  5. When NF calibration fails, the radio often becomes deaf. The usual
  6. hardware hang checks do not detect this, so it's better to issue a reset
  7. when that happens.
  8. Signed-off-by: Felix Fietkau <[email protected]>
  9. ---
  10. --- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
  11. +++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
  12. @@ -657,14 +657,13 @@ static void ar9002_hw_olc_temp_compensat
  13. ar9280_hw_olc_temp_compensation(ah);
  14. }
  15. -static bool ar9002_hw_calibrate(struct ath_hw *ah,
  16. - struct ath9k_channel *chan,
  17. - u8 rxchainmask,
  18. - bool longcal)
  19. +static int ar9002_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
  20. + u8 rxchainmask, bool longcal)
  21. {
  22. bool iscaldone = true;
  23. struct ath9k_cal_list *currCal = ah->cal_list_curr;
  24. bool nfcal, nfcal_pending = false;
  25. + int ret;
  26. nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF);
  27. if (ah->caldata)
  28. @@ -698,7 +697,9 @@ static bool ar9002_hw_calibrate(struct a
  29. * NF is slow time-variant, so it is OK to use a
  30. * historical value.
  31. */
  32. - ath9k_hw_loadnf(ah, ah->curchan);
  33. + ret = ath9k_hw_loadnf(ah, ah->curchan);
  34. + if (ret < 0)
  35. + return ret;
  36. }
  37. if (longcal) {
  38. --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
  39. +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
  40. @@ -121,13 +121,12 @@ static bool ar9003_hw_per_calibration(st
  41. return iscaldone;
  42. }
  43. -static bool ar9003_hw_calibrate(struct ath_hw *ah,
  44. - struct ath9k_channel *chan,
  45. - u8 rxchainmask,
  46. - bool longcal)
  47. +static int ar9003_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
  48. + u8 rxchainmask, bool longcal)
  49. {
  50. bool iscaldone = true;
  51. struct ath9k_cal_list *currCal = ah->cal_list_curr;
  52. + int ret;
  53. /*
  54. * For given calibration:
  55. @@ -163,7 +162,9 @@ static bool ar9003_hw_calibrate(struct a
  56. * NF is slow time-variant, so it is OK to use a historical
  57. * value.
  58. */
  59. - ath9k_hw_loadnf(ah, ah->curchan);
  60. + ret = ath9k_hw_loadnf(ah, ah->curchan);
  61. + if (ret < 0)
  62. + return ret;
  63. /* start NF calibration, without updating BB NF register */
  64. ath9k_hw_start_nfcal(ah, false);
  65. --- a/drivers/net/wireless/ath/ath9k/calib.c
  66. +++ b/drivers/net/wireless/ath/ath9k/calib.c
  67. @@ -234,7 +234,7 @@ void ath9k_hw_start_nfcal(struct ath_hw
  68. REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
  69. }
  70. -void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
  71. +int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
  72. {
  73. struct ath9k_nfcal_hist *h = NULL;
  74. unsigned i, j;
  75. @@ -301,7 +301,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah,
  76. ath_dbg(common, ANY,
  77. "Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n",
  78. REG_READ(ah, AR_PHY_AGC_CONTROL));
  79. - return;
  80. + return -ETIMEDOUT;
  81. }
  82. /*
  83. @@ -322,6 +322,8 @@ void ath9k_hw_loadnf(struct ath_hw *ah,
  84. }
  85. }
  86. REGWRITE_BUFFER_FLUSH(ah);
  87. +
  88. + return 0;
  89. }
  90. --- a/drivers/net/wireless/ath/ath9k/calib.h
  91. +++ b/drivers/net/wireless/ath/ath9k/calib.h
  92. @@ -109,7 +109,7 @@ struct ath9k_pacal_info{
  93. bool ath9k_hw_reset_calvalid(struct ath_hw *ah);
  94. void ath9k_hw_start_nfcal(struct ath_hw *ah, bool update);
  95. -void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
  96. +int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan);
  97. bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan);
  98. void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
  99. struct ath9k_channel *chan);
  100. --- a/drivers/net/wireless/ath/ath9k/debug.c
  101. +++ b/drivers/net/wireless/ath/ath9k/debug.c
  102. @@ -863,6 +863,7 @@ static ssize_t read_file_reset(struct fi
  103. [RESET_TYPE_MAC_HANG] = "MAC Hang",
  104. [RESET_TYPE_BEACON_STUCK] = "Stuck Beacon",
  105. [RESET_TYPE_MCI] = "MCI Reset",
  106. + [RESET_TYPE_CALIBRATION] = "Calibration error",
  107. };
  108. char buf[512];
  109. unsigned int len = 0;
  110. --- a/drivers/net/wireless/ath/ath9k/debug.h
  111. +++ b/drivers/net/wireless/ath/ath9k/debug.h
  112. @@ -49,6 +49,7 @@ enum ath_reset_type {
  113. RESET_TYPE_MAC_HANG,
  114. RESET_TYPE_BEACON_STUCK,
  115. RESET_TYPE_MCI,
  116. + RESET_TYPE_CALIBRATION,
  117. __RESET_TYPE_MAX
  118. };
  119. --- a/drivers/net/wireless/ath/ath9k/hw-ops.h
  120. +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
  121. @@ -41,10 +41,9 @@ static inline void ath9k_hw_set_desc_lin
  122. ath9k_hw_ops(ah)->set_desc_link(ds, link);
  123. }
  124. -static inline bool ath9k_hw_calibrate(struct ath_hw *ah,
  125. - struct ath9k_channel *chan,
  126. - u8 rxchainmask,
  127. - bool longcal)
  128. +static inline int ath9k_hw_calibrate(struct ath_hw *ah,
  129. + struct ath9k_channel *chan,
  130. + u8 rxchainmask, bool longcal)
  131. {
  132. return ath9k_hw_ops(ah)->calibrate(ah, chan, rxchainmask, longcal);
  133. }
  134. --- a/drivers/net/wireless/ath/ath9k/hw.h
  135. +++ b/drivers/net/wireless/ath/ath9k/hw.h
  136. @@ -688,10 +688,8 @@ struct ath_hw_ops {
  137. bool power_off);
  138. void (*rx_enable)(struct ath_hw *ah);
  139. void (*set_desc_link)(void *ds, u32 link);
  140. - bool (*calibrate)(struct ath_hw *ah,
  141. - struct ath9k_channel *chan,
  142. - u8 rxchainmask,
  143. - bool longcal);
  144. + int (*calibrate)(struct ath_hw *ah, struct ath9k_channel *chan,
  145. + u8 rxchainmask, bool longcal);
  146. bool (*get_isr)(struct ath_hw *ah, enum ath9k_int *masked,
  147. u32 *sync_cause_p);
  148. void (*set_txdesc)(struct ath_hw *ah, void *ds,
  149. --- a/drivers/net/wireless/ath/ath9k/link.c
  150. +++ b/drivers/net/wireless/ath/ath9k/link.c
  151. @@ -371,9 +371,14 @@ void ath_ani_calibrate(unsigned long dat
  152. /* Perform calibration if necessary */
  153. if (longcal || shortcal) {
  154. - common->ani.caldone =
  155. - ath9k_hw_calibrate(ah, ah->curchan,
  156. - ah->rxchainmask, longcal);
  157. + int ret = ath9k_hw_calibrate(ah, ah->curchan, ah->rxchainmask,
  158. + longcal);
  159. + if (ret < 0) {
  160. + ath9k_queue_reset(sc, RESET_TYPE_CALIBRATION);
  161. + return;
  162. + }
  163. +
  164. + common->ani.caldone = ret;
  165. }
  166. ath_dbg(common, ANI,