304-ath9k-DFS-add-pulse-chirp-detection-for-FCC.patch 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. From: Zefir Kurtisi <[email protected]>
  2. Date: Tue, 16 Jun 2015 12:52:16 +0200
  3. Subject: [PATCH] ath9k: DFS - add pulse chirp detection for FCC
  4. FCC long pulse radar (type 5) requires pulses to be
  5. checked for chirping. This patch implements chirp
  6. detection based on the FFT data provided for long
  7. pulses.
  8. A chirp is detected when a set of criteria defined
  9. by FCC pulse characteristics is met, including
  10. * have at least 4 FFT samples
  11. * max_bin index moves equidistantly between samples
  12. * the gradient is within defined range
  13. The chirp detection has been tested with reference
  14. radar generating devices and proved to work reliably.
  15. Signed-off-by: Zefir Kurtisi <[email protected]>
  16. ---
  17. --- a/drivers/net/wireless/ath/ath9k/dfs.c
  18. +++ b/drivers/net/wireless/ath/ath9k/dfs.c
  19. @@ -30,6 +30,157 @@ struct ath_radar_data {
  20. u8 pulse_length_pri;
  21. };
  22. +/**** begin: CHIRP ************************************************************/
  23. +
  24. +/* min and max gradients for defined FCC chirping pulses, given by
  25. + * - 20MHz chirp width over a pulse width of 50us
  26. + * - 5MHz chirp width over a pulse width of 100us
  27. + */
  28. +static const int BIN_DELTA_MIN = 1;
  29. +static const int BIN_DELTA_MAX = 10;
  30. +
  31. +/* we need at least 3 deltas / 4 samples for a reliable chirp detection */
  32. +#define NUM_DIFFS 3
  33. +static const int FFT_NUM_SAMPLES = (NUM_DIFFS + 1);
  34. +
  35. +/* Threshold for difference of delta peaks */
  36. +static const int MAX_DIFF = 2;
  37. +
  38. +/* width range to be checked for chirping */
  39. +static const int MIN_CHIRP_PULSE_WIDTH = 20;
  40. +static const int MAX_CHIRP_PULSE_WIDTH = 110;
  41. +
  42. +struct ath9k_dfs_fft_20 {
  43. + u8 bin[28];
  44. + u8 lower_bins[3];
  45. +} __packed;
  46. +struct ath9k_dfs_fft_40 {
  47. + u8 bin[64];
  48. + u8 lower_bins[3];
  49. + u8 upper_bins[3];
  50. +} __packed;
  51. +
  52. +static inline int fft_max_index(u8 *bins)
  53. +{
  54. + return (bins[2] & 0xfc) >> 2;
  55. +}
  56. +static inline int fft_max_magnitude(u8 *bins)
  57. +{
  58. + return (bins[0] & 0xc0) >> 6 | bins[1] << 2 | (bins[2] & 0x03) << 10;
  59. +}
  60. +static inline u8 fft_bitmap_weight(u8 *bins)
  61. +{
  62. + return bins[0] & 0x3f;
  63. +}
  64. +
  65. +static int ath9k_get_max_index_ht40(struct ath9k_dfs_fft_40 *fft,
  66. + bool is_ctl, bool is_ext)
  67. +{
  68. + const int DFS_UPPER_BIN_OFFSET = 64;
  69. + /* if detected radar on both channels, select the significant one */
  70. + if (is_ctl && is_ext) {
  71. + /* first check wether channels have 'strong' bins */
  72. + is_ctl = fft_bitmap_weight(fft->lower_bins) != 0;
  73. + is_ext = fft_bitmap_weight(fft->upper_bins) != 0;
  74. +
  75. + /* if still unclear, take higher magnitude */
  76. + if (is_ctl && is_ext) {
  77. + int mag_lower = fft_max_magnitude(fft->lower_bins);
  78. + int mag_upper = fft_max_magnitude(fft->upper_bins);
  79. + if (mag_upper > mag_lower)
  80. + is_ctl = false;
  81. + else
  82. + is_ext = false;
  83. + }
  84. + }
  85. + if (is_ctl)
  86. + return fft_max_index(fft->lower_bins);
  87. + return fft_max_index(fft->upper_bins) + DFS_UPPER_BIN_OFFSET;
  88. +}
  89. +static bool ath9k_check_chirping(struct ath_softc *sc, u8 *data,
  90. + int datalen, bool is_ctl, bool is_ext)
  91. +{
  92. + int i;
  93. + int max_bin[FFT_NUM_SAMPLES];
  94. + struct ath_hw *ah = sc->sc_ah;
  95. + struct ath_common *common = ath9k_hw_common(ah);
  96. + int prev_delta;
  97. +
  98. + if (IS_CHAN_HT40(ah->curchan)) {
  99. + struct ath9k_dfs_fft_40 *fft = (struct ath9k_dfs_fft_40 *) data;
  100. + int num_fft_packets = datalen / sizeof(*fft);
  101. + if (num_fft_packets == 0)
  102. + return false;
  103. +
  104. + ath_dbg(common, DFS, "HT40: datalen=%d, num_fft_packets=%d\n",
  105. + datalen, num_fft_packets);
  106. + if (num_fft_packets < (FFT_NUM_SAMPLES)) {
  107. + ath_dbg(common, DFS, "not enough packets for chirp\n");
  108. + return false;
  109. + }
  110. + /* HW sometimes adds 2 garbage bytes in front of FFT samples */
  111. + if ((datalen % sizeof(*fft)) == 2) {
  112. + fft = (struct ath9k_dfs_fft_40 *) (data + 2);
  113. + ath_dbg(common, DFS, "fixing datalen by 2\n");
  114. + }
  115. + if (IS_CHAN_HT40MINUS(ah->curchan)) {
  116. + int temp = is_ctl;
  117. + is_ctl = is_ext;
  118. + is_ext = temp;
  119. + }
  120. + for (i = 0; i < FFT_NUM_SAMPLES; i++)
  121. + max_bin[i] = ath9k_get_max_index_ht40(fft + i, is_ctl,
  122. + is_ext);
  123. + } else {
  124. + struct ath9k_dfs_fft_20 *fft = (struct ath9k_dfs_fft_20 *) data;
  125. + int num_fft_packets = datalen / sizeof(*fft);
  126. + if (num_fft_packets == 0)
  127. + return false;
  128. + ath_dbg(common, DFS, "HT20: datalen=%d, num_fft_packets=%d\n",
  129. + datalen, num_fft_packets);
  130. + if (num_fft_packets < (FFT_NUM_SAMPLES)) {
  131. + ath_dbg(common, DFS, "not enough packets for chirp\n");
  132. + return false;
  133. + }
  134. + /* in ht20, this is a 6-bit signed number => shift it to 0 */
  135. + for (i = 0; i < FFT_NUM_SAMPLES; i++)
  136. + max_bin[i] = fft_max_index(fft[i].lower_bins) ^ 0x20;
  137. + }
  138. + ath_dbg(common, DFS, "bin_max = [%d, %d, %d, %d]\n",
  139. + max_bin[0], max_bin[1], max_bin[2], max_bin[3]);
  140. +
  141. + /* Check for chirp attributes within specs
  142. + * a) delta of adjacent max_bins is within range
  143. + * b) delta of adjacent deltas are within tolerance
  144. + */
  145. + prev_delta = 0;
  146. + for (i = 0; i < NUM_DIFFS; i++) {
  147. + int ddelta = -1;
  148. + int delta = max_bin[i + 1] - max_bin[i];
  149. +
  150. + /* ensure gradient is within valid range */
  151. + if (abs(delta) < BIN_DELTA_MIN || abs(delta) > BIN_DELTA_MAX) {
  152. + ath_dbg(common, DFS, "CHIRP: invalid delta %d "
  153. + "in sample %d\n", delta, i);
  154. + return false;
  155. + }
  156. + if (i == 0)
  157. + goto done;
  158. + ddelta = delta - prev_delta;
  159. + if (abs(ddelta) > MAX_DIFF) {
  160. + ath_dbg(common, DFS, "CHIRP: ddelta %d too high\n",
  161. + ddelta);
  162. + return false;
  163. + }
  164. +done:
  165. + ath_dbg(common, DFS, "CHIRP - %d: delta=%d, ddelta=%d\n",
  166. + i, delta, ddelta);
  167. + prev_delta = delta;
  168. + }
  169. + return true;
  170. +}
  171. +/**** end: CHIRP **************************************************************/
  172. +
  173. /* convert pulse duration to usecs, considering clock mode */
  174. static u32 dur_to_usecs(struct ath_hw *ah, u32 dur)
  175. {
  176. @@ -113,12 +264,6 @@ ath9k_postprocess_radar_event(struct ath
  177. return false;
  178. }
  179. - /*
  180. - * TODO: check chirping pulses
  181. - * checks for chirping are dependent on the DFS regulatory domain
  182. - * used, which is yet TBD
  183. - */
  184. -
  185. /* convert duration to usecs */
  186. pe->width = dur_to_usecs(sc->sc_ah, dur);
  187. pe->rssi = rssi;
  188. @@ -190,6 +335,16 @@ void ath9k_dfs_process_phyerr(struct ath
  189. if (!ath9k_postprocess_radar_event(sc, &ard, &pe))
  190. return;
  191. + if (pe.width > MIN_CHIRP_PULSE_WIDTH &&
  192. + pe.width < MAX_CHIRP_PULSE_WIDTH) {
  193. + bool is_ctl = !!(ard.pulse_bw_info & PRI_CH_RADAR_FOUND);
  194. + bool is_ext = !!(ard.pulse_bw_info & EXT_CH_RADAR_FOUND);
  195. + int clen = datalen - 3;
  196. + pe.chirp = ath9k_check_chirping(sc, data, clen, is_ctl, is_ext);
  197. + } else {
  198. + pe.chirp = false;
  199. + }
  200. +
  201. ath_dbg(common, DFS,
  202. "ath9k_dfs_process_phyerr: type=%d, freq=%d, ts=%llu, "
  203. "width=%d, rssi=%d, delta_ts=%llu\n",