1 /*
2 * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2002-2010, Atheros Communications Inc.
4 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
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: For each radar pulse that the HW detects, a single radar PHY error is
21 * reported to the driver. This PHY error contains information like the RSSI,
22 * the pulse duration, the pulse location (primary/extension/DC) and possibly
23 * FFT data.
24 */
25
26 #include "../dfs.h"
27 #include "../dfs_zero_cac.h"
28 #include "../dfs_channel.h"
29 #include "wlan_dfs_mlme_api.h"
30 #include "../dfs_internal.h"
31
32 #ifdef WLAN_DFS_PARTIAL_OFFLOAD
33 /**
34 * dfs_get_event_freqwidth() - Get frequency width.
35 * @dfs: Pointer to wlan_dfs structure.
36 *
37 * Return: Return the frequency width for the current operating channel.
38 * This isn't the channel width - it's how wide the reported event may be.
39 * For HT20 this is 20MHz. For HT40 on Howl and later it'll still be 20MHz
40 * - the hardware returns either pri or ext channel.
41 */
dfs_get_event_freqwidth(struct wlan_dfs * dfs)42 static inline int dfs_get_event_freqwidth(struct wlan_dfs *dfs)
43 {
44 /* Handle edge cases during startup/transition, shouldn't happen! */
45 if (!dfs)
46 return 0;
47
48 if (!dfs->dfs_curchan)
49 return 0;
50
51 /*
52 * For now, assume 20MHz wide - but this is incorrect when operating in
53 * half/quarter mode!
54 */
55 return 20;
56 }
57
58 /**
59 * dfs_get_event_freqcentre() - Get event frequency centre.
60 * @dfs: Pointer to wlan_dfs structure.
61 * @is_pri: detected on primary channel.
62 * @is_ext: detected on extension channel.
63 * @is_dc: detected at DC.
64 *
65 * Return the centre frequency for the current operating channel and event.
66 * This is for post-Owl 11n chips which report pri/extension channel events.
67 */
dfs_get_event_freqcentre(struct wlan_dfs * dfs,int is_pri,int is_ext,int is_dc)68 static inline uint16_t dfs_get_event_freqcentre(struct wlan_dfs *dfs,
69 int is_pri,
70 int is_ext,
71 int is_dc)
72 {
73 int chan_offset = 0, chan_width;
74
75 /* Handle edge cases during startup/transition, shouldn't happen! */
76 if (!dfs)
77 return 0;
78 if (!dfs->dfs_curchan)
79 return 0;
80
81 /*
82 * For wide channels, DC and ext frequencies need a bit of hand-holding
83 * based on whether it's an upper or lower channel.
84 */
85 chan_width = dfs_get_event_freqwidth(dfs);
86
87 if (WLAN_IS_CHAN_11N_HT40PLUS(dfs->dfs_curchan))
88 chan_offset = chan_width;
89 else if (WLAN_IS_CHAN_11N_HT40MINUS(dfs->dfs_curchan))
90 chan_offset = -chan_width;
91 else
92 chan_offset = 0;
93
94 /*
95 * Check for DC events first - the sowl code may just set all the bits
96 * together.
97 */
98 if (is_dc) {
99 /* XXX TODO: Should DC events be considered 40MHz wide here? */
100 return dfs_chan2freq(
101 dfs->dfs_curchan) + (chan_offset / 2);
102 }
103
104 /*
105 * For non-wide channels, the centre frequency is just dfs_ch_freq.
106 * The centre frequency for pri events is still dfs_ch_freq.
107 */
108 if (is_pri)
109 return dfs_chan2freq(dfs->dfs_curchan);
110
111 if (is_ext)
112 return dfs_chan2freq(dfs->dfs_curchan) + chan_width;
113
114 return dfs_chan2freq(dfs->dfs_curchan);
115 }
116
117 /**
118 * dfs_process_phyerr_owl() - Process an Owl-style phy error.
119 * @dfs: Pointer to wlan_dfs structure.
120 * @buf: Phyerr buffer
121 * @datalen: Phyerr buf len
122 * @rssi: RSSI
123 * @ext_rssi: Extension RSSI.
124 * @rs_tstamp: Time stamp.
125 * @fulltsf: TSF64.
126 * @e: Pointer to dfs_phy_err structure.
127 *
128 * Return: Returns 1.
129 */
dfs_process_phyerr_owl(struct wlan_dfs * dfs,void * buf,uint16_t datalen,uint8_t rssi,uint8_t ext_rssi,uint32_t rs_tstamp,uint64_t fulltsf,struct dfs_phy_err * e)130 static int dfs_process_phyerr_owl(struct wlan_dfs *dfs,
131 void *buf,
132 uint16_t datalen,
133 uint8_t rssi,
134 uint8_t ext_rssi,
135 uint32_t rs_tstamp,
136 uint64_t fulltsf,
137 struct dfs_phy_err *e)
138 {
139 const char *cbuf = (const char *) buf;
140 uint8_t dur;
141 int event_width;
142
143 dfs->wlan_dfs_stats.owl_phy_errors++;
144
145 /*
146 * HW cannot detect extension channel radar so it only passes us primary
147 * channel radar data.
148 */
149 if (datalen == 0)
150 dur = 0;
151 else
152 dur = ((uint8_t *) cbuf)[0];
153
154 /* This is a spurious event; toss. */
155 if (rssi == 0 && dur == 0) {
156 dfs->wlan_dfs_stats.datalen_discards++;
157 return 0;
158 }
159
160 /* Fill out dfs_phy_err with the information we have at hand. */
161 qdf_mem_zero(e, sizeof(*e));
162 e->rssi = rssi;
163 e->dur = dur;
164 e->is_pri = 1;
165 e->is_ext = 0;
166 e->is_dc = 0;
167 e->is_early = 1;
168 e->fulltsf = fulltsf;
169 e->rs_tstamp = rs_tstamp;
170
171 /*
172 * Owl only ever reports events on the primary channel. It doesn't
173 * even see events on the secondary channel.
174 */
175 event_width = dfs_get_event_freqwidth(dfs);
176 e->freq = dfs_get_event_freqcentre(dfs, 1, 0, 0) * 1000;
177 e->freq_lo = e->freq - (event_width / 2) * 1000;
178 e->freq_hi = e->freq + (event_width / 2) * 1000;
179
180 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR_SUM,
181 "rssi=%u dur=%u, freq=%d MHz, freq_lo=%d MHz, freq_hi=%d MHz",
182 rssi, dur, e->freq/1000, e->freq_lo/1000,
183 e->freq_hi / 1000);
184
185 return 1;
186 }
187
188 /**
189 * dfs_process_phyerr_sowl() -Process a Sowl/Howl style phy error.
190 * @dfs: Pointer to wlan_dfs structure.
191 * @buf: Phyerr buffer
192 * @datalen: Phyerr buf len
193 * @rssi: RSSI
194 * @ext_rssi: Extension RSSI.
195 * @rs_tstamp: Time stamp.
196 * @fulltsf: TSF64.
197 * @e: Pointer to dfs_phy_err structure.
198 *
199 * Return: Returns 1.
200 */
dfs_process_phyerr_sowl(struct wlan_dfs * dfs,void * buf,uint16_t datalen,uint8_t rssi,uint8_t ext_rssi,uint32_t rs_tstamp,uint64_t fulltsf,struct dfs_phy_err * e)201 static int dfs_process_phyerr_sowl(struct wlan_dfs *dfs,
202 void *buf,
203 uint16_t datalen,
204 uint8_t rssi,
205 uint8_t ext_rssi,
206 uint32_t rs_tstamp,
207 uint64_t fulltsf,
208 struct dfs_phy_err *e)
209 {
210 #define EXT_CH_RADAR_FOUND 0x02
211 #define PRI_CH_RADAR_FOUND 0x01
212 #define EXT_CH_RADAR_EARLY_FOUND 0x04
213 const char *cbuf = (const char *)buf;
214 uint8_t dur = 0;
215 uint8_t pulse_bw_info, pulse_length_ext, pulse_length_pri;
216 int pri_found = 0, ext_found = 0;
217 int early_ext = 0;
218 int event_width;
219
220 /*
221 * If radar can be detected on the extension channel, datalen zero
222 * pulses are bogus, discard them.
223 */
224 if (!datalen) {
225 dfs->wlan_dfs_stats.datalen_discards++;
226 return 0;
227 }
228
229 /* Ensure that we have at least three bytes of payload. */
230 if (datalen < 3) {
231 dfs_debug(dfs, WLAN_DEBUG_DFS,
232 "short error frame (%d bytes)", datalen);
233 dfs->wlan_dfs_stats.datalen_discards++;
234 return 0;
235 }
236
237 /*
238 * Fetch the payload directly - the compiler will happily generate
239 * byte-read instructions with a const char * cbuf pointer.
240 */
241 pulse_length_pri = cbuf[datalen - 3];
242 pulse_length_ext = cbuf[datalen - 2];
243 pulse_bw_info = cbuf[datalen - 1];
244
245 /*
246 * Only the last 3 bits of the BW info are relevant, they indicate
247 * which channel the radar was detected in.
248 */
249 pulse_bw_info &= 0x07;
250
251 /* If pulse on DC, both primary and extension flags will be set */
252 if (((pulse_bw_info & EXT_CH_RADAR_FOUND) &&
253 (pulse_bw_info & PRI_CH_RADAR_FOUND))) {
254 /*
255 * Conducted testing, when pulse is on DC, both pri and ext
256 * durations are reported to be same. Radiated testing, when
257 * pulse is on DC, differentpri and ext durations are reported,
258 * so take the larger of the two.
259 */
260 if (pulse_length_ext >= pulse_length_pri) {
261 dur = pulse_length_ext;
262 ext_found = 1;
263 } else {
264 dur = pulse_length_pri;
265 pri_found = 1;
266 }
267 dfs->wlan_dfs_stats.dc_phy_errors++;
268 } else {
269 if (pulse_bw_info & EXT_CH_RADAR_FOUND) {
270 dur = pulse_length_ext;
271 pri_found = 0;
272 ext_found = 1;
273 dfs->wlan_dfs_stats.ext_phy_errors++;
274 }
275 if (pulse_bw_info & PRI_CH_RADAR_FOUND) {
276 dur = pulse_length_pri;
277 pri_found = 1;
278 ext_found = 0;
279 dfs->wlan_dfs_stats.pri_phy_errors++;
280 }
281 if (pulse_bw_info & EXT_CH_RADAR_EARLY_FOUND) {
282 dur = pulse_length_ext;
283 pri_found = 0;
284 ext_found = 1;
285 early_ext = 1;
286 dfs->wlan_dfs_stats.early_ext_phy_errors++;
287 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
288 "EARLY ext channel dur=%u rssi=%u datalen=%d",
289 dur, rssi, datalen);
290 }
291 if (!pulse_bw_info) {
292 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
293 "ERROR channel dur=%u rssi=%u pulse_bw_info=0x%x datalen MOD 4 = %d",
294 dur, rssi, pulse_bw_info, (datalen & 0x3));
295 /*
296 * Bogus bandwidth info received in descriptor, so
297 * ignore this PHY error.
298 */
299 dfs->wlan_dfs_stats.bwinfo_errors++;
300 return 0;
301 }
302 }
303
304 /*
305 * Always use combined RSSI reported, unless RSSI reported on
306 * extension is stronger.
307 */
308 if ((ext_rssi > rssi) && (ext_rssi < 128))
309 rssi = ext_rssi;
310
311 /* Fill out the rssi/duration fields from above. */
312 qdf_mem_zero(e, sizeof(*e));
313 e->rssi = rssi;
314 e->dur = dur;
315 e->is_pri = pri_found;
316 e->is_ext = ext_found;
317 e->is_dc = !!(((pulse_bw_info & EXT_CH_RADAR_FOUND) &&
318 (pulse_bw_info & PRI_CH_RADAR_FOUND)));
319 e->is_early = early_ext;
320 e->fulltsf = fulltsf;
321 e->rs_tstamp = rs_tstamp;
322
323 /* Sowl and later can report pri/ext events. */
324 event_width = dfs_get_event_freqwidth(dfs);
325 e->freq = dfs_get_event_freqcentre(dfs, e->is_pri, e->is_ext,
326 e->is_dc) * 1000;
327 e->freq_lo = e->freq - (event_width / 2) * 1000;
328 e->freq_hi = e->freq + (event_width / 2) * 1000;
329
330 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR_SUM,
331 "pulse_bw_info=0x%x pulse_length_ext=%u pulse_length_pri=%u rssi=%u ext_rssi=%u, freq=%d MHz, freq_lo=%d MHz, freq_hi=%d MHz",
332 pulse_bw_info, pulse_length_ext, pulse_length_pri,
333 rssi, ext_rssi, e->freq/1000, e->freq_lo/1000, e->freq_hi/1000);
334 #undef EXT_CH_RADAR_FOUND
335 #undef PRI_CH_RADAR_FOUND
336 #undef EXT_CH_RADAR_EARLY_FOUND
337
338 return 1;
339 }
340
341 /**
342 * dfs_process_phyerr_merlin() - Process a Merlin/Osprey style phy error.
343 * dfs_phy_err struct.
344 * @dfs: Pointer to wlan_dfs structure.
345 * @buf: Phyerr buffer
346 * @datalen: Phyerr buf len
347 * @rssi: RSSI
348 * @ext_rssi: Extension RSSI.
349 * @rs_tstamp: Time stamp.
350 * @fulltsf: TSF64.
351 * @e: Pointer to dfs_phy_err structure.
352 *
353 * Return: Returns 1.
354 */
dfs_process_phyerr_merlin(struct wlan_dfs * dfs,void * buf,uint16_t datalen,uint8_t rssi,uint8_t ext_rssi,uint32_t rs_tstamp,uint64_t fulltsf,struct dfs_phy_err * e)355 static int dfs_process_phyerr_merlin(struct wlan_dfs *dfs,
356 void *buf,
357 uint16_t datalen,
358 uint8_t rssi,
359 uint8_t ext_rssi,
360 uint32_t rs_tstamp,
361 uint64_t fulltsf,
362 struct dfs_phy_err *e)
363 {
364 const char *cbuf = (const char *) buf;
365 uint8_t pulse_bw_info = 0;
366
367 /* Process using the sowl code. */
368 if (!dfs_process_phyerr_sowl(dfs, buf, datalen, rssi, ext_rssi,
369 rs_tstamp, fulltsf, e)) {
370 return 0;
371 }
372
373 /*
374 * For osprey (and Merlin) bw_info has implication for selecting RSSI
375 * value. So re-fetch the bw_info field so the RSSI values can be
376 * appropriately overridden.
377 */
378 pulse_bw_info = cbuf[datalen - 1];
379
380 switch (pulse_bw_info & 0x03) {
381 case 0x00:
382 /* No radar in ctrl or ext channel */
383 rssi = 0;
384 break;
385 case 0x01:
386 /* Radar in ctrl channel */
387 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
388 "RAW RSSI: rssi=%u ext_rssi=%u", rssi, ext_rssi);
389 if (ext_rssi >= (rssi + 3)) {
390 /*
391 * Cannot use ctrl channel RSSI if extension channel is
392 * stronger.
393 */
394 rssi = 0;
395 }
396 break;
397 case 0x02:
398 /* Radar in extension channel */
399 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
400 "RAW RSSI: rssi=%u ext_rssi=%u", rssi, ext_rssi);
401 if (rssi >= (ext_rssi + 12)) {
402 /*
403 * Cannot use extension channel RSSI if control channel
404 * is stronger
405 */
406 rssi = 0;
407 } else {
408 rssi = ext_rssi;
409 }
410 break;
411 case 0x03:
412 /* When both are present use stronger one */
413 if (rssi < ext_rssi)
414 rssi = ext_rssi;
415 break;
416 }
417
418 /*
419 * Override the rssi decision made by the sowl code. The rest of the
420 * fields (duration, timestamp, etc) are left untouched.
421 */
422 e->rssi = rssi;
423
424 return 1;
425 }
426
427 /**
428 * dfs_dump_phyerr_contents() - Dump the phyerr contents.
429 * @d: Phyerr buffer.
430 * @len: Phyerr buf length.
431 */
432
dfs_dump_phyerr_contents(const char * d,int len)433 static void dfs_dump_phyerr_contents(const char *d, int len)
434 {
435 int i, n, bufsize = 64;
436
437 /*
438 * This is statically sized for a 4-digit address + 16 * 2 digit data
439 * string. It's done so the printk() passed to the kernel is an entire
440 * line, so the kernel logging code will atomically print it. Otherwise
441 * we'll end up with interleaved lines with output from other kernel
442 * threads.
443 */
444 char buf[64];
445
446 /* Initial conditions */
447 buf[0] = '\n';
448 n = 0;
449
450 for (i = 0; i < len; i++) {
451 if (i % 16 == 0)
452 n += snprintf(buf + n, bufsize - n, "%04x: ", i);
453
454 n += snprintf(buf + n, bufsize - n, "%02x ", d[i] & 0xff);
455 if (i % 16 == 15) {
456 dfs_debug(NULL, WLAN_DEBUG_DFS_ALWAYS, "%s", buf);
457 n = 0;
458 buf[0] = '\0';
459 }
460 }
461
462 /* Print the final line if we didn't print it above. */
463 if (n != 0)
464 dfs_debug(NULL, WLAN_DEBUG_DFS_ALWAYS, "%s", buf);
465 }
466
467 /**
468 * dfs_bump_up_bin5_pulse_dur() - Bump up to a random BIN 5 pulse duration.
469 * @dfs: Pointer to wlan_dfs structure.
470 * @e: Pointer to dfs_phy_err structure.
471 * @slope: Slope value.
472 */
dfs_bump_up_bin5_pulse_dur(struct wlan_dfs * dfs,struct dfs_phy_err * e,int slope)473 static inline void dfs_bump_up_bin5_pulse_dur(
474 struct wlan_dfs *dfs,
475 struct dfs_phy_err *e,
476 int slope)
477 {
478 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR, "old dur %d slope =%d",
479 e->dur, slope);
480
481 e->is_sw_chirp = 1;
482 /* bump up to a random bin5 pulse duration */
483 if (e->dur < MIN_BIN5_DUR)
484 e->dur = dfs_get_random_bin5_dur(dfs, e->fulltsf);
485
486 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR, "new dur %d", e->dur);
487 }
488
489 /**
490 * dfs_filter_short_pulses() - Filter short pulses.
491 * @dfs: Pointer to wlan_dfs structure.
492 * @e: Pointer to dfs_phy_err structure.
493 * @retval: Return value
494 *
495 * Rssi is not accurate for short pulses, so donot filter based on that for
496 * short duration pulses.
497 */
dfs_filter_short_pulses(struct wlan_dfs * dfs,struct dfs_phy_err * e,int * retval)498 static inline void dfs_filter_short_pulses(
499 struct wlan_dfs *dfs,
500 struct dfs_phy_err *e,
501 int *retval)
502 {
503 if (dfs->dfs_caps.wlan_dfs_ext_chan_ok) {
504 if ((e->rssi < dfs->dfs_rinfo.rn_minrssithresh &&
505 (e->dur > MAX_DUR_FOR_LOW_RSSI)) ||
506 e->dur > (dfs->dfs_rinfo.rn_maxpulsedur)) {
507 dfs->wlan_dfs_stats.rssi_discards++;
508 *retval = 1;
509 }
510 } else if (e->rssi < dfs->dfs_rinfo.rn_minrssithresh ||
511 e->dur > dfs->dfs_rinfo.rn_maxpulsedur) {
512 dfs->wlan_dfs_stats.rssi_discards++;
513 *retval = 1;
514 }
515
516 if (*retval) {
517 dfs_debug(dfs, WLAN_DEBUG_DFS1,
518 "%s pulse is discarded: dur=%d, maxpulsedur=%d, rssi=%d, minrssi=%d",
519 (dfs->dfs_caps.wlan_dfs_ext_chan_ok) ?
520 "Extension channel" : "",
521 e->dur, dfs->dfs_rinfo.rn_maxpulsedur,
522 e->rssi, dfs->dfs_rinfo.rn_minrssithresh);
523 }
524 }
525
526 /**
527 * dfs_set_chan_index() - Set channel index.
528 * @dfs: Pointer to wlan_dfs structure.
529 * @e: Pointer to dfs_phy_err structure.
530 * @event: Pointer to dfs_event structure.
531 */
dfs_set_chan_index(struct wlan_dfs * dfs,struct dfs_phy_err * e,struct dfs_event * event)532 static inline void dfs_set_chan_index(
533 struct wlan_dfs *dfs,
534 struct dfs_phy_err *e,
535 struct dfs_event *event)
536 {
537 if (e->is_pri) {
538 event->re_chanindex = dfs->dfs_curchan_radindex;
539 } else {
540 event->re_chanindex = dfs->dfs_extchan_radindex;
541 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
542 "%s New extension channel event is added to queue",
543 (event->re_chanindex == -1) ?
544 "- phyerr on ext channel" : "");
545 }
546 }
547
548 /**
549 * dfs_is_second_seg_radar_disabled() - Check for second segment radar disabled.
550 * @dfs: Pointer to wlan_dfs structure.
551 * @seg_id: Segment id.
552 *
553 * Return: true if the second segment RADAR is enabled else false.
554 */
dfs_is_second_seg_radar_disabled(struct wlan_dfs * dfs,int seg_id)555 static bool dfs_is_second_seg_radar_disabled(
556 struct wlan_dfs *dfs, int seg_id)
557 {
558 if ((seg_id == SEG_ID_SECONDARY) &&
559 !(dfs->dfs_proc_phyerr & DFS_SECOND_SEGMENT_RADAR_EN)) {
560 dfs_debug(dfs, WLAN_DEBUG_DFS3,
561 "Second segment radar detection is disabled");
562 return true;
563 }
564
565 return false;
566 }
567
dfs_process_phyerr(struct wlan_dfs * dfs,void * buf,uint16_t datalen,uint8_t r_rssi,uint8_t r_ext_rssi,uint32_t r_rs_tstamp,uint64_t r_fulltsf)568 void dfs_process_phyerr(struct wlan_dfs *dfs, void *buf, uint16_t datalen,
569 uint8_t r_rssi, uint8_t r_ext_rssi, uint32_t r_rs_tstamp,
570 uint64_t r_fulltsf)
571 {
572 struct dfs_event *event;
573 struct dfs_phy_err e;
574 int empty;
575
576 if (!dfs) {
577 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
578 return;
579 }
580
581 if (dfs->dfs_ignore_dfs) {
582 dfs_debug(dfs, WLAN_DEBUG_DFS1, "ignoring dfs");
583 return;
584 }
585
586 /*
587 * EV 129487: If radar detection is disabled, do not process PHY error
588 * data.
589 */
590
591 if (!(dfs->dfs_proc_phyerr & DFS_RADAR_EN)) {
592 dfs_debug(dfs, WLAN_DEBUG_DFS1,
593 "DFS_RADAR_EN not set in dfs->dfs_proc_phyerr");
594 return;
595 }
596
597 /*
598 * The combined_rssi_ok support has been removed. This was only clear
599 * for Owl.
600 * XXX TODO: re-add this; it requires passing in the ctl/ext
601 * RSSI set from the RX status descriptor.
602 * XXX TODO : this may be done for us from the legacy phy error path in
603 * wlan_dev; please review that code.
604 */
605
606 /*
607 * At this time we have a radar pulse that we need to examine and
608 * queue. But if dfs_process_radarevent already detected radar and set
609 * CHANNEL_INTERFERENCE flag then do not queue any more radar data.
610 * When we are in a new channel this flag will be clear and we will
611 * start queueing data for new channel. (EV74162)
612 */
613 if (dfs->dfs_debug_mask & WLAN_DEBUG_DFS_PHYERR_PKT)
614 dfs_dump_phyerr_contents(buf, datalen);
615
616 if (WLAN_IS_CHAN_RADAR(dfs, dfs->dfs_curchan)) {
617 dfs_debug(dfs, WLAN_DEBUG_DFS1,
618 "Radar already found in the channel, do not queue radar data");
619 return;
620 }
621 dfs->dfs_phyerr_count++;
622 dfs->wlan_dfs_stats.total_phy_errors++;
623 dfs_debug(dfs, WLAN_DEBUG_DFS2, "phyerr %d len %d",
624 dfs->wlan_dfs_stats.total_phy_errors, datalen);
625
626 /*
627 * Hardware stores this as 8 bit signed value. we will cap it at 0 if it
628 * is a negative number.
629 */
630 if (r_rssi & 0x80)
631 r_rssi = 0;
632
633 if (r_ext_rssi & 0x80)
634 r_ext_rssi = 0;
635
636 qdf_mem_zero(&e, sizeof(e));
637
638 /*
639 * This is a bit evil - instead of just passing in the chip version, the
640 * existing code uses a set of HAL capability bits to determine what is
641 * possible.
642 * The way I'm decoding it is thus:
643 * + DFS enhancement? Merlin or later
644 * + DFS extension channel? Sowl or later. (Howl?)
645 * + otherwise, Owl (and legacy.)
646 */
647 if (dfs->dfs_caps.wlan_chip_is_bb_tlv) {
648 if (dfs_process_phyerr_bb_tlv(dfs, buf, datalen, r_rssi,
649 r_ext_rssi, r_rs_tstamp, r_fulltsf, &e) == 0) {
650 dfs->dfs_phyerr_reject_count++;
651 return;
652 }
653
654 if (dfs->dfs_phyerr_freq_min > e.freq)
655 dfs->dfs_phyerr_freq_min = e. freq;
656
657 if (dfs->dfs_phyerr_freq_max < e.freq)
658 dfs->dfs_phyerr_freq_max = e. freq;
659 } else if (dfs->dfs_caps.wlan_dfs_use_enhancement) {
660 if (dfs_process_phyerr_merlin(dfs, buf, datalen, r_rssi,
661 r_ext_rssi, r_rs_tstamp, r_fulltsf, &e) == 0)
662 return;
663 } else if (dfs->dfs_caps.wlan_dfs_ext_chan_ok) {
664 if (dfs_process_phyerr_sowl(dfs, buf, datalen, r_rssi,
665 r_ext_rssi, r_rs_tstamp, r_fulltsf, &e) == 0)
666 return;
667 } else {
668 if (dfs_process_phyerr_owl(dfs, buf, datalen, r_rssi,
669 r_ext_rssi, r_rs_tstamp, r_fulltsf, &e) == 0)
670 return;
671 }
672
673 /*
674 * If the hardware supports radar reporting on the extension channel
675 * it will supply FFT data for longer radar pulses.
676 * TLV chips don't go through this software check - the hardware
677 * check should be enough. If we want to do software checking
678 * later on then someone will have to craft an FFT parser
679 * suitable for the TLV FFT data format.
680 */
681 if ((!dfs->dfs_caps.wlan_chip_is_bb_tlv) &&
682 dfs->dfs_caps.wlan_dfs_ext_chan_ok) {
683 /*
684 * HW has a known issue with chirping pulses injected at or
685 * around DC in 40MHz mode. Such pulses are reported with much
686 * lower durations and SW then discards them because they do
687 * not fit the minimum bin5 pulse duration. To work around this
688 * issue, if a pulse is within a 10us range of the bin5 min
689 * duration, check if the pulse is chirping. If the pulse is
690 * chirping, bump up the duration to the minimum bin5 duration.
691 * This makes sure that a valid chirping pulse will not be
692 * discarded because of incorrect low duration. TBD - Is it
693 * possible to calculate the 'real' duration of the pulse using
694 * the slope of the FFT data? TBD - Use FFT data to
695 * differentiate between radar pulses and false PHY errors.
696 * This will let us reduce the number of false alarms seen.
697 * BIN 5 chirping pulses are only for FCC or Japan MMK4 domain
698 */
699 if (((dfs->dfsdomain == DFS_FCC_DOMAIN) ||
700 (dfs->dfsdomain == DFS_MKK4_DOMAIN) ||
701 (dfs->dfsdomain == DFS_MKKN_DOMAIN)) &&
702 (e.dur >= MAYBE_BIN5_DUR) && (e.dur < MAX_BIN5_DUR)) {
703 int add_dur;
704 int slope = 0, dc_found = 0;
705
706 /*
707 * Set the event chirping flags; as we're doing an
708 * actual chirp check.
709 */
710 e.do_check_chirp = 1;
711 e.is_hw_chirp = 0;
712 e.is_sw_chirp = 0;
713
714 /*
715 * dfs_check_chirping() expects is_pri and is_ext to
716 * be '1' for true and '0' for false for now, as the
717 * function itself uses these values in constructing
718 * things rather than testing them
719 */
720 add_dur = dfs_check_chirping(dfs, buf, datalen,
721 (e.is_pri ? 1 : 0),
722 (e.is_ext ? 1 : 0), &slope, &dc_found);
723 if (add_dur) {
724 dfs_bump_up_bin5_pulse_dur(dfs, &e, slope);
725 } else {
726 /* Set the duration so that it is rejected. */
727 e.is_sw_chirp = 0;
728 e.dur = MAX_BIN5_DUR + 100;
729 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
730 "is_chirping = %d dur=%d",
731 add_dur, e.dur);
732 }
733 } else {
734 /*
735 * We have a pulse that is either bigger than
736 * MAX_BIN5_DUR or less than MAYBE_BIN5_DUR
737 */
738 if ((dfs->dfsdomain == DFS_FCC_DOMAIN) ||
739 (dfs->dfsdomain == DFS_MKK4_DOMAIN) ||
740 (dfs->dfsdomain == DFS_MKKN_DOMAIN)) {
741 /*
742 * Would this result in very large pulses
743 * wrapping around to become short pulses?
744 */
745 if (e.dur >= MAX_BIN5_DUR) {
746 /*
747 * Set the duration so that it is
748 * rejected.
749 */
750 e.dur = MAX_BIN5_DUR + 50;
751 }
752 }
753 }
754 }
755
756 /*
757 * Add the parsed, checked and filtered entry to the radar pulse
758 * event list. This is then checked by dfs_radar_processevent().
759 *
760 * XXX TODO: some filtering is still done below this point - fix this!
761 */
762 WLAN_DFSEVENTQ_LOCK(dfs);
763 empty = STAILQ_EMPTY(&(dfs->dfs_eventq));
764 WLAN_DFSEVENTQ_UNLOCK(dfs);
765 if (empty)
766 return;
767
768 /*
769 * If the channel is a turbo G channel, then the event is for the
770 * adaptive radio (AR) pattern matching rather than radar detection.
771 */
772 if (WLAN_IS_CHAN_108G(dfs->dfs_curchan)) {
773 if (!(dfs->dfs_proc_phyerr & DFS_AR_EN)) {
774 dfs_debug(dfs, WLAN_DEBUG_DFS2,
775 "DFS_AR_EN not enabled");
776 return;
777 }
778 WLAN_DFSEVENTQ_LOCK(dfs);
779 event = STAILQ_FIRST(&(dfs->dfs_eventq));
780 if (!event) {
781 WLAN_DFSEVENTQ_UNLOCK(dfs);
782 dfs_debug(dfs, WLAN_DEBUG_DFS,
783 "no more events space left");
784 return;
785 }
786 STAILQ_REMOVE_HEAD(&(dfs->dfs_eventq), re_list);
787 WLAN_DFSEVENTQ_UNLOCK(dfs);
788 event->re_rssi = e.rssi;
789 event->re_dur = e.dur;
790 event->re_full_ts = e.fulltsf;
791 event->re_ts = (e.rs_tstamp) & DFS_TSMASK;
792 event->re_chanindex = dfs->dfs_curchan_radindex;
793 event->re_flags = 0;
794
795 /* Handle chirp flags. */
796 if (e.do_check_chirp) {
797 event->re_flags |= DFS_EVENT_CHECKCHIRP;
798 if (e.is_hw_chirp)
799 event->re_flags |= DFS_EVENT_HW_CHIRP;
800 if (e.is_sw_chirp)
801 event->re_flags |= DFS_EVENT_SW_CHIRP;
802 }
803
804 WLAN_ARQ_LOCK(dfs);
805 STAILQ_INSERT_TAIL(&(dfs->dfs_arq), event, re_list);
806 WLAN_ARQ_UNLOCK(dfs);
807 } else {
808 if ((WLAN_IS_CHAN_DFS(dfs->dfs_curchan) ||
809 ((WLAN_IS_CHAN_11AC_VHT160(dfs->dfs_curchan) ||
810 WLAN_IS_CHAN_11AC_VHT80_80(dfs->dfs_curchan)) &&
811 WLAN_IS_CHAN_DFS_CFREQ2(dfs->dfs_curchan))) ||
812 (dfs_is_precac_timer_running(dfs))) {
813
814 int retval = 0;
815
816 if (!(dfs->dfs_proc_phyerr & DFS_RADAR_EN)) {
817 dfs_debug(dfs, WLAN_DEBUG_DFS3,
818 "DFS_RADAR_EN not enabled");
819 return;
820 }
821
822 dfs_filter_short_pulses(dfs, &e, &retval);
823 if (retval)
824 return;
825
826 if (dfs_is_second_seg_radar_disabled(dfs, e.seg_id))
827 return;
828
829 /* Add the event to the list, if there's space. */
830 WLAN_DFSEVENTQ_LOCK(dfs);
831 event = STAILQ_FIRST(&(dfs->dfs_eventq));
832 if (!event) {
833 WLAN_DFSEVENTQ_UNLOCK(dfs);
834 dfs_debug(dfs, WLAN_DEBUG_DFS,
835 "no more events space left");
836 return;
837 }
838 STAILQ_REMOVE_HEAD(&(dfs->dfs_eventq), re_list);
839 WLAN_DFSEVENTQ_UNLOCK(dfs);
840
841 dfs->dfs_phyerr_queued_count++;
842 dfs->dfs_phyerr_w53_counter++;
843
844 event->re_dur = e.dur;
845 event->re_full_ts = e.fulltsf;
846 event->re_ts = (e.rs_tstamp) & DFS_TSMASK;
847 event->re_rssi = e.rssi;
848
849 event->re_seg_id = e.seg_id;
850 event->re_sidx = e.sidx;
851 event->re_freq_offset_khz = e.freq_offset_khz;
852 event->re_peak_mag = e.peak_mag;
853 event->re_total_gain = e.total_gain;
854 event->re_mb_gain = e.mb_gain;
855 event->re_relpwr_db = e.relpwr_db;
856 event->re_delta_diff = e.pulse_delta_diff;
857 event->re_delta_peak = e.pulse_delta_peak;
858 event->re_psidx_diff = e.pulse_psidx_diff;
859 event->re_flags = 0;
860 event->re_flags |= DFS_EVENT_VALID_PSIDX_DIFF;
861 /* Handle chirp flags. */
862 if (e.do_check_chirp) {
863 event->re_flags |= DFS_EVENT_CHECKCHIRP;
864 if (e.is_hw_chirp)
865 event->re_flags |= DFS_EVENT_HW_CHIRP;
866 if (e.is_sw_chirp)
867 event->re_flags |= DFS_EVENT_SW_CHIRP;
868 }
869
870 /* Correctly set which channel is being reported on */
871 dfs_set_chan_index(dfs, &e, event);
872
873 WLAN_DFSQ_LOCK(dfs);
874 STAILQ_INSERT_TAIL(&(dfs->dfs_radarq), event, re_list);
875 WLAN_DFSQ_UNLOCK(dfs);
876 }
877 }
878
879 /*
880 * Schedule the radar/AR task as appropriate.
881 * XXX isn't a lock needed for wlan_radar_tasksched?
882 */
883 if (!STAILQ_EMPTY(&dfs->dfs_arq)) {
884 /* XXX shouldn't this be a task/timer too? */
885 dfs_process_ar_event(dfs, dfs->dfs_curchan);
886 }
887 if (!STAILQ_EMPTY(&dfs->dfs_radarq) && !dfs->wlan_radar_tasksched) {
888 dfs->wlan_radar_tasksched = 1;
889 qdf_timer_mod(&dfs->wlan_dfs_task_timer, 0);
890 }
891 #undef EXT_CH_RADAR_FOUND
892 #undef PRI_CH_RADAR_FOUND
893 #undef EXT_CH_RADAR_EARLY_FOUND
894 }
895 #endif /* WLAN_DFS_PARTIAL_OFFLOAD */
896
897 #ifdef MOBILE_DFS_SUPPORT
dfs_process_phyerr_filter_offload(struct wlan_dfs * dfs,struct radar_event_info * wlan_radar_event)898 void dfs_process_phyerr_filter_offload(struct wlan_dfs *dfs,
899 struct radar_event_info *wlan_radar_event)
900 {
901 struct dfs_event *event;
902 int empty;
903 int do_check_chirp = 0;
904 int is_hw_chirp = 0;
905 int is_sw_chirp = 0;
906 int is_pri = 0;
907
908 if (!dfs) {
909 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
910 return;
911 }
912
913 if (dfs->dfs_ignore_dfs) {
914 dfs_debug(dfs, WLAN_DEBUG_DFS1, "ignoring dfs");
915 return;
916 }
917
918 if (!(dfs->dfs_proc_phyerr & DFS_RADAR_EN)) {
919 dfs_debug(dfs, WLAN_DEBUG_DFS1,
920 "DFS_RADAR_EN not set in dfs->dfs_proc_phyerr");
921 return;
922 }
923
924 if (WLAN_IS_CHAN_RADAR(dfs, dfs->dfs_curchan)) {
925 dfs_debug(dfs, WLAN_DEBUG_DFS1,
926 "Radar already found in the channel, do not queue radar data");
927 return;
928 }
929
930 dfs->wlan_dfs_stats.total_phy_errors++;
931 if (dfs->dfs_caps.wlan_chip_is_bb_tlv) {
932 do_check_chirp = 1;
933 is_pri = 1;
934 is_hw_chirp = wlan_radar_event->pulse_is_chirp;
935
936 if ((uint32_t) dfs->dfs_phyerr_freq_min >
937 wlan_radar_event->pulse_center_freq) {
938 dfs->dfs_phyerr_freq_min =
939 (int)wlan_radar_event->pulse_center_freq;
940 }
941
942 if (dfs->dfs_phyerr_freq_max <
943 (int)wlan_radar_event->pulse_center_freq) {
944 dfs->dfs_phyerr_freq_max =
945 (int)wlan_radar_event->pulse_center_freq;
946 }
947 }
948
949 /*
950 * Now, add the parsed, checked and filtered
951 * radar phyerror event radar pulse event list.
952 * This event will then be processed by
953 * dfs_radar_processevent() to see if the pattern
954 * of pulses in radar pulse list match any radar
955 * singnature in the current regulatory domain.
956 */
957
958 WLAN_DFSEVENTQ_LOCK(dfs);
959 empty = STAILQ_EMPTY(&(dfs->dfs_eventq));
960 WLAN_DFSEVENTQ_UNLOCK(dfs);
961 if (empty)
962 return;
963 /*
964 * Add the event to the list, if there's space.
965 */
966 WLAN_DFSEVENTQ_LOCK(dfs);
967 event = STAILQ_FIRST(&(dfs->dfs_eventq));
968 if (!event) {
969 WLAN_DFSEVENTQ_UNLOCK(dfs);
970 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,
971 "No more space left for queuing DFS Phyerror events");
972 return;
973 }
974 STAILQ_REMOVE_HEAD(&(dfs->dfs_eventq), re_list);
975 WLAN_DFSEVENTQ_UNLOCK(dfs);
976 dfs->dfs_phyerr_queued_count++;
977 dfs->dfs_phyerr_w53_counter++;
978 event->re_dur = (uint8_t) wlan_radar_event->pulse_duration;
979 event->re_rssi = wlan_radar_event->rssi;
980 event->re_ts = wlan_radar_event->pulse_detect_ts & DFS_TSMASK;
981 event->re_full_ts = (((uint64_t) wlan_radar_event->upload_fullts_high)
982 << 32) | wlan_radar_event->upload_fullts_low;
983
984 /*
985 * Index of peak magnitude
986 */
987 event->re_sidx = wlan_radar_event->peak_sidx;
988 event->re_delta_diff = wlan_radar_event->delta_diff;
989 event->re_delta_peak = wlan_radar_event->delta_peak;
990 event->re_flags = 0;
991 if (wlan_radar_event->is_psidx_diff_valid) {
992 event->re_flags |= DFS_EVENT_VALID_PSIDX_DIFF;
993 event->re_psidx_diff = wlan_radar_event->psidx_diff;
994 }
995
996 /*
997 * Handle chirp flags.
998 */
999 if (do_check_chirp) {
1000 event->re_flags |= DFS_EVENT_CHECKCHIRP;
1001 if (is_hw_chirp)
1002 event->re_flags |= DFS_EVENT_HW_CHIRP;
1003 if (is_sw_chirp)
1004 event->re_flags |= DFS_EVENT_SW_CHIRP;
1005 }
1006 /*
1007 * Correctly set which channel is being reported on
1008 */
1009 if (is_pri) {
1010 event->re_chanindex = (uint8_t) dfs->dfs_curchan_radindex;
1011 } else {
1012 if (dfs->dfs_extchan_radindex == -1)
1013 dfs_debug(dfs, WLAN_DEBUG_DFS1,
1014 "phyerr on ext channel");
1015 event->re_chanindex = (uint8_t) dfs->dfs_extchan_radindex;
1016 dfs_debug(dfs, WLAN_DEBUG_DFS1,
1017 "New extension channel event is added to queue");
1018 }
1019
1020 WLAN_DFSQ_LOCK(dfs);
1021
1022 STAILQ_INSERT_TAIL(&(dfs->dfs_radarq), event, re_list);
1023
1024 empty = STAILQ_EMPTY(&dfs->dfs_radarq);
1025
1026 WLAN_DFSQ_UNLOCK(dfs);
1027
1028 if (!empty && !dfs->wlan_radar_tasksched) {
1029 dfs->wlan_radar_tasksched = 1;
1030 qdf_timer_mod(&dfs->wlan_dfs_task_timer, 0);
1031 }
1032 }
1033 #endif
1034
dfs_is_radar_enabled(struct wlan_dfs * dfs,int * ignore_dfs)1035 void dfs_is_radar_enabled(struct wlan_dfs *dfs, int *ignore_dfs)
1036 {
1037 *ignore_dfs = dfs->dfs_ignore_dfs;
1038 }
1039