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