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