xref: /wlan-dirver/qca-wifi-host-cmn/umac/dfs/core/src/filtering/dfs_process_phyerr.c (revision 3149adf58a329e17232a4c0e58d460d025edd55a)
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_channel.h"
27 #include "wlan_dfs_mlme_api.h"
28 #include "../dfs_internal.h"
29 
30 /**
31  * dfs_get_event_freqwidth() - Get frequency width.
32  * @dfs: Pointer to wlan_dfs structure.
33  *
34  * Return: Return the frequency width for the current operating channel.
35  * This isn't the channel width - it's how wide the reported event may be.
36  * For HT20 this is 20MHz. For HT40 on Howl and later it'll still be 20MHz
37  * - the hardware returns either pri or ext channel.
38  */
39 static inline int dfs_get_event_freqwidth(struct wlan_dfs *dfs)
40 {
41 	/* Handle edge cases during startup/transition, shouldn't happen! */
42 	if (!dfs)
43 		return 0;
44 
45 	if (!dfs->dfs_curchan)
46 		return 0;
47 
48 	/*
49 	 * For now, assume 20MHz wide - but this is incorrect when operating in
50 	 * half/quarter mode!
51 	 */
52 	return 20;
53 }
54 
55 /**
56  * dfs_get_event_freqcentre() - Get event frequency centre.
57  * @dfs: Pointer to wlan_dfs structure.
58  * @is_pri: detected on primary channel.
59  * @is_ext: detected on extension channel.
60  * @is_dc: detected at DC.
61  *
62  * Return the centre frequency for the current operating channel and event.
63  * This is for post-Owl 11n chips which report pri/extension channel events.
64  */
65 static inline uint16_t dfs_get_event_freqcentre(struct wlan_dfs *dfs,
66 		int is_pri,
67 		int is_ext,
68 		int is_dc)
69 {
70 	int chan_offset = 0, chan_width;
71 
72 	/* Handle edge cases during startup/transition, shouldn't happen! */
73 	if (!dfs)
74 		return 0;
75 	if (!dfs->dfs_curchan)
76 		return 0;
77 
78 	/*
79 	 * For wide channels, DC and ext frequencies need a bit of hand-holding
80 	 * based on whether it's an upper or lower channel.
81 	 */
82 	chan_width = dfs_get_event_freqwidth(dfs);
83 
84 	if (WLAN_IS_CHAN_11N_HT40PLUS(dfs->dfs_curchan))
85 		chan_offset = chan_width;
86 	else if (WLAN_IS_CHAN_11N_HT40MINUS(dfs->dfs_curchan))
87 		chan_offset = -chan_width;
88 	else
89 		chan_offset = 0;
90 
91 	/*
92 	 * Check for DC events first - the sowl code may just set all the bits
93 	 * together.
94 	 */
95 	if (is_dc) {
96 		/* XXX TODO: Should DC events be considered 40MHz wide here? */
97 		return dfs_chan2freq(
98 				dfs->dfs_curchan) + (chan_offset / 2);
99 	}
100 
101 	/*
102 	 * For non-wide channels, the centre frequency is just dfs_ch_freq.
103 	 * The centre frequency for pri events is still dfs_ch_freq.
104 	 */
105 	if (is_pri)
106 		return dfs_chan2freq(dfs->dfs_curchan);
107 
108 	if (is_ext)
109 		return dfs_chan2freq(dfs->dfs_curchan) + chan_width;
110 
111 	return dfs_chan2freq(dfs->dfs_curchan);
112 }
113 
114 int dfs_process_phyerr_owl(struct wlan_dfs *dfs,
115 		void *buf,
116 		uint16_t datalen,
117 		uint8_t rssi,
118 		uint8_t ext_rssi,
119 		uint32_t rs_tstamp,
120 		uint64_t fulltsf,
121 		struct dfs_phy_err *e)
122 {
123 	const char *cbuf = (const char *) buf;
124 	uint8_t dur;
125 	int event_width;
126 
127 	dfs->wlan_dfs_stats.owl_phy_errors++;
128 
129 	/*
130 	 * HW cannot detect extension channel radar so it only passes us primary
131 	 * channel radar data.
132 	 */
133 	if (datalen == 0)
134 		dur = 0;
135 	else
136 		dur = ((uint8_t *) cbuf)[0];
137 
138 	/* This is a spurious event; toss. */
139 	if (rssi == 0 && dur == 0)
140 		dfs->wlan_dfs_stats.datalen_discards++;
141 	return 0;
142 
143 	/* Fill out dfs_phy_err with the information we have at hand. */
144 	qdf_mem_set(e, sizeof(*e), 0);
145 	e->rssi = rssi;
146 	e->dur = dur;
147 	e->is_pri = 1;
148 	e->is_ext = 0;
149 	e->is_dc = 0;
150 	e->is_early = 1;
151 	e->fulltsf = fulltsf;
152 	e->rs_tstamp = rs_tstamp;
153 
154 	/*
155 	 * Owl only ever reports events on the primary channel. It doesn't
156 	 * even see events on the secondary channel.
157 	 */
158 	event_width = dfs_get_event_freqwidth(dfs);
159 	e->freq = dfs_get_event_freqcentre(dfs, 1, 0, 0) * 1000;
160 	e->freq_lo = e->freq - (event_width / 2) * 1000;
161 	e->freq_hi = e->freq + (event_width / 2) * 1000;
162 
163 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR_SUM,
164 		"rssi=%u dur=%u, freq=%d MHz, freq_lo=%d MHz, freq_hi=%d MHz",
165 		 rssi, dur, e->freq/1000, e->freq_lo/1000,
166 		e->freq_hi / 1000);
167 
168 	return 1;
169 }
170 
171 int dfs_process_phyerr_sowl(struct wlan_dfs *dfs,
172 		void *buf,
173 		uint16_t datalen,
174 		uint8_t rssi,
175 		uint8_t ext_rssi,
176 		uint32_t rs_tstamp,
177 		uint64_t fulltsf,
178 		struct dfs_phy_err *e)
179 {
180 #define EXT_CH_RADAR_FOUND 0x02
181 #define PRI_CH_RADAR_FOUND 0x01
182 #define EXT_CH_RADAR_EARLY_FOUND 0x04
183 	const char *cbuf = (const char *)buf;
184 	uint8_t dur = 0;
185 	uint8_t pulse_bw_info, pulse_length_ext, pulse_length_pri;
186 	int pri_found = 0, ext_found = 0;
187 	int early_ext = 0;
188 	int event_width;
189 
190 	/*
191 	 * If radar can be detected on the extension channel, datalen zero
192 	 * pulses are bogus, discard them.
193 	 */
194 	if (!datalen) {
195 		dfs->wlan_dfs_stats.datalen_discards++;
196 		return 0;
197 	}
198 
199 	/* Ensure that we have at least three bytes of payload. */
200 	if (datalen < 3) {
201 		dfs_debug(dfs, WLAN_DEBUG_DFS,
202 			"short error frame (%d bytes)", datalen);
203 		dfs->wlan_dfs_stats.datalen_discards++;
204 		return 0;
205 	}
206 
207 	/*
208 	 * Fetch the payload directly - the compiler will happily generate
209 	 * byte-read instructions with a const char * cbuf pointer.
210 	 */
211 	pulse_length_pri = cbuf[datalen - 3];
212 	pulse_length_ext = cbuf[datalen - 2];
213 	pulse_bw_info = cbuf[datalen - 1];
214 
215 	/*
216 	 * Only the last 3 bits of the BW info are relevant, they indicate
217 	 * which channel the radar was detected in.
218 	 */
219 	pulse_bw_info &= 0x07;
220 
221 	/* If pulse on DC, both primary and extension flags will be set */
222 	if (((pulse_bw_info & EXT_CH_RADAR_FOUND) &&
223 				(pulse_bw_info & PRI_CH_RADAR_FOUND))) {
224 		/*
225 		 * Conducted testing, when pulse is on DC, both pri and ext
226 		 * durations are reported to be same. Radiated testing, when
227 		 * pulse is on DC, differentpri and ext durations are reported,
228 		 * so take the larger of the two.
229 		 */
230 		if (pulse_length_ext >= pulse_length_pri) {
231 			dur = pulse_length_ext;
232 			ext_found = 1;
233 		} else {
234 			dur = pulse_length_pri;
235 			pri_found = 1;
236 		}
237 		dfs->wlan_dfs_stats.dc_phy_errors++;
238 	} else {
239 		if (pulse_bw_info & EXT_CH_RADAR_FOUND) {
240 			dur = pulse_length_ext;
241 			pri_found = 0;
242 			ext_found = 1;
243 			dfs->wlan_dfs_stats.ext_phy_errors++;
244 		}
245 		if (pulse_bw_info & PRI_CH_RADAR_FOUND) {
246 			dur = pulse_length_pri;
247 			pri_found = 1;
248 			ext_found = 0;
249 			dfs->wlan_dfs_stats.pri_phy_errors++;
250 		}
251 		if (pulse_bw_info & EXT_CH_RADAR_EARLY_FOUND) {
252 			dur = pulse_length_ext;
253 			pri_found = 0;
254 			ext_found = 1;
255 			early_ext = 1;
256 			dfs->wlan_dfs_stats.early_ext_phy_errors++;
257 			dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
258 				"EARLY ext channel dur=%u rssi=%u datalen=%d",
259 				dur, rssi, datalen);
260 		}
261 		if (!pulse_bw_info) {
262 			dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
263 				"ERROR channel dur=%u rssi=%u pulse_bw_info=0x%x datalen MOD 4 = %d",
264 				dur, rssi, pulse_bw_info, (datalen & 0x3));
265 			/*
266 			 * Bogus bandwidth info received in descriptor, so
267 			 * ignore this PHY error.
268 			 */
269 			dfs->wlan_dfs_stats.bwinfo_errors++;
270 			return 0;
271 		}
272 	}
273 
274 	/*
275 	 * Always use combined RSSI reported, unless RSSI reported on
276 	 * extension is stronger.
277 	 */
278 	if ((ext_rssi > rssi) && (ext_rssi < 128))
279 		rssi = ext_rssi;
280 
281 	/* Fill out the rssi/duration fields from above. */
282 	qdf_mem_set(e, sizeof(*e), 0);
283 	e->rssi = rssi;
284 	e->dur = dur;
285 	e->is_pri = pri_found;
286 	e->is_ext = ext_found;
287 	e->is_dc = !!(((pulse_bw_info & EXT_CH_RADAR_FOUND) &&
288 				(pulse_bw_info & PRI_CH_RADAR_FOUND)));
289 	e->is_early = early_ext;
290 	e->fulltsf = fulltsf;
291 	e->rs_tstamp = rs_tstamp;
292 
293 	/* Sowl and later can report pri/ext events. */
294 	event_width = dfs_get_event_freqwidth(dfs);
295 	e->freq = dfs_get_event_freqcentre(dfs, e->is_pri, e->is_ext,
296 			e->is_dc) * 1000;
297 	e->freq_lo = e->freq - (event_width / 2) * 1000;
298 	e->freq_hi = e->freq + (event_width / 2) * 1000;
299 
300 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR_SUM,
301 		"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",
302 		 pulse_bw_info, pulse_length_ext, pulse_length_pri,
303 		rssi, ext_rssi, e->freq/1000, e->freq_lo/1000, e->freq_hi/1000);
304 #undef EXT_CH_RADAR_FOUND
305 #undef PRI_CH_RADAR_FOUND
306 #undef EXT_CH_RADAR_EARLY_FOUND
307 
308 	return 1;
309 }
310 
311 int dfs_process_phyerr_merlin(struct wlan_dfs *dfs,
312 		void *buf,
313 		uint16_t datalen,
314 		uint8_t rssi,
315 		uint8_t ext_rssi,
316 		uint32_t rs_tstamp,
317 		uint64_t fulltsf,
318 		struct dfs_phy_err *e)
319 {
320 	const char *cbuf = (const char *) buf;
321 	uint8_t pulse_bw_info = 0;
322 
323 	/* Process using the sowl code. */
324 	if (!dfs_process_phyerr_sowl(dfs, buf, datalen, rssi, ext_rssi,
325 				rs_tstamp, fulltsf, e)) {
326 		return 0;
327 	}
328 
329 	/*
330 	 * For osprey (and Merlin) bw_info has implication for selecting RSSI
331 	 * value. So re-fetch the bw_info field so the RSSI values can be
332 	 * appropriately overridden.
333 	 */
334 	pulse_bw_info = cbuf[datalen - 1];
335 
336 	switch (pulse_bw_info & 0x03) {
337 	case 0x00:
338 		/* No radar in ctrl or ext channel */
339 		rssi = 0;
340 		break;
341 	case 0x01:
342 		/* Radar in ctrl channel */
343 		dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
344 			"RAW RSSI: rssi=%u ext_rssi=%u", rssi, ext_rssi);
345 		if (ext_rssi >= (rssi + 3)) {
346 			/*
347 			 * Cannot use ctrl channel RSSI if extension channel is
348 			 * stronger.
349 			 */
350 			rssi = 0;
351 		}
352 		break;
353 	case 0x02:
354 		/* Radar in extension channel */
355 		dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
356 			"RAW RSSI: rssi=%u ext_rssi=%u", rssi, ext_rssi);
357 		if (rssi >= (ext_rssi + 12)) {
358 			/*
359 			 * Cannot use extension channel RSSI if control channel
360 			 * is stronger
361 			 */
362 			rssi = 0;
363 		} else {
364 			rssi = ext_rssi;
365 		}
366 		break;
367 	case 0x03:
368 		/* When both are present use stronger one */
369 		if (rssi < ext_rssi)
370 			rssi = ext_rssi;
371 		break;
372 	}
373 
374 	/*
375 	 * Override the rssi decision made by the sowl code. The rest of the
376 	 * fields (duration, timestamp, etc) are left untouched.
377 	 */
378 	e->rssi = rssi;
379 
380 	return 1;
381 }
382 
383 /**
384  * dfs_dump_phyerr_contents() - Dump the phyerr contents.
385  * @d: Phyerr buffer.
386  * @len: Phyerr buf length.
387  */
388 
389 static void dfs_dump_phyerr_contents(const char *d, int len)
390 {
391 	int i, n, bufsize = 64;
392 
393 	/*
394 	 * This is statically sized for a 4-digit address + 16 * 2 digit data
395 	 * string. It's done so the printk() passed to the kernel is an entire
396 	 * line, so the kernel logging code will atomically print it. Otherwise
397 	 * we'll end up with interleaved lines with output from other kernel
398 	 * threads.
399 	 */
400 	char buf[64];
401 
402 	/* Initial conditions */
403 	buf[0] = '\n';
404 	n = 0;
405 
406 	for (i = 0; i < len; i++) {
407 		if (i % 16 == 0)
408 			n += snprintf(buf + n, bufsize - n, "%04x: ", i);
409 
410 		n += snprintf(buf + n, bufsize - n, "%02x ", d[i] & 0xff);
411 		if (i % 16 == 15) {
412 			dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS, "%s", buf);
413 			n = 0;
414 			buf[0] = '\0';
415 		}
416 	}
417 
418 	/* Print the final line if we didn't print it above. */
419 	if (n != 0)
420 		dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS, "%s", buf);
421 }
422 
423 /**
424  * dfs_bump_up_bin5_pulse_dur() - Bump up to a random BIN 5 pulse duration.
425  * @dfs: Pointer to wlan_dfs structure.
426  * @e: Pointer to dfs_phy_err structure.
427  * @slope: Slope value.
428  */
429 static inline void dfs_bump_up_bin5_pulse_dur(
430 		struct wlan_dfs *dfs,
431 		struct dfs_phy_err *e,
432 		int slope)
433 {
434 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR, "old dur %d slope =%d",
435 			e->dur, slope);
436 
437 	e->is_sw_chirp = 1;
438 	/* bump up to a random bin5 pulse duration */
439 	if (e->dur < MIN_BIN5_DUR)
440 		e->dur = dfs_get_random_bin5_dur(dfs, e->fulltsf);
441 
442 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR, "new dur %d", e->dur);
443 }
444 
445 /**
446  * dfs_filter_short_pulses() - Filter short pulses.
447  * @dfs: Pointer to wlan_dfs structure.
448  * @e: Pointer to dfs_phy_err structure.
449  * @retval: Return value
450  *
451  * Rssi is not accurate for short pulses, so donot filter based on that for
452  * short duration pulses.
453  */
454 static inline void dfs_filter_short_pulses(
455 		struct wlan_dfs *dfs,
456 		struct dfs_phy_err *e,
457 		int *retval)
458 {
459 	if (dfs->dfs_caps.wlan_dfs_ext_chan_ok) {
460 		if ((e->rssi < dfs->dfs_rinfo.rn_minrssithresh &&
461 					(e->dur > MAX_DUR_FOR_LOW_RSSI)) ||
462 				e->dur > (dfs->dfs_rinfo.rn_maxpulsedur)) {
463 			dfs->wlan_dfs_stats.rssi_discards++;
464 			*retval = 1;
465 		}
466 	} else if (e->rssi < dfs->dfs_rinfo.rn_minrssithresh ||
467 			e->dur > dfs->dfs_rinfo.rn_maxpulsedur) {
468 		dfs->wlan_dfs_stats.rssi_discards++;
469 		*retval = 1;
470 	}
471 
472 	if (*retval) {
473 		dfs_debug(dfs, WLAN_DEBUG_DFS1,
474 				"%s pulse is discarded: dur=%d, maxpulsedur=%d, rssi=%d, minrssi=%d",
475 				(dfs->dfs_caps.wlan_dfs_ext_chan_ok) ?
476 				"Extension channel" : "",
477 				e->dur, dfs->dfs_rinfo.rn_maxpulsedur,
478 				e->rssi, dfs->dfs_rinfo.rn_minrssithresh);
479 	}
480 }
481 
482 /**
483  * dfs_is_second_seg_radar_disabled() - Check for second segment radar disabled.
484  * @dfs: Pointer to wlan_dfs structure.
485  * @seg_id: Segment id.
486  *
487  * Return: true if the second segment RADAR is enabled else false.
488  */
489 static inline bool dfs_is_second_seg_radar_disabled(
490 		struct wlan_dfs *dfs,
491 		int seg_id)
492 {
493 	if ((seg_id == SEG_ID_SECONDARY) &&
494 			!(dfs->dfs_proc_phyerr &
495 				DFS_SECOND_SEGMENT_RADAR_EN)) {
496 		dfs_debug(dfs, WLAN_DEBUG_DFS3,
497 				"Do not process PHY error data from Second segment, DFS_SECOND_SEGMENT_RADAR_EN is not enabled");
498 		return true;
499 	}
500 
501 	return false;
502 }
503 
504 /**
505  * dfs_set_chan_index() - Set channel index.
506  * @dfs: Pointer to wlan_dfs structure.
507  * @e: Pointer to dfs_phy_err structure.
508  * @event: Pointer to dfs_event structure.
509  */
510 static inline void dfs_set_chan_index(
511 		struct wlan_dfs *dfs,
512 		struct dfs_phy_err *e,
513 		struct dfs_event *event)
514 {
515 	if (e->is_pri) {
516 		event->re_chanindex = dfs->dfs_curchan_radindex;
517 	} else {
518 		event->re_chanindex = dfs->dfs_extchan_radindex;
519 		dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
520 				"%s New extension channel event is added to queue",
521 				(event->re_chanindex == -1) ?
522 				"- phyerr on ext channel" : "");
523 	}
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 
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 			/* Handle chirp flags. */
815 			if (e.do_check_chirp) {
816 				event->re_flags |= DFS_EVENT_CHECKCHIRP;
817 				if (e.is_hw_chirp)
818 					event->re_flags |= DFS_EVENT_HW_CHIRP;
819 				if (e.is_sw_chirp)
820 					event->re_flags |= DFS_EVENT_SW_CHIRP;
821 			}
822 
823 			/* Correctly set which channel is being reported on */
824 			dfs_set_chan_index(dfs, &e, event);
825 
826 			WLAN_DFSQ_LOCK(dfs);
827 			STAILQ_INSERT_TAIL(&(dfs->dfs_radarq), event, re_list);
828 			WLAN_DFSQ_UNLOCK(dfs);
829 		}
830 	}
831 
832 	/*
833 	 * Schedule the radar/AR task as appropriate.
834 	 * XXX isn't a lock needed for wlan_radar_tasksched?
835 	 */
836 	if (!STAILQ_EMPTY(&dfs->dfs_arq)) {
837 		/* XXX shouldn't this be a task/timer too? */
838 		dfs_process_ar_event(dfs, dfs->dfs_curchan);
839 	}
840 	if (!STAILQ_EMPTY(&dfs->dfs_radarq) && !dfs->wlan_radar_tasksched) {
841 		dfs->wlan_radar_tasksched = 1;
842 		qdf_timer_mod(&dfs->wlan_dfs_task_timer, 0);
843 	}
844 #undef EXT_CH_RADAR_FOUND
845 #undef PRI_CH_RADAR_FOUND
846 #undef EXT_CH_RADAR_EARLY_FOUND
847 }
848 
849 #ifdef QCA_MCL_DFS_SUPPORT
850 void dfs_process_phyerr_filter_offload(struct wlan_dfs *dfs,
851 	struct radar_event_info *wlan_radar_event)
852 {
853 	struct dfs_event *event;
854 	int empty;
855 	int do_check_chirp = 0;
856 	int is_hw_chirp = 0;
857 	int is_sw_chirp = 0;
858 	int is_pri = 0;
859 
860 	if (!dfs) {
861 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
862 		return;
863 	}
864 
865 	if (dfs->dfs_ignore_dfs) {
866 		dfs_debug(dfs, WLAN_DEBUG_DFS1, "ignoring dfs");
867 		return;
868 	}
869 
870 	if (!(dfs->dfs_proc_phyerr & DFS_RADAR_EN)) {
871 		dfs_debug(dfs, WLAN_DEBUG_DFS1,
872 			"DFS_RADAR_EN not set in dfs->dfs_proc_phyerr");
873 		return;
874 	}
875 
876 	if (WLAN_IS_CHAN_RADAR(dfs->dfs_curchan)) {
877 		dfs_debug(dfs, WLAN_DEBUG_DFS1,
878 			"Radar already found in the channel, do not queue radar data");
879 		return;
880 	}
881 
882 	dfs->wlan_dfs_stats.total_phy_errors++;
883 	if (dfs->dfs_caps.wlan_chip_is_bb_tlv) {
884 		do_check_chirp = 1;
885 		is_pri = 1;
886 		is_hw_chirp = wlan_radar_event->pulse_is_chirp;
887 
888 		if ((uint32_t) dfs->dfs_phyerr_freq_min >
889 		    wlan_radar_event->pulse_center_freq) {
890 			dfs->dfs_phyerr_freq_min =
891 				(int)wlan_radar_event->pulse_center_freq;
892 		}
893 
894 		if (dfs->dfs_phyerr_freq_max <
895 		    (int)wlan_radar_event->pulse_center_freq) {
896 			dfs->dfs_phyerr_freq_max =
897 				(int)wlan_radar_event->pulse_center_freq;
898 		}
899 	}
900 
901 	/*
902 	 * Now, add the parsed, checked and filtered
903 	 * radar phyerror event radar pulse event list.
904 	 * This event will then be processed by
905 	 * dfs_radar_processevent() to see if the pattern
906 	 * of pulses in radar pulse list match any radar
907 	 * singnature in the current regulatory domain.
908 	 */
909 
910 	WLAN_DFSEVENTQ_LOCK(dfs);
911 	empty = STAILQ_EMPTY(&(dfs->dfs_eventq));
912 	WLAN_DFSEVENTQ_UNLOCK(dfs);
913 	if (empty)
914 		return;
915 	/*
916 	 * Add the event to the list, if there's space.
917 	 */
918 	WLAN_DFSEVENTQ_LOCK(dfs);
919 	event = STAILQ_FIRST(&(dfs->dfs_eventq));
920 	if (!event) {
921 		WLAN_DFSEVENTQ_UNLOCK(dfs);
922 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,
923 			"%s: No more space left for queuing DFS Phyerror events",
924 			__func__);
925 		return;
926 	}
927 	STAILQ_REMOVE_HEAD(&(dfs->dfs_eventq), re_list);
928 	WLAN_DFSEVENTQ_UNLOCK(dfs);
929 	dfs->dfs_phyerr_queued_count++;
930 	dfs->dfs_phyerr_w53_counter++;
931 	event->re_dur = (uint8_t) wlan_radar_event->pulse_duration;
932 	event->re_rssi = wlan_radar_event->rssi;
933 	event->re_ts = wlan_radar_event->pulse_detect_ts & DFS_TSMASK;
934 	event->re_full_ts = (((uint64_t) wlan_radar_event->upload_fullts_high)
935 				<< 32) | wlan_radar_event->upload_fullts_low;
936 
937 	/*
938 	 * Index of peak magnitude
939 	 */
940 	event->re_sidx = wlan_radar_event->peak_sidx;
941 	event->re_delta_diff = wlan_radar_event->delta_diff;
942 	event->re_delta_peak = wlan_radar_event->delta_peak;
943 	event->re_flags = 0;
944 
945 	/*
946 	 * Handle chirp flags.
947 	 */
948 	if (do_check_chirp) {
949 		event->re_flags |= DFS_EVENT_CHECKCHIRP;
950 		if (is_hw_chirp)
951 			event->re_flags |= DFS_EVENT_HW_CHIRP;
952 		if (is_sw_chirp)
953 			event->re_flags |= DFS_EVENT_SW_CHIRP;
954 	}
955 	/*
956 	 * Correctly set which channel is being reported on
957 	 */
958 	if (is_pri) {
959 		event->re_chanindex = (uint8_t) dfs->dfs_curchan_radindex;
960 	} else {
961 		if (dfs->dfs_extchan_radindex == -1)
962 			dfs_debug(dfs, WLAN_DEBUG_DFS1,
963 				"%s phyerr on ext channel", __func__);
964 		event->re_chanindex = (uint8_t) dfs->dfs_extchan_radindex;
965 		dfs_debug(dfs, WLAN_DEBUG_DFS1,
966 			"%s:New extension channel event is added to queue",
967 			 __func__);
968 	}
969 
970 	WLAN_DFSQ_LOCK(dfs);
971 
972 	STAILQ_INSERT_TAIL(&(dfs->dfs_radarq), event, re_list);
973 
974 	empty = STAILQ_EMPTY(&dfs->dfs_radarq);
975 
976 	WLAN_DFSQ_UNLOCK(dfs);
977 
978 	if (!empty && !dfs->wlan_radar_tasksched) {
979 		dfs->wlan_radar_tasksched = 1;
980 		qdf_timer_mod(&dfs->wlan_dfs_task_timer, 0);
981 	}
982 }
983 #endif
984