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