1 /*
2 * Copyright (c) 2013, 2016-2020 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4 * Copyright (c) 2002-2010, Atheros Communications Inc.
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 /**
20 * DOC: FCC Bin5 are special type of radars because they "chirp". Basically the
21 * pulses move across the frequency band and are called chirping pulses.
22 * dfs_check_chirping() actually examines the FFT data contained in the PHY
23 * error information to figure out whether the pulse is moving across
24 * frequencies.
25 */
26
27 #include "../dfs.h"
28 #include "wlan_dfs_mlme_api.h"
29 #include "../dfs_channel.h"
30
dfs_bin5_check_pulse(struct wlan_dfs * dfs,struct dfs_event * re,struct dfs_bin5radars * br)31 int dfs_bin5_check_pulse(struct wlan_dfs *dfs, struct dfs_event *re,
32 struct dfs_bin5radars *br)
33 {
34 int b5_rssithresh = br->br_pulse.b5_rssithresh;
35
36 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_PULSE,
37 "re_dur=%d, rssi=%d, check_chirp=%d, hw_chirp=%d, sw_chirp=%d",
38 (int)re->re_dur, (int)re->re_rssi,
39 !!(re->re_flags & DFS_EVENT_CHECKCHIRP),
40 !!(re->re_flags & DFS_EVENT_HW_CHIRP),
41 !!(re->re_flags & DFS_EVENT_SW_CHIRP));
42
43 /* If the SW/HW chirp detection says to fail the pulse,do so. */
44 if (DFS_EVENT_NOTCHIRP(re)) {
45 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5,
46 "rejecting chirp: ts=%llu, dur=%d, rssi=%d checkchirp=%d, hwchirp=%d, swchirp=%d",
47 (unsigned long long)re->re_full_ts,
48 (int)re->re_dur, (int)re->re_rssi,
49 !!(re->re_flags & DFS_EVENT_CHECKCHIRP),
50 !!(re->re_flags & DFS_EVENT_HW_CHIRP),
51 !!(re->re_flags & DFS_EVENT_SW_CHIRP));
52
53 return 0;
54 }
55
56 /* Adjust the filter threshold for rssi in non TURBO mode. */
57 if (!WLAN_IS_CHAN_TURBO(dfs->dfs_curchan))
58 b5_rssithresh += br->br_pulse.b5_rssimargin;
59
60 /* Check if the pulse is within duration and rssi thresholds. */
61 if ((re->re_dur >= br->br_pulse.b5_mindur) &&
62 (re->re_dur <= br->br_pulse.b5_maxdur) &&
63 (re->re_rssi >= b5_rssithresh)) {
64 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5,
65 "dur=%d, rssi=%d - adding!",
66 (int)re->re_dur, (int)re->re_rssi);
67 return 1;
68 }
69
70 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5,
71 "too low to be Bin5 pulse tsf=%llu, dur=%d, rssi=%d",
72 (unsigned long long)re->re_full_ts,
73 (int)re->re_dur, (int)re->re_rssi);
74
75 return 0;
76 }
77
dfs_bin5_addpulse(struct wlan_dfs * dfs,struct dfs_bin5radars * br,struct dfs_event * re,uint64_t thists)78 int dfs_bin5_addpulse(struct wlan_dfs *dfs,
79 struct dfs_bin5radars *br,
80 struct dfs_event *re,
81 uint64_t thists)
82 {
83 uint32_t index, stop;
84 uint64_t tsDelta;
85
86 /*
87 * Check if this pulse is a valid pulse in terms of repetition,
88 * if not, return without adding it to the queue. PRI : Pulse
89 * Repitetion Interval.
90 * BRI : Burst Repitetion Interval.
91 */
92 if (br->br_numelems != 0) {
93 index = br->br_lastelem;
94 tsDelta = thists - br->br_elems[index].be_ts;
95 if ((tsDelta < DFS_BIN5_PRI_LOWER_LIMIT) ||
96 ((tsDelta > DFS_BIN5_PRI_HIGHER_LIMIT) &&
97 (tsDelta < DFS_BIN5_BRI_LOWER_LIMIT))) {
98 return 0;
99 }
100 }
101
102 if (dfs->dfs_min_sidx > re->re_sidx)
103 dfs->dfs_min_sidx = re->re_sidx;
104
105 if (dfs->dfs_max_sidx < re->re_sidx)
106 dfs->dfs_max_sidx = re->re_sidx;
107 /* Circular buffer of size 2^n. */
108 index = (br->br_lastelem + 1) & DFS_MAX_B5_MASK;
109 br->br_lastelem = index;
110 if (br->br_numelems == DFS_MAX_B5_SIZE)
111 br->br_firstelem = (br->br_firstelem + 1) & DFS_MAX_B5_MASK;
112 else
113 br->br_numelems++;
114
115 br->br_elems[index].be_ts = thists;
116 br->br_elems[index].be_rssi = re->re_rssi;
117 br->br_elems[index].be_dur = re->re_dur; /* This is in u-sec */
118 stop = 0;
119 index = br->br_firstelem;
120 while ((!stop) && (br->br_numelems - 1) > 0) {
121 if ((thists - br->br_elems[index].be_ts) >
122 ((uint64_t)br->br_pulse.b5_timewindow)) {
123 br->br_numelems--;
124 br->br_firstelem =
125 (br->br_firstelem + 1) & DFS_MAX_B5_MASK;
126 index = br->br_firstelem;
127 } else {
128 stop = 1;
129 }
130 }
131
132 return 1;
133 }
134
135 /**
136 * dfs_calculate_bursts_for_same_rssi() - Calculate bursts for same rssi.
137 * @dfs: Pointer to wlan_dfs structure.
138 * @br: Pointer to dfs_bin5radars structure.
139 * @bursts: Bursts.
140 * @numevents: Number of events.
141 * @prev: prev index.
142 * @this: index to br_elems[].
143 * @index: index array.
144 */
dfs_calculate_bursts_for_same_rssi(struct wlan_dfs * dfs,struct dfs_bin5radars * br,uint32_t * bursts,uint32_t * numevents,uint32_t prev,uint32_t this,int * index)145 static inline void dfs_calculate_bursts_for_same_rssi(
146 struct wlan_dfs *dfs,
147 struct dfs_bin5radars *br,
148 uint32_t *bursts,
149 uint32_t *numevents,
150 uint32_t prev,
151 uint32_t this,
152 int *index)
153 {
154 uint32_t rssi_diff;
155
156 if (br->br_elems[this].be_rssi >= br->br_elems[prev].be_rssi)
157 rssi_diff = (br->br_elems[this].be_rssi -
158 br->br_elems[prev].be_rssi);
159 else
160 rssi_diff = (br->br_elems[prev].be_rssi -
161 br->br_elems[this].be_rssi);
162
163 if (rssi_diff <= DFS_BIN5_RSSI_MARGIN) {
164 (*bursts)++;
165 /*
166 * Save the indexes of this pair for later
167 * width variance check.
168 */
169 if ((*numevents) >= 2) {
170 /*
171 * Make sure the event is not duplicated, possible in
172 * a 3 pulse burst.
173 */
174 if (index[(*numevents)-1] != prev)
175 index[(*numevents)++] = prev;
176 } else {
177 index[(*numevents)++] = prev;
178 }
179
180 index[(*numevents)++] = this;
181 } else {
182 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5,
183 "Bin5 rssi_diff=%d", rssi_diff);
184 }
185 }
186
bin5_rules_check_internal(struct wlan_dfs * dfs,struct dfs_bin5radars * br,uint32_t * bursts,uint32_t * numevents,uint32_t prev,uint32_t i,uint32_t this,int * index)187 void bin5_rules_check_internal(struct wlan_dfs *dfs,
188 struct dfs_bin5radars *br,
189 uint32_t *bursts,
190 uint32_t *numevents,
191 uint32_t prev,
192 uint32_t i,
193 uint32_t this,
194 int *index)
195 {
196 uint64_t pri = 0;
197 uint32_t width_diff = 0;
198
199 /* Rule 1: 1000 <= PRI <= 2000 + some margin. */
200 if (br->br_elems[this].be_ts >= br->br_elems[prev].be_ts) {
201 pri = br->br_elems[this].be_ts - br->br_elems[prev].be_ts;
202 } else {
203 /* Roll over case */
204 pri = br->br_elems[this].be_ts;
205 }
206 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5,
207 " pri=%llu this.ts=%llu this.dur=%d this.rssi=%d prev.ts=%llu",
208 (uint64_t)pri,
209 (uint64_t) br->br_elems[this].be_ts,
210 (int) br->br_elems[this].be_dur,
211 (int) br->br_elems[this].be_rssi,
212 (uint64_t)br->br_elems[prev].be_ts);
213
214 if (((pri >= DFS_BIN5_PRI_LOWER_LIMIT) &&
215 /*pri: pulse repetition interval in us. */
216 (pri <= DFS_BIN5_PRI_HIGHER_LIMIT))) {
217 /*
218 * Rule 2: pulse width of the pulses in the
219 * burst should be same (+/- margin).
220 */
221 if (br->br_elems[this].be_dur >= br->br_elems[prev].be_dur) {
222 width_diff = (br->br_elems[this].be_dur
223 - br->br_elems[prev].be_dur);
224 } else {
225 width_diff = (br->br_elems[prev].be_dur
226 - br->br_elems[this].be_dur);
227 }
228
229 if (width_diff <= DFS_BIN5_WIDTH_MARGIN)
230 /*
231 * Rule 3: RSSI of the pulses in the
232 * burst should be same (+/- margin)
233 */
234 dfs_calculate_bursts_for_same_rssi(dfs, br, bursts,
235 numevents, prev, this, index);
236 else
237 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5,
238 "Bin5 width_diff=%d", width_diff);
239 } else if ((pri >= DFS_BIN5_BRI_LOWER_LIMIT) &&
240 (pri <= DFS_BIN5_BRI_UPPER_LIMIT)) {
241 /* Check pulse width to make sure it is in range of bin 5. */
242 (*bursts)++;
243 } else{
244 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5,
245 "Bin5 PRI check fail pri=%llu", (uint64_t)pri);
246 }
247 }
248
dfs_bin5_check(struct wlan_dfs * dfs)249 int dfs_bin5_check(struct wlan_dfs *dfs)
250 {
251 struct dfs_bin5radars *br;
252 uint32_t n = 0, i = 0, i1 = 0, this = 0, prev = 0;
253 uint32_t bursts = 0, total_diff = 0, average_diff = 0;
254 uint32_t total_width = 0, average_width = 0, numevents = 0;
255 int index[DFS_MAX_B5_SIZE];
256
257 if (!dfs) {
258 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
259 return 1;
260 }
261
262 for (n = 0; n < dfs->dfs_rinfo.rn_numbin5radars; n++) {
263 br = &(dfs->dfs_b5radars[n]);
264 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5, "Num elems = %d",
265 br->br_numelems);
266
267 /* Find a valid bin 5 pulse and use it as reference. */
268 for (i1 = 0; i1 < br->br_numelems; i1++) {
269 this = ((br->br_firstelem + i1) & DFS_MAX_B5_MASK);
270 if ((br->br_elems[this].be_dur >= MIN_BIN5_DUR_MICROSEC)
271 && (br->br_elems[this].be_dur <=
272 MAX_BIN5_DUR_MICROSEC)) {
273 break;
274 }
275 }
276
277 prev = this;
278 for (i = i1 + 1; i < br->br_numelems; i++) {
279 this = ((br->br_firstelem + i) & DFS_MAX_B5_MASK);
280 /*
281 * First make sure it is a bin 5 pulse by checking
282 * the duration.
283 */
284 if ((br->br_elems[this].be_dur < MIN_BIN5_DUR_MICROSEC)
285 || (br->br_elems[this].be_dur >
286 MAX_BIN5_DUR_MICROSEC)) {
287 continue;
288 }
289 bin5_rules_check_internal(dfs, br, &bursts, &numevents,
290 prev, i, this, index);
291 prev = this;
292 }
293
294 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5,
295 "bursts=%u numevents=%u", bursts, numevents);
296 if (bursts >= br->br_pulse.b5_threshold) {
297 if ((br->br_elems[br->br_lastelem].be_ts -
298 br->br_elems[br->br_firstelem].be_ts) <
299 3000000)
300 return 0;
301
302 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5,
303 "bursts=%u numevents=%u total_width=%d average_width=%d total_diff=%d average_diff=%d",
304 bursts, numevents, total_width,
305 average_width, total_diff,
306 average_diff);
307 dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS,
308 "bin 5 radar detected, bursts=%d",
309 bursts);
310 return 1;
311 }
312 }
313
314 return 0;
315 }
316
317 /**
318 * dfs_check_chirping_sowl() - Chirp detection for Sowl/Howl.
319 * @dfs: Pointer to wlan_dfs structure.
320 * @buf: Phyerr buffer.
321 * @datalen: Phyerr buf length
322 * @is_ctl: detected on primary channel.
323 * @is_ext: detected on extension channel.
324 * @slope: Slope
325 * @is_dc: DC found
326 *
327 * Return: Return TRUE if chirping pulse, FALSE if not. Decision is made
328 * based on processing the FFT data included with the PHY error.
329 * Calculate the slope using the maximum bin index reported in
330 * the FFT data. Calculate slope between FFT packet 0 and packet
331 * n-1. Also calculate slope between packet 1 and packet n. If a
332 * pulse is chirping, a slope of 5 and greater is seen.
333 * Non-chirping pulses have slopes of 0, 1, 2 or 3.
334 */
dfs_check_chirping_sowl(struct wlan_dfs * dfs,void * buf,uint16_t datalen,int is_ctl,int is_ext,int * slope,int * is_dc)335 static int dfs_check_chirping_sowl(struct wlan_dfs *dfs,
336 void *buf,
337 uint16_t datalen,
338 int is_ctl,
339 int is_ext,
340 int *slope,
341 int *is_dc)
342 {
343 #define FFT_LEN 70
344 #define FFT_LOWER_BIN_MAX_INDEX_BYTE 66
345 #define FFT_UPPER_BIN_MAX_INDEX_BYTE 69
346 #define MIN_CHIRPING_SLOPE 4
347 int is_chirp = 0;
348 int p, num_fft_packets = 0;
349 int ctl_slope = 0, ext_slope = 0;
350 int ctl_high0 = 0, ctl_low0 = 0, ctl_slope0 = 0;
351 int ext_high0 = 0, ext_low0 = 0, ext_slope0 = 0;
352 int ctl_high1 = 0, ctl_low1 = 0, ctl_slope1 = 0;
353 int ext_high1 = 0, ext_low1 = 0, ext_slope1 = 0;
354 uint8_t *fft_data_ptr;
355
356 *slope = 0;
357 *is_dc = 0;
358 num_fft_packets = datalen / FFT_LEN;
359 fft_data_ptr = (uint8_t *)buf;
360
361 /* DEBUG - Print relevant portions of the FFT data. */
362 for (p = 0; p < num_fft_packets; p++) {
363 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT,
364 "fft_data_ptr=0x%pK\t", fft_data_ptr);
365 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT,
366 "[66]=%d [69]=%d",
367 *(fft_data_ptr + FFT_LOWER_BIN_MAX_INDEX_BYTE) >> 2,
368 *(fft_data_ptr + FFT_UPPER_BIN_MAX_INDEX_BYTE) >> 2);
369 fft_data_ptr += FFT_LEN;
370 }
371
372 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT,
373 "datalen=%d num_fft_packets=%d", datalen, num_fft_packets);
374
375 /*
376 * There is not enough FFT data to figure out whether the pulse
377 * is chirping or not.
378 */
379 if (num_fft_packets < 4)
380 return 0;
381
382 fft_data_ptr = (uint8_t *)buf;
383
384 if (is_ctl) {
385 fft_data_ptr = (uint8_t *)buf;
386 ctl_low0 = *(fft_data_ptr + FFT_LOWER_BIN_MAX_INDEX_BYTE) >> 2;
387 fft_data_ptr += FFT_LEN;
388 ctl_low1 = *(fft_data_ptr + FFT_LOWER_BIN_MAX_INDEX_BYTE) >> 2;
389
390 /* Last packet with first packet. */
391 fft_data_ptr =
392 (uint8_t *)buf + (FFT_LEN * (num_fft_packets - 1));
393 ctl_high1 = *(fft_data_ptr + FFT_LOWER_BIN_MAX_INDEX_BYTE) >> 2;
394
395 /* Second last packet with 0th packet. */
396 fft_data_ptr =
397 (uint8_t *)buf + (FFT_LEN * (num_fft_packets - 2));
398 ctl_high0 = *(fft_data_ptr + FFT_LOWER_BIN_MAX_INDEX_BYTE) >> 2;
399
400 ctl_slope0 = ctl_high0 - ctl_low0;
401 if (ctl_slope0 < 0)
402 ctl_slope0 *= (-1);
403
404 ctl_slope1 = ctl_high1 - ctl_low1;
405 if (ctl_slope1 < 0)
406 ctl_slope1 *= (-1);
407
408 ctl_slope =
409 ((ctl_slope0 > ctl_slope1) ? ctl_slope0 : ctl_slope1);
410 *slope = ctl_slope;
411
412 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT,
413 "ctl_slope0=%d ctl_slope1=%d ctl_slope=%d",
414 ctl_slope0, ctl_slope1, ctl_slope);
415 } else if (is_ext) {
416 fft_data_ptr = (uint8_t *)buf;
417 ext_low0 = *(fft_data_ptr + FFT_UPPER_BIN_MAX_INDEX_BYTE) >> 2;
418
419 fft_data_ptr += FFT_LEN;
420 ext_low1 = *(fft_data_ptr + FFT_UPPER_BIN_MAX_INDEX_BYTE) >> 2;
421
422 fft_data_ptr =
423 (uint8_t *)buf + (FFT_LEN * (num_fft_packets - 1));
424 ext_high1 = *(fft_data_ptr + FFT_UPPER_BIN_MAX_INDEX_BYTE) >> 2;
425 fft_data_ptr =
426 (uint8_t *)buf + (FFT_LEN * (num_fft_packets - 2));
427
428 ext_high0 = *(fft_data_ptr + FFT_UPPER_BIN_MAX_INDEX_BYTE) >> 2;
429
430 ext_slope0 = ext_high0 - ext_low0;
431 if (ext_slope0 < 0)
432 ext_slope0 *= (-1);
433
434 ext_slope1 = ext_high1 - ext_low1;
435 if (ext_slope1 < 0)
436 ext_slope1 *= (-1);
437
438 ext_slope = ((ext_slope0 > ext_slope1) ?
439 ext_slope0 : ext_slope1);
440 *slope = ext_slope;
441 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT | WLAN_DEBUG_DFS_BIN5,
442 "ext_slope0=%d ext_slope1=%d ext_slope=%d",
443 ext_slope0, ext_slope1, ext_slope);
444 } else
445 return 0;
446
447 if ((ctl_slope >= MIN_CHIRPING_SLOPE) ||
448 (ext_slope >= MIN_CHIRPING_SLOPE)) {
449 is_chirp = 1;
450 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5 | WLAN_DEBUG_DFS_BIN5_FFT |
451 WLAN_DEBUG_DFS_PHYERR_SUM, "is_chirp=%d is_dc=%d",
452 is_chirp, *is_dc);
453 }
454
455 return is_chirp;
456
457 #undef FFT_LEN
458 #undef FFT_LOWER_BIN_MAX_INDEX_BYTE
459 #undef FFT_UPPER_BIN_MAX_INDEX_BYTE
460 #undef MIN_CHIRPING_SLOPE
461 }
462
463 /**
464 * dfs_check_chirping_merlin() - Merlin (and Osprey, etc) chirp radar chirp
465 * detection.
466 * @dfs: Pointer to wlan_dfs structure.
467 * @buf: Phyerr buffer
468 * @datalen: Phyerr buf length
469 * @is_ctl: detected on primary channel.
470 * @is_ext: detected on extension channel.
471 * @slope: Slope
472 * @is_dc: DC found
473 */
dfs_check_chirping_merlin(struct wlan_dfs * dfs,void * buf,uint16_t datalen,int is_ctl,int is_ext,int * slope,int * is_dc)474 static int dfs_check_chirping_merlin(struct wlan_dfs *dfs,
475 void *buf,
476 uint16_t datalen,
477 int is_ctl,
478 int is_ext,
479 int *slope,
480 int *is_dc)
481 {
482 #define ABS_DIFF(_x, _y) ((int)_x > (int)_y ? (int)_x - (int)_y : \
483 (int)_y - (int)_x)
484 #define ABS(_x) ((int)_x > 0 ? (int)_x : -(int)_x)
485 /* This should be between 1 and 3. Default is 1. */
486 #define DELTA_STEP 1
487 /* Number of Diffs to compute. valid range is 2-4. */
488 #define NUM_DIFFS 3
489 /* Threshold for difference of delta peaks. */
490 #define MAX_DIFF 2
491 /* Max. number of strong bins for narrow band. */
492 #define BIN_COUNT_MAX 6
493
494 /* Dynamic 20/40 mode FFT packet format related definition. */
495 #define NUM_FFT_BYTES_HT40 70
496 #define NUM_BIN_BYTES_HT40 64
497 #define NUM_SUBCHAN_BINS_HT40 64
498 #define LOWER_INDEX_BYTE_HT40 66
499 #define UPPER_INDEX_BYTE_HT40 69
500 #define LOWER_WEIGHT_BYTE_HT40 64
501 #define UPPER_WEIGHT_BYTE_HT40 67
502 #define LOWER_MAG_BYTE_HT40 65
503 #define UPPER_MAG_BYTE_HT40 68
504
505 /* Static 20 mode FFT packet format related definition. */
506 #define NUM_FFT_BYTES_HT20 31
507 #define NUM_BIN_BYTES_HT20 28
508 #define NUM_SUBCHAN_BINS_HT20 56
509 #define LOWER_INDEX_BYTE_HT20 30
510 #define UPPER_INDEX_BYTE_HT20 30
511 #define LOWER_WEIGHT_BYTE_HT20 28
512 #define UPPER_WEIGHT_BYTE_HT20 28
513 #define LOWER_MAG_BYTE_HT20 29
514 #define UPPER_MAG_BYTE_HT20 29
515
516 int num_fft_packets; /* number of FFT packets reported to software */
517 int num_fft_bytes;
518 int num_bin_bytes;
519 int num_subchan_bins;
520 int lower_index_byte;
521 int upper_index_byte;
522 int lower_weight_byte;
523 int upper_weight_byte;
524 int lower_mag_byte;
525 int upper_mag_byte;
526 int max_index_lower[DELTA_STEP + NUM_DIFFS];
527 int max_index_upper[DELTA_STEP + NUM_DIFFS];
528 int max_mag_lower[DELTA_STEP + NUM_DIFFS];
529 int max_mag_upper[DELTA_STEP + NUM_DIFFS];
530 int bin_wt_lower[DELTA_STEP + NUM_DIFFS];
531 int bin_wt_upper[DELTA_STEP + NUM_DIFFS];
532 int max_mag_sel[DELTA_STEP + NUM_DIFFS];
533 int max_mag[DELTA_STEP + NUM_DIFFS];
534 int max_index[DELTA_STEP + NUM_DIFFS];
535 int max_d[] = {10, 19, 28};
536 int min_d[] = {1, 2, 3};
537 uint8_t *ptr; /* pointer to FFT data */
538 int i;
539 int fft_start;
540 int chirp_found;
541 int delta_peak[NUM_DIFFS];
542 int j;
543 int bin_count;
544 int bw_mask;
545 int delta_diff;
546 int same_sign;
547 int temp;
548
549 if (WLAN_IS_CHAN_11N_HT40(dfs->dfs_curchan)) {
550 num_fft_bytes = NUM_FFT_BYTES_HT40;
551 num_bin_bytes = NUM_BIN_BYTES_HT40;
552 num_subchan_bins = NUM_SUBCHAN_BINS_HT40;
553 lower_index_byte = LOWER_INDEX_BYTE_HT40;
554 upper_index_byte = UPPER_INDEX_BYTE_HT40;
555 lower_weight_byte = LOWER_WEIGHT_BYTE_HT40;
556 upper_weight_byte = UPPER_WEIGHT_BYTE_HT40;
557 lower_mag_byte = LOWER_MAG_BYTE_HT40;
558 upper_mag_byte = UPPER_MAG_BYTE_HT40;
559
560 /* If we are in HT40MINUS then swap primary and extension. */
561 if (WLAN_IS_CHAN_11N_HT40MINUS(dfs->dfs_curchan)) {
562 temp = is_ctl;
563 is_ctl = is_ext;
564 is_ext = temp;
565 }
566 } else {
567 num_fft_bytes = NUM_FFT_BYTES_HT20;
568 num_bin_bytes = NUM_BIN_BYTES_HT20;
569 num_subchan_bins = NUM_SUBCHAN_BINS_HT20;
570 lower_index_byte = LOWER_INDEX_BYTE_HT20;
571 upper_index_byte = UPPER_INDEX_BYTE_HT20;
572 lower_weight_byte = LOWER_WEIGHT_BYTE_HT20;
573 upper_weight_byte = UPPER_WEIGHT_BYTE_HT20;
574 lower_mag_byte = LOWER_MAG_BYTE_HT20;
575 upper_mag_byte = UPPER_MAG_BYTE_HT20;
576 }
577
578 ptr = (uint8_t *)buf;
579 /* Sanity check for FFT buffer. */
580 if (!ptr || (datalen == 0)) {
581 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT,
582 "FFT buffer pointer is null or size is 0");
583 return 0;
584 }
585
586 num_fft_packets = (datalen - 3) / num_fft_bytes;
587 if (num_fft_packets < (NUM_DIFFS + DELTA_STEP)) {
588 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT,
589 "datalen = %d, num_fft_packets = %d, too few packets... (exiting)",
590 datalen, num_fft_packets);
591 return 0;
592 }
593
594 if ((((datalen - 3) % num_fft_bytes) == 2) &&
595 (datalen > num_fft_bytes)) {
596 ptr += 2;
597 datalen -= 2;
598 }
599
600 for (i = 0; i < (NUM_DIFFS + DELTA_STEP); i++) {
601 fft_start = i * num_fft_bytes;
602 bin_wt_lower[i] = ptr[fft_start + lower_weight_byte] & 0x3f;
603 bin_wt_upper[i] = ptr[fft_start + upper_weight_byte] & 0x3f;
604 max_index_lower[i] = ptr[fft_start + lower_index_byte] >> 2;
605 max_index_upper[i] = (ptr[fft_start + upper_index_byte] >> 2) +
606 num_subchan_bins;
607
608 if (!WLAN_IS_CHAN_11N_HT40(dfs->dfs_curchan)) {
609 /* For HT20 mode indices are 6 bit signed number. */
610 max_index_lower[i] ^= 0x20;
611 max_index_upper[i] = 0;
612 }
613
614 /*
615 * Reconstruct the maximum magnitude for each sub-channel.
616 * Also select and flag the max overall magnitude between
617 * the two sub-channels.
618 */
619
620 max_mag_lower[i] =
621 ((ptr[fft_start + lower_index_byte] & 0x03) << 8) +
622 ptr[fft_start + lower_mag_byte];
623 max_mag_upper[i] =
624 ((ptr[fft_start + upper_index_byte] & 0x03) << 8) +
625 ptr[fft_start + upper_mag_byte];
626 bw_mask = ((bin_wt_lower[i] == 0) ? 0 : is_ctl) +
627 (((bin_wt_upper[i] == 0) ? 0 : is_ext) << 1);
628
629 /*
630 * Limit the max bin based on channel bandwidth
631 * If the upper sub-channel max index is stuck at '1',
632 * the signal is dominated * by residual DC
633 * (or carrier leak) and should be ignored.
634 */
635
636 if (bw_mask == 1) {
637 max_mag_sel[i] = 0;
638 max_mag[i] = max_mag_lower[i];
639 max_index[i] = max_index_lower[i];
640 } else if (bw_mask == 2) {
641 max_mag_sel[i] = 1;
642 max_mag[i] = max_mag_upper[i];
643 max_index[i] = max_index_upper[i];
644 } else if (max_index_upper[i] == num_subchan_bins) {
645 max_mag_sel[i] = 0; /* Ignore DC bin. */
646 max_mag[i] = max_mag_lower[i];
647 max_index[i] = max_index_lower[i];
648 } else {
649 if (max_mag_upper[i] > max_mag_lower[i]) {
650 max_mag_sel[i] = 1;
651 max_mag[i] = max_mag_upper[i];
652 max_index[i] = max_index_upper[i];
653 } else {
654 max_mag_sel[i] = 0;
655 max_mag[i] = max_mag_lower[i];
656 max_index[i] = max_index_lower[i];
657 }
658 }
659 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT,
660 "i=%d, max_index[i]=%d, max_index_lower[i]=%d, max_index_upper[i]=%d",
661 i, max_index[i], max_index_lower[i],
662 max_index_upper[i]);
663 }
664
665 chirp_found = 1;
666 delta_diff = 0;
667 same_sign = 1;
668
669 /*
670 * delta_diff computation -- look for movement in peak.
671 * make sure that the chirp direction (i.e. sign) is
672 * always the same, i.e. sign of the two peaks should
673 * be same.
674 */
675 for (i = 0; i < NUM_DIFFS; i++) {
676 delta_peak[i] = max_index[i + DELTA_STEP] - max_index[i];
677 if (i > 0) {
678 delta_diff = delta_peak[i] - delta_peak[i-1];
679 same_sign = !((delta_peak[i] & 0x80) ^
680 (delta_peak[i-1] & 0x80));
681 }
682 chirp_found &=
683 (ABS(delta_peak[i]) >= min_d[DELTA_STEP - 1]) &&
684 (ABS(delta_peak[i]) <= max_d[DELTA_STEP - 1]) &&
685 same_sign && (ABS(delta_diff) <= MAX_DIFF);
686 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT,
687 "i=%d, delta_peak[i]=%d, delta_diff=%d",
688 i, delta_peak[i], delta_diff);
689 }
690
691 if (chirp_found) {
692 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT,
693 "CHIRPING_BEFORE_STRONGBIN_YES");
694 } else {
695 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT,
696 "CHIRPING_BEFORE_STRONGBIN_NO");
697 }
698
699 /*
700 * Work around for potential hardware data corruption bug.
701 * Check for wide band signal by counting strong bins
702 * indicated by bitmap flags. This check is done if
703 * chirp_found is true. We do this as a final check to
704 * weed out corrupt FFTs bytes. This looks expensive but
705 * in most cases it will exit early.
706 */
707
708 for (i = 0; (i < (NUM_DIFFS + DELTA_STEP)) &&
709 (chirp_found == 1); i++) {
710 bin_count = 0;
711 /*
712 * Point to the start of the 1st byte of the selected
713 * sub-channel.
714 */
715 fft_start = (i * num_fft_bytes) + (max_mag_sel[i] ?
716 (num_subchan_bins >> 1) : 0);
717 for (j = 0; j < (num_subchan_bins >> 1); j++) {
718 /*
719 * If either bin is flagged "strong", accumulate
720 * the bin_count. It's not accurate, but good
721 * enough...
722 */
723 bin_count += (ptr[fft_start + j] & 0x88) ? 1 : 0;
724 }
725 chirp_found &= (bin_count > BIN_COUNT_MAX) ? 0 : 1;
726 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT,
727 "i=%d, computed bin_count=%d",
728 i, bin_count);
729 }
730
731 if (chirp_found) {
732 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT |
733 WLAN_DEBUG_DFS_PHYERR_SUM,
734 "CHIRPING_YES");
735 } else {
736 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT |
737 WLAN_DEBUG_DFS_PHYERR_SUM,
738 "CHIRPING_NO");
739 }
740
741 return chirp_found;
742 #undef ABS_DIFF
743 #undef ABS
744 #undef DELTA_STEP
745 #undef NUM_DIFFS
746 #undef MAX_DIFF
747 #undef BIN_COUNT_MAX
748
749 #undef NUM_FFT_BYTES_HT40
750 #undef NUM_BIN_BYTES_HT40
751 #undef NUM_SUBCHAN_BINS_HT40
752 #undef LOWER_INDEX_BYTE_HT40
753 #undef UPPER_INDEX_BYTE_HT40
754 #undef LOWER_WEIGHT_BYTE_HT40
755 #undef UPPER_WEIGHT_BYTE_HT40
756 #undef LOWER_MAG_BYTE_HT40
757 #undef UPPER_MAG_BYTE_HT40
758
759 #undef NUM_FFT_BYTES_HT40
760 #undef NUM_BIN_BYTES_HT40
761 #undef NUM_SUBCHAN_BINS_HT40
762 #undef LOWER_INDEX_BYTE_HT40
763 #undef UPPER_INDEX_BYTE_HT40
764 #undef LOWER_WEIGHT_BYTE_HT40
765 #undef UPPER_WEIGHT_BYTE_HT40
766 #undef LOWER_MAG_BYTE_HT40
767 #undef UPPER_MAG_BYTE_HT40
768 }
769
dfs_check_chirping(struct wlan_dfs * dfs,void * buf,uint16_t datalen,int is_ctl,int is_ext,int * slope,int * is_dc)770 int dfs_check_chirping(struct wlan_dfs *dfs,
771 void *buf,
772 uint16_t datalen,
773 int is_ctl,
774 int is_ext,
775 int *slope,
776 int *is_dc)
777 {
778 if (dfs->dfs_caps.wlan_dfs_use_enhancement) {
779 return dfs_check_chirping_merlin(dfs, buf, datalen, is_ctl,
780 is_ext, slope, is_dc);
781 } else {
782 return dfs_check_chirping_sowl(dfs, buf, datalen, is_ctl,
783 is_ext, slope, is_dc);
784 }
785 }
786
dfs_retain_bin5_burst_pattern(struct wlan_dfs * dfs,uint32_t diff_ts,uint8_t old_dur)787 uint8_t dfs_retain_bin5_burst_pattern(struct wlan_dfs *dfs,
788 uint32_t diff_ts,
789 uint8_t old_dur)
790 {
791 /*
792 * Pulses may get split into 2 during chirping, this print
793 * is only to show that it happened, we do not handle this
794 * condition if we cannot detect the chirping.
795 */
796 /* SPLIT pulses will have a time stamp difference of < 50 */
797 if (diff_ts < 50) {
798 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5,
799 "SPLIT pulse diffTs=%u dur=%d (old_dur=%d)",
800 diff_ts,
801 dfs->dfs_rinfo.dfs_last_bin5_dur, old_dur);
802 }
803
804 /*
805 * Check if this is the 2nd or 3rd pulse in the same burst,
806 * PRI will be between 1000 and 2000 us.
807 */
808 if (((diff_ts >= DFS_BIN5_PRI_LOWER_LIMIT) &&
809 (diff_ts <= DFS_BIN5_PRI_HIGHER_LIMIT))) {
810 /*
811 * This pulse belongs to the same burst as the pulse before,
812 * so return the same random duration for it.
813 */
814 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5,
815 "this pulse belongs to the same burst as before, give it same dur=%d (old_dur=%d)",
816 dfs->dfs_rinfo.dfs_last_bin5_dur, old_dur);
817 return dfs->dfs_rinfo.dfs_last_bin5_dur;
818 }
819
820 /* This pulse does not belong to this burst, return unchanged duration*/
821 return old_dur;
822 }
823
dfs_get_random_bin5_dur(struct wlan_dfs * dfs,uint64_t tstamp)824 int dfs_get_random_bin5_dur(struct wlan_dfs *dfs,
825 uint64_t tstamp)
826 {
827 uint8_t new_dur = MIN_BIN5_DUR;
828 int range;
829
830 get_random_bytes(&new_dur, sizeof(uint8_t));
831 range = (MAX_BIN5_DUR - MIN_BIN5_DUR + 1);
832 new_dur %= range;
833 new_dur += MIN_BIN5_DUR;
834
835 return new_dur;
836 }
837