xref: /wlan-dirver/qca-wifi-host-cmn/umac/dfs/core/src/filtering/dfs_phyerr_tlv.c (revision 2f4b444fb7e689b83a4ab0e7b3b38f0bf4def8e0)
1 /*
2  * Copyright (c) 2012, 2016-2021 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /**
18  * DOC: This file contains TLV frame processing functions.
19  */
20 
21 #include "../dfs.h"
22 #include "../dfs_channel.h"
23 #include "../dfs_phyerr_tlv.h"
24 #include "wlan_dfs_mlme_api.h"
25 #include "../dfs_internal.h"
26 
27 #define AGC_MB_GAIN_THRESH1    68
28 #define AGC_OTHER_GAIN_THRESH1 40
29 #define AGC_MB_GAIN_THRESH2    80
30 #define AGC_OTHER_GAIN_THRESH2 60
31 #define AGC_GAIN_RSSI_THRESH   25
32 
33 /*
34  * Until "fastclk" is stored in the DFS configuration.
35  */
36 #define PERE_IS_OVERSAMPLING(_dfs) \
37 	(_dfs->dfs_caps.wlan_chip_is_over_sampled ? 1 : 0)
38 
39 /**
40  * dfs_sign_extend_32() - Calculates extended 32bit value.
41  * @v: Value.
42  * @nb: Offset.
43  *
44  * Return: Returns Extend vale.
45  */
46 static int32_t dfs_sign_extend_32(uint32_t v, int nb)
47 {
48 	uint32_t m = 1U << (nb - 1);
49 
50 	/* Chop off high bits, just in case. */
51 	v &= v & ((1U << nb) - 1);
52 
53 	/* Extend */
54 	return (v ^ m) - m;
55 }
56 
57 /**
58  * dfs_calc_freq_offset() - Calculate the frequency offset.
59  * @sindex: signed bin index.
60  * @is_oversampling: oversampling mode
61  *
62  * Calculate the frequency offset from the given signed bin index from the
63  * radar summary report. This takes the oversampling mode into account.
64  * For oversampling, each bin has resolution 44MHz/128. For non-oversampling,
65  * each bin has resolution 40MHz/128. It returns kHz - ie, 1000th's of MHz.
66  */
67 static int dfs_calc_freq_offset(int sindex, int is_oversampling)
68 {
69 	if (is_oversampling)
70 		return sindex * (44000 / 128);
71 	else
72 		return sindex * (40000 / 128);
73 }
74 
75 /**
76  * dfs_radar_summary_print() - Prints the Radar summary.
77  * @dfs: Pointer to wlan_dfs structure.
78  * @rsu: Pointer rx_radar_status structure.
79  */
80 static void dfs_radar_summary_print(struct wlan_dfs *dfs,
81 		struct rx_radar_status *rsu)
82 {
83 
84 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
85 		"    pulsedur=%d", rsu->pulse_duration);
86 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
87 		"    rssi=%d", rsu->rssi);
88 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
89 		"    ischirp=%d", rsu->is_chirp);
90 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
91 		"    sidx=%d", rsu->sidx);
92 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
93 		"    raw tsf=%d", rsu->raw_tsf);
94 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
95 		"    tsf_offset=%d", rsu->tsf_offset);
96 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
97 		"    cooked tsf=%d", rsu->raw_tsf - rsu->tsf_offset);
98 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
99 		"    frequency offset=%d.%d MHz (oversampling=%d)",
100 		(int)(rsu->freq_offset / 1000),
101 		(int)abs(rsu->freq_offset % 1000),
102 		PERE_IS_OVERSAMPLING(dfs));
103 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
104 		"    agc_total_gain=%d", rsu->agc_total_gain);
105 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
106 		"    agc_mb_gain=%d", rsu->agc_mb_gain);
107 }
108 
109 /**
110  * dfs_radar_summary_parse() - Parse the radar summary frame.
111  * @dfs: pointer to wlan_dfs structure.
112  * @buf: Phyerr buffer.
113  * @len: Phyerr buflen.
114  * @rsu: Pointer to rx_radar_status structure.
115  *
116  * The frame contents _minus_ the TLV are passed in.
117  */
118 static void dfs_radar_summary_parse(struct wlan_dfs *dfs,
119 		const char *buf,
120 		size_t len,
121 		struct rx_radar_status *rsu)
122 {
123 	uint32_t rs[3];
124 
125 	/* Drop out if we have < 2 DWORDs available. */
126 	if (len < sizeof(rs)) {
127 		dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR |
128 			WLAN_DEBUG_DFS_PHYERR_SUM,
129 			"len (%zu) < expected (%zu)!", len, sizeof(rs));
130 	}
131 
132 	/*
133 	 * Since the TLVs may be unaligned for some reason
134 	 * we take a private copy into aligned memory.
135 	 * This enables us to use the HAL-like accessor macros
136 	 * into the DWORDs to access sub-DWORD fields.
137 	 */
138 	qdf_mem_copy(rs, buf, sizeof(rs));
139 
140 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
141 		"two 32 bit values are: %08x %08x", rs[0], rs[1]);
142 
143 	/* Populate the fields from the summary report. */
144 	rsu->tsf_offset =
145 		MS(rs[RADAR_REPORT_PULSE_REG_2], RADAR_REPORT_PULSE_TSF_OFFSET);
146 	rsu->pulse_duration =
147 		MS(rs[RADAR_REPORT_PULSE_REG_2], RADAR_REPORT_PULSE_DUR);
148 	rsu->is_chirp =
149 		MS(rs[RADAR_REPORT_PULSE_REG_1], RADAR_REPORT_PULSE_IS_CHIRP);
150 	rsu->sidx = dfs_sign_extend_32(MS(rs[RADAR_REPORT_PULSE_REG_1],
151 				RADAR_REPORT_PULSE_SIDX),
152 			10);
153 	rsu->freq_offset =
154 		dfs_calc_freq_offset(rsu->sidx, PERE_IS_OVERSAMPLING(dfs));
155 
156 	/* These are only relevant if the pulse is a chirp. */
157 	rsu->delta_peak = dfs_sign_extend_32(MS(rs[RADAR_REPORT_PULSE_REG_1],
158 		    RADAR_REPORT_PULSE_DELTA_PEAK), 6);
159 	rsu->delta_diff =
160 		MS(rs[RADAR_REPORT_PULSE_REG_1], RADAR_REPORT_PULSE_DELTA_DIFF);
161 	rsu->agc_total_gain =
162 		MS(rs[RADAR_REPORT_PULSE_REG_1], RADAR_REPORT_AGC_TOTAL_GAIN);
163 	rsu->agc_mb_gain = MS(rs[RADAR_REPORT_PULSE_REG_2],
164 		RADAR_REPORT_PULSE_AGC_MB_GAIN);
165 }
166 
167 /**
168  * dfs_radar_fft_search_report_parse () - Parse FFT report.
169  * @dfs: pointer to wlan_dfs structure.
170  * @buf: Phyerr buffer.
171  * @len: Phyerr buflen.
172  * @rsu: Pointer to rx_radar_status structure.
173  */
174 static void dfs_radar_fft_search_report_parse(struct wlan_dfs *dfs,
175 		const char *buf,
176 		size_t len,
177 		struct rx_search_fft_report *rsfr)
178 {
179 	uint32_t rs[3];
180 
181 	/* Drop out if we have < 2 DWORDs available. */
182 	if (len < sizeof(rs)) {
183 		dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR |
184 			WLAN_DEBUG_DFS_PHYERR_SUM,
185 			"len (%zu) < expected (%zu)!", len, sizeof(rs));
186 	}
187 
188 	/*
189 	 * Since the TLVs may be unaligned for some reason we take a private
190 	 * copy into aligned memory. This enables us to use the HAL-like
191 	 * accessor macros into the DWORDs to access sub-DWORD fields.
192 	 */
193 	qdf_mem_copy(rs, buf, sizeof(rs));
194 
195 	rsfr->total_gain_db =
196 	    MS(rs[SEARCH_FFT_REPORT_REG_1], SEARCH_FFT_REPORT_TOTAL_GAIN_DB);
197 
198 	rsfr->base_pwr_db =
199 	    MS(rs[SEARCH_FFT_REPORT_REG_1], SEARCH_FFT_REPORT_BASE_PWR_DB);
200 
201 	rsfr->fft_chn_idx =
202 	    MS(rs[SEARCH_FFT_REPORT_REG_1], SEARCH_FFT_REPORT_FFT_CHN_IDX);
203 
204 	rsfr->peak_sidx = dfs_sign_extend_32(MS(rs[SEARCH_FFT_REPORT_REG_1],
205 				SEARCH_FFT_REPORT_PEAK_SIDX), 12);
206 
207 	rsfr->relpwr_db =
208 	    MS(rs[SEARCH_FFT_REPORT_REG_2], SEARCH_FFT_REPORT_RELPWR_DB);
209 
210 	rsfr->avgpwr_db =
211 	    MS(rs[SEARCH_FFT_REPORT_REG_2], SEARCH_FFT_REPORT_AVGPWR_DB);
212 
213 	rsfr->peak_mag =
214 	    MS(rs[SEARCH_FFT_REPORT_REG_2], SEARCH_FFT_REPORT_PEAK_MAG);
215 
216 	rsfr->num_str_bins_ib =
217 	    MS(rs[SEARCH_FFT_REPORT_REG_2], SEARCH_FFT_REPORT_NUM_STR_BINS_IB);
218 
219 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
220 		"two 32 bit values are: %08x %08x", rs[0], rs[1]);
221 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
222 		"rsfr->total_gain_db = %d", rsfr->total_gain_db);
223 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
224 		"rsfr->base_pwr_db = %d", rsfr->base_pwr_db);
225 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
226 		"rsfr->fft_chn_idx = %d", rsfr->fft_chn_idx);
227 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
228 		"rsfr->peak_sidx = %d", rsfr->peak_sidx);
229 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
230 		"rsfr->relpwr_db = %d", rsfr->relpwr_db);
231 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
232 		"rsfr->avgpwr_db = %d", rsfr->avgpwr_db);
233 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
234 		"rsfr->peak_mag = %d", rsfr->peak_mag);
235 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
236 		"rsfr->num_str_bins_ib = %d", rsfr->num_str_bins_ib);
237 
238 	if (dfs->dfs_caps.wlan_chip_is_ht160) {
239 		rsfr->seg_id =
240 		    MS(rs[SEARCH_FFT_REPORT_REG_3], SEARCH_FFT_REPORT_SEG_ID);
241 		dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
242 			"rsfr->seg_id = %d", rsfr->seg_id);
243 	}
244 }
245 
246 /**
247  * dfs_check_for_false_detection() -  Check for possible false detection on
248  * beeliner this may also work for Cascade but parameters
249  * (e.g. AGC_MB_GAIN_THRESH1) may be different for Cascade.
250  * @dfs: pointer to wlan_dfs structure.
251  * @rs: pointer to rx_radar_status structure.
252  * @false_detect: Pointer to save false detect value.
253  * @rssi: RSSI.
254  */
255 static inline void dfs_check_for_false_detection(
256 		struct wlan_dfs *dfs,
257 		struct rx_radar_status *rs,
258 		bool *false_detect,
259 		uint8_t rssi)
260 {
261 	bool is_ht160 = false;
262 	bool is_false_detect = false;
263 
264 	is_ht160 = dfs->dfs_caps.wlan_chip_is_ht160;
265 	is_false_detect = dfs->dfs_caps.wlan_chip_is_false_detect;
266 
267 	if ((dfs->dfs_caps.wlan_chip_is_over_sampled == 0) &&
268 			(is_ht160 == 0 && is_false_detect)) {
269 		if ((rs->agc_mb_gain > AGC_MB_GAIN_THRESH1) &&
270 				((rs->agc_total_gain - rs->agc_mb_gain) <
271 				 AGC_OTHER_GAIN_THRESH1)) {
272 			*false_detect = true;
273 		}
274 
275 		if ((rs->agc_mb_gain > AGC_MB_GAIN_THRESH2) &&
276 				((rs->agc_total_gain - rs->agc_mb_gain) >
277 				 AGC_OTHER_GAIN_THRESH2) &&
278 				(rssi > AGC_GAIN_RSSI_THRESH)) {
279 			*false_detect = true;
280 		}
281 	}
282 
283 	if (*false_detect)
284 		dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
285 				"setting false_detect to TRUE because of mb/total_gain/rssi, agc_mb_gain=%d, agc_total_gain=%d, rssi=%d",
286 				rs->agc_mb_gain, rs->agc_total_gain, rssi);
287 }
288 
289 /**
290  * dfs_tlv_parse_frame () - Parse a Peregrine BB TLV frame.
291  * @dfs: pointer to wlan_dfs structure.
292  * @rs: pointer to rx_radar_status structure.
293  * @rsfr: Pointer to rx_search_fft_report structure.
294  * @buf: Phyerr buffer.
295  * @len: Phyerr buflen.
296  * @rssi: RSSI.
297  * @first_short_fft_peak_mag: first short FFT peak_mag.
298  * @psidx_diff: Pointer to psidx diff.
299  *
300  * This routine parses each TLV, prints out what's going on and calls an
301  * appropriate sub-function. Since the TLV format doesn't _specify_ all TLV
302  * components are DWORD aligned, we must treat them as not and access the
303  * fields appropriately.
304  */
305 static int dfs_tlv_parse_frame(struct wlan_dfs *dfs,
306 		struct rx_radar_status *rs,
307 		struct rx_search_fft_report *rsfr,
308 		const char *buf,
309 		size_t len,
310 		uint8_t rssi,
311 		int *first_short_fft_peak_mag,
312 		int16_t *psidx_diff)
313 {
314 	int i = 0;
315 	uint32_t tlv_hdr[1];
316 	bool false_detect = false;
317 	/* total search FFT reports including short and long */
318 	int8_t sfr_count = 0;
319 	int16_t first_short_fft_psidx = 0;
320 
321 	*psidx_diff = 0;
322 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
323 			"total length = %zu bytes", len);
324 	while ((i < len) && (false_detect == false)) {
325 		/* Ensure we at least have four bytes. */
326 		if ((len - i) < sizeof(tlv_hdr)) {
327 			dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR |
328 				WLAN_DEBUG_DFS_PHYERR_SUM,
329 				"ran out of bytes, len=%zu, i=%d", len, i);
330 			return 0;
331 		}
332 
333 		/*
334 		 * Copy the offset into the header, so the DWORD style access
335 		 * macros can be used.
336 		 */
337 		qdf_mem_copy(&tlv_hdr, buf + i, sizeof(tlv_hdr));
338 
339 		dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
340 			"HDR: TLV SIG=0x%x, TAG=0x%x, LEN=%d bytes",
341 			MS(tlv_hdr[TLV_REG], TLV_SIG),
342 			MS(tlv_hdr[TLV_REG], TLV_TAG),
343 			MS(tlv_hdr[TLV_REG], TLV_LEN));
344 
345 		/*
346 		 * Sanity check the length field is available in the remaining
347 		 * frame. Drop out if this isn't the case - we can't trust the
348 		 * rest of the TLV entries.
349 		 */
350 		if (MS(tlv_hdr[TLV_REG], TLV_LEN) + i >= len) {
351 			dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
352 				"TLV oversize: TLV LEN=%d, available=%zu, i=%d",
353 				 MS(tlv_hdr[TLV_REG], TLV_LEN),
354 				len, i);
355 			break;
356 		}
357 
358 		/* Skip the TLV header - one DWORD. */
359 		i += sizeof(tlv_hdr);
360 
361 		/* Handle the payload. */
362 		switch (MS(tlv_hdr[TLV_REG], TLV_SIG)) {
363 		case TAG_ID_RADAR_PULSE_SUMMARY: /* Radar pulse summary */
364 			dfs_radar_summary_parse(dfs, buf + i,
365 					MS(tlv_hdr[TLV_REG], TLV_LEN), rs);
366 
367 			dfs_check_for_false_detection(dfs, rs, &false_detect,
368 					rssi);
369 			break;
370 		case TAG_ID_SEARCH_FFT_REPORT:
371 			sfr_count++;
372 			dfs_radar_fft_search_report_parse(dfs, buf + i,
373 					MS(tlv_hdr[TLV_REG], TLV_LEN), rsfr);
374 
375 			/* we are interested in the first short FFT report's
376 			 * peak_mag for this value to be reliable, we must
377 			 * ensure that
378 			 * BB_srch_fft_ctrl_4.radar_fft_short_rpt_scl is set to
379 			 * 0.
380 			 */
381 			if (sfr_count == 1) {
382 				*first_short_fft_peak_mag = rsfr->peak_mag;
383 				first_short_fft_psidx = rsfr->peak_sidx;
384 			}
385 
386 			/*
387 			 * Check for possible false detection on Peregrine.
388 			 * we examine search FFT report and make the following
389 			 * assumption as per algorithms group's input:
390 			 * (1) There may be multiple TLV
391 			 * (2) We make false detection decison solely based on
392 			 * the first TLV
393 			 * (3) If the first TLV is a serch FFT report then we
394 			 * check the peak_mag value.
395 			 * When RSSI is equal to dfs->wlan_dfs_false_rssI_thres
396 			 * (default 50) and peak_mag is less than
397 			 * 2 * dfs->wlan_dfs_peak_mag (default 40) we treat it
398 			 * as false detect. Please note that 50 is not a true
399 			 * RSSI estimate, but value indicated by HW for RF
400 			 * saturation event.
401 			 */
402 			if (PERE_IS_OVERSAMPLING(dfs) &&
403 				(sfr_count == 1) &&
404 				(rssi == dfs->wlan_dfs_false_rssi_thres) &&
405 				(rsfr->peak_mag < (2 * dfs->wlan_dfs_peak_mag))
406 				) {
407 				false_detect = true;
408 				dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
409 					"setting false_detect to TRUE because of false_rssi_thres");
410 			}
411 
412 			/*
413 			 * The first FFT report indicated by (sfr_count == 1)
414 			 * should correspond to the first short FFT report from
415 			 * HW and the second FFT report indicated by
416 			 * (sfr_count == 2) should correspond to the first long
417 			 * FFT report from HW for the same pulse. The short and
418 			 * log FFT reports have a factor of 4 difference in
419 			 * resolution; hence the need to multiply by 4 when
420 			 * computing the psidx_diff.
421 			 */
422 			if (sfr_count == 2)
423 				*psidx_diff = rsfr->peak_sidx -
424 					      4 * first_short_fft_psidx;
425 
426 			break;
427 		default:
428 			dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR,
429 				"unknown entry, SIG=0x%02x",
430 				 MS(tlv_hdr[TLV_REG], TLV_SIG));
431 		}
432 
433 		/* Skip the payload. */
434 		i += MS(tlv_hdr[TLV_REG], TLV_LEN);
435 	}
436 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR, "done");
437 
438 	return false_detect ? 0 : 1;
439 }
440 
441 /**
442  * dfs_tlv_calc_freq_info() - Calculate the channel centre in MHz.
443  * @dfs: pointer to wlan_dfs structure.
444  * @rs: pointer to rx_radar_status structure.
445  *
446  * Return: Returns the channel center.
447  */
448 #ifdef CONFIG_CHAN_FREQ_API
449 static int dfs_tlv_calc_freq_info(struct wlan_dfs *dfs,
450 				  struct rx_radar_status *rs)
451 {
452 	uint32_t chan_centre;
453 	uint32_t chan_width;
454 	int chan_offset;
455 
456 	/* For now, just handle up to VHT80 correctly. */
457 	if (!dfs->dfs_curchan) {
458 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs_curchan is null");
459 		return 0;
460 		/*
461 		 * For now, the only 11ac channel with freq1/freq2 setup is
462 		 * VHT80. Should have a flag macro to check this!
463 		 */
464 	} else if (WLAN_IS_CHAN_11AC_VHT80(dfs->dfs_curchan)) {
465 		/*
466 		 * 11AC, so cfreq1/cfreq2 are setup.
467 		 * If it's 80+80 this won't work - need to use seg
468 		 * appropriately!
469 		 */
470 		chan_centre = dfs->dfs_curchan->dfs_ch_mhz_freq_seg1;
471 	} else {
472 		/*
473 		 * HT20/HT40.
474 		 * This is hard-coded - it should be 5 or 10 for half/quarter
475 		 * appropriately.
476 		 */
477 		chan_width = 20;
478 
479 		/* Grab default channel centre. */
480 		chan_centre = dfs->dfs_curchan->dfs_ch_freq;
481 
482 		/* Calculate offset based on HT40U/HT40D and VHT40U/VHT40D. */
483 		if (WLAN_IS_CHAN_11N_HT40PLUS(dfs->dfs_curchan) ||
484 		    WLAN_IS_CHAN_VHT40PLUS(dfs->dfs_curchan))
485 			chan_offset = chan_width;
486 		else if (WLAN_IS_CHAN_11N_HT40MINUS(dfs->dfs_curchan) ||
487 			  WLAN_IS_CHAN_VHT40MINUS(dfs->dfs_curchan))
488 			chan_offset = -chan_width;
489 		else
490 			chan_offset = 0;
491 
492 		/* Calculate new _real_ channel centre. */
493 		chan_centre += (chan_offset / 2);
494 	}
495 
496 	/* Return ev_chan_centre in MHz. */
497 	return chan_centre;
498 }
499 #endif
500 
501 
502 /**
503  * dfs_tlv_calc_event_freq_pulse() - Calculate the centre frequency and
504  *                                   low/high range for a radar pulse event.
505  * @dfs: pointer to wlan_dfs structure.
506  * @rs: pointer to rx_radar_status structure.
507  * @freq_centre: center frequency
508  * @freq_lo: lower bounds of frequency.
509  * @freq_hi: upper bounds of frequency.
510  *
511  * XXX TODO: Handle half/quarter rates correctly!
512  * XXX TODO: handle VHT160 correctly!
513  * XXX TODO: handle VHT80+80 correctly!
514  *
515  * Return: Returns 1.
516  */
517 static int dfs_tlv_calc_event_freq_pulse(struct wlan_dfs *dfs,
518 		struct rx_radar_status *rs,
519 		uint32_t *freq_centre,
520 		uint32_t *freq_lo,
521 		uint32_t *freq_hi)
522 {
523 	int chan_width;
524 	int chan_centre;
525 
526 	/* Fetch the channel centre frequency in MHz. */
527 	chan_centre = dfs_tlv_calc_freq_info(dfs, rs);
528 
529 	/* Convert to KHz. */
530 	chan_centre *= 1000;
531 
532 	/*
533 	 * XXX hard-code event width to be 2 * bin size for now;
534 	 * XXX this needs to take into account the core clock speed
535 	 * XXX for half/quarter rate mode.
536 	 */
537 	if (PERE_IS_OVERSAMPLING(dfs))
538 		chan_width = (44000 * 2 / 128);
539 	else
540 		chan_width = (40000 * 2 / 128);
541 
542 	/* XXX adjust chan_width for half/quarter rate! */
543 
544 	/* Now we can do the math to figure out the correct channel range. */
545 	(*freq_centre) = (uint32_t) (chan_centre + rs->freq_offset);
546 	(*freq_lo) = (uint32_t) ((chan_centre + rs->freq_offset) - chan_width);
547 	(*freq_hi) = (uint32_t) ((chan_centre + rs->freq_offset) + chan_width);
548 
549 	return 1;
550 }
551 
552 /**
553  * dfs_tlv_calc_event_freq_chirp() - Calculate the event freq.
554  * @dfs: pointer to wlan_dfs structure.
555  * @rs: pointer to rx_radar_status structure.
556  * @freq_centre: center frequency
557  * @freq_lo: lower bounds of frequency.
558  * @freq_hi: upper bounds of frequency.
559  *
560  * The chirp bandwidth in KHz is defined as:
561  * totalBW(KHz) = delta_peak(mean)
562  *    * [ (bin resolution in KHz) / (radar_fft_long_period in uS) ]
563  *    * pulse_duration (us)
564  * The bin resolution depends upon oversampling.
565  * For now, we treat the radar_fft_long_period as a hard-coded 8uS.
566  *
567  * Return: Returns 1
568  */
569 static int dfs_tlv_calc_event_freq_chirp(struct wlan_dfs *dfs,
570 		struct rx_radar_status *rs,
571 		uint32_t *freq_centre,
572 		uint32_t *freq_lo,
573 		uint32_t *freq_hi)
574 {
575 	int32_t bin_resolution; /* KHz * 100 */
576 	int32_t radar_fft_long_period = 8; /* microseconds */
577 	int32_t delta_peak;
578 	int32_t pulse_duration;
579 	int32_t total_bw;
580 	int32_t chan_centre;
581 	int32_t freq_1, freq_2;
582 
583 	/*
584 	 * KHz isn't enough resolution here!
585 	 * So treat it as deci-hertz (10Hz) and convert back to KHz later.
586 	 */
587 
588 	if (PERE_IS_OVERSAMPLING(dfs))
589 		bin_resolution = (OVER_SAMPLING_FREQ * HUNDRED) / NUM_BINS;
590 	else
591 		bin_resolution = (SAMPLING_FREQ * HUNDRED) / NUM_BINS;
592 
593 	delta_peak = rs->delta_peak;
594 	pulse_duration = rs->pulse_duration;
595 
596 	total_bw = delta_peak * (bin_resolution / radar_fft_long_period) *
597 		pulse_duration;
598 
599 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR | WLAN_DEBUG_DFS_PHYERR_SUM,
600 		"delta_peak=%d, pulse_duration=%d, bin_resolution=%d.%dKHz, radar_fft_long_period=%d, total_bw=%d.%ldKHz",
601 		delta_peak, pulse_duration, bin_resolution / THOUSAND,
602 		bin_resolution % THOUSAND, radar_fft_long_period,
603 		total_bw / HUNDRED,
604 		(long)abs(total_bw % HUNDRED));
605 
606 	total_bw /= HUNDRED; /* back to KHz */
607 	/* Grab the channel centre frequency in MHz. */
608 	chan_centre = dfs_tlv_calc_freq_info(dfs, rs);
609 
610 	/* Early abort! */
611 	if (chan_centre == 0) {
612 		(*freq_centre) = 0;
613 		return 0;
614 	}
615 
616 	/* Convert to KHz. */
617 	chan_centre *= THOUSAND;
618 
619 	/*
620 	 * Sidx is the starting frequency; total_bw is a signed value and for
621 	 * negative chirps (ie, moving down in frequency rather than up) the end
622 	 * frequency may be less than the start frequency.
623 	 */
624 	if (total_bw > 0) {
625 		freq_1 = chan_centre + rs->freq_offset;
626 		freq_2 = chan_centre + rs->freq_offset + total_bw;
627 	} else {
628 		freq_1 = chan_centre + rs->freq_offset + total_bw;
629 		freq_2 = chan_centre + rs->freq_offset;
630 	}
631 
632 	(*freq_lo) = (uint32_t)(freq_1);
633 	(*freq_hi) = (uint32_t)(freq_2);
634 	(*freq_centre) = (uint32_t) (freq_1 + (abs(total_bw) / 2));
635 
636 	return 1;
637 }
638 
639 /**
640  * dfs_tlv_calc_event_freq() - Calculate the centre and band edge frequencies
641  *                             of the given radar event.
642  * @dfs: Pointer to wlan_dfs structure.
643  * @rs: Pointer to rx_radar_status structure.
644  * @freq_centre: Center frequency
645  * @freq_lo: Lower bounds of frequency.
646  * @freq_hi: Upper bounds of frequency.
647  */
648 static int dfs_tlv_calc_event_freq(struct wlan_dfs *dfs,
649 		struct rx_radar_status *rs,
650 		uint32_t *freq_centre,
651 		uint32_t *freq_lo,
652 		uint32_t *freq_hi)
653 {
654 	if (rs->is_chirp)
655 		return dfs_tlv_calc_event_freq_chirp(dfs, rs, freq_centre,
656 				freq_lo, freq_hi);
657 	else
658 		return dfs_tlv_calc_event_freq_pulse(dfs, rs, freq_centre,
659 				freq_lo, freq_hi);
660 }
661 
662 int dfs_process_phyerr_bb_tlv(struct wlan_dfs *dfs,
663 		void *buf,
664 		uint16_t datalen,
665 		uint8_t rssi,
666 		uint8_t ext_rssi,
667 		uint32_t rs_tstamp,
668 		uint64_t fulltsf,
669 		struct dfs_phy_err *e)
670 {
671 	struct rx_radar_status rs;
672 	struct rx_search_fft_report rsfr;
673 	int first_short_fft_peak_mag = 0;
674 	int16_t psidx_diff;
675 
676 	qdf_mem_zero(&rs, sizeof(rs));
677 	qdf_mem_zero(&rsfr, sizeof(rsfr));
678 
679 	/*
680 	 * Add the ppdu_start/ppdu_end fields given to us by the upper layers.
681 	 * The firmware gives us a summary set of parameters rather than the
682 	 * whole PPDU_START/PPDU_END descriptor contenst.
683 	 */
684 	rs.rssi = rssi;
685 	rs.raw_tsf = rs_tstamp;
686 
687 	/* Try parsing the TLV set. */
688 	if (!dfs_tlv_parse_frame(dfs, &rs, &rsfr, buf, datalen, rssi,
689 				&first_short_fft_peak_mag, &psidx_diff))
690 		return 0;
691 
692 	/* For debugging, print what we have parsed. */
693 	dfs_radar_summary_print(dfs, &rs);
694 
695 	/* Populate dfs_phy_err from rs. */
696 	qdf_mem_zero(e, sizeof(*e));
697 	e->rssi = rs.rssi;
698 	e->dur = rs.pulse_duration;
699 	e->is_pri = 1; /* Always PRI for now */
700 	e->is_ext = 0;
701 	e->is_dc = 0;
702 	e->is_early = 0;
703 
704 	/*
705 	 * XXX TODO: add a "chirp detection enabled" capability or config bit
706 	 * somewhere, in case for some reason the hardware chirp detection AND
707 	 * FFTs are disabled.
708 	 * For now, assume this hardware always does chirp detection.
709 	 */
710 	e->do_check_chirp = 1;
711 	e->is_hw_chirp = !!(rs.is_chirp);
712 	e->is_sw_chirp = 0; /* We don't yet do software chirp checking */
713 
714 	e->fulltsf = fulltsf;
715 	e->rs_tstamp = rs.raw_tsf - rs.tsf_offset;
716 
717 	/* XXX error check */
718 	(void)dfs_tlv_calc_event_freq(dfs, &rs, &e->freq, &e->freq_lo,
719 			&e->freq_hi);
720 
721 	e->seg_id = rsfr.seg_id;
722 	e->sidx = rs.sidx;
723 	e->freq_offset_khz = rs.freq_offset;
724 	e->peak_mag = first_short_fft_peak_mag;
725 	e->total_gain = rs.agc_total_gain;
726 	e->mb_gain = rs.agc_mb_gain;
727 	e->relpwr_db = rsfr.relpwr_db;
728 	e->pulse_delta_peak = rs.delta_peak;
729 	e->pulse_psidx_diff = psidx_diff;
730 	e->pulse_delta_diff = rs.delta_diff;
731 
732 	dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR_SUM,
733 		"fbin=%d, freq=%d.%d MHz, raw tsf=%u, offset=%d, cooked tsf=%u, rssi=%d, dur=%d, is_chirp=%d, fulltsf=%llu, freq=%d.%d MHz, freq_lo=%d.%dMHz, freq_hi=%d.%d MHz",
734 		 rs.sidx, (int) (rs.freq_offset / 1000),
735 		(int) abs(rs.freq_offset % 1000), rs.raw_tsf, rs.tsf_offset,
736 		e->rs_tstamp, rs.rssi, rs.pulse_duration, (int)rs.is_chirp,
737 		(unsigned long long) fulltsf, (int)e->freq / 1000,
738 		(int) abs(e->freq) % 1000, (int)e->freq_lo / 1000,
739 		(int) abs(e->freq_lo) % 1000, (int)e->freq_hi / 1000,
740 		(int) abs(e->freq_hi) % 1000);
741 
742 	dfs_debug(dfs, WLAN_DEBUG_DFS_FALSE_DET,
743 		"ts=%u, dur=%d, rssi=%d, freq_offset=%d.%dMHz, is_chirp=%d, seg_id=%d, peak_mag=%d, total_gain=%d, mb_gain=%d, relpwr_db=%d, delta_peak=%d, delta_diff=%d, psidx_diff=%d",
744 		e->rs_tstamp, rs.pulse_duration, rs.rssi,
745 		(int)e->freq_offset_khz / 1000,
746 		(int)abs(e->freq_offset_khz) % 1000, (int)rs.is_chirp,
747 		rsfr.seg_id, rsfr.peak_mag, rs.agc_total_gain, rs.agc_mb_gain,
748 		rsfr.relpwr_db,
749 		rs.delta_peak,
750 		rs.delta_diff,
751 		psidx_diff);
752 
753 	return 1;
754 }
755