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