xref: /wlan-dirver/qca-wifi-host-cmn/umac/dfs/core/src/filtering/dfs_process_phyerr.c (revision edf9fd0441a5a3b63c14b7bb754f301dd8d5e57c)
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  */
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  */
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  */
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  */
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  */
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 
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  */
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  */
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  */
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  */
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 
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
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 
1035 void dfs_is_radar_enabled(struct wlan_dfs *dfs, int *ignore_dfs)
1036 {
1037 	*ignore_dfs = dfs->dfs_ignore_dfs;
1038 }
1039