1 /* 2 * Copyright (c) 2012, 2016-2019 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 (dfs->dfs_curchan->dfs_ch_flags & WLAN_CHAN_VHT40PLUS)) 485 chan_offset = chan_width; 486 else if (WLAN_IS_CHAN_11N_HT40MINUS(dfs->dfs_curchan) || 487 (dfs->dfs_curchan->dfs_ch_flags & 488 WLAN_CHAN_VHT40MINUS)) 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 #else 501 #ifdef CONFIG_CHAN_NUM_API 502 static int dfs_tlv_calc_freq_info(struct wlan_dfs *dfs, 503 struct rx_radar_status *rs) 504 { 505 uint32_t chan_centre; 506 uint32_t chan_width; 507 int chan_offset; 508 509 /* For now, just handle up to VHT80 correctly. */ 510 if (!dfs->dfs_curchan) { 511 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs_curchan is null"); 512 return 0; 513 /* 514 * For now, the only 11ac channel with freq1/freq2 setup is 515 * VHT80. Should have a flag macro to check this! 516 */ 517 } else if (WLAN_IS_CHAN_11AC_VHT80(dfs->dfs_curchan)) { 518 /* 519 * 11AC, so cfreq1/cfreq2 are setup. 520 * If it's 80+80 this won't work - need to use seg 521 * appropriately! 522 */ 523 chan_centre = dfs_mlme_ieee2mhz(dfs->dfs_pdev_obj, 524 dfs->dfs_curchan->dfs_ch_vhtop_ch_freq_seg1, 525 dfs->dfs_curchan->dfs_ch_flags); 526 } else { 527 /* 528 * HT20/HT40. 529 * This is hard-coded - it should be 5 or 10 for half/quarter 530 * appropriately. 531 */ 532 chan_width = 20; 533 534 /* Grab default channel centre. */ 535 chan_centre = dfs_chan2freq(dfs->dfs_curchan); 536 537 /* Calculate offset based on HT40U/HT40D and VHT40U/VHT40D. */ 538 if (WLAN_IS_CHAN_11N_HT40PLUS(dfs->dfs_curchan) || 539 dfs->dfs_curchan->dfs_ch_flags & 540 WLAN_CHAN_VHT40PLUS) 541 chan_offset = chan_width; 542 else if (WLAN_IS_CHAN_11N_HT40MINUS(dfs->dfs_curchan) || 543 dfs->dfs_curchan->dfs_ch_flags & 544 WLAN_CHAN_VHT40MINUS) 545 chan_offset = -chan_width; 546 else 547 chan_offset = 0; 548 549 /* Calculate new _real_ channel centre. */ 550 chan_centre += (chan_offset / 2); 551 } 552 553 /* Return ev_chan_centre in MHz. */ 554 return chan_centre; 555 } 556 #endif 557 #endif 558 559 560 /** 561 * dfs_tlv_calc_event_freq_pulse() - Calculate the centre frequency and 562 * low/high range for a radar pulse event. 563 * @dfs: pointer to wlan_dfs structure. 564 * @rs: pointer to rx_radar_status structure. 565 * @freq_centre: center frequency 566 * @freq_lo: lower bounds of frequency. 567 * @freq_hi: upper bounds of frequency. 568 * 569 * XXX TODO: Handle half/quarter rates correctly! 570 * XXX TODO: handle VHT160 correctly! 571 * XXX TODO: handle VHT80+80 correctly! 572 * 573 * Return: Returns 1. 574 */ 575 static int dfs_tlv_calc_event_freq_pulse(struct wlan_dfs *dfs, 576 struct rx_radar_status *rs, 577 uint32_t *freq_centre, 578 uint32_t *freq_lo, 579 uint32_t *freq_hi) 580 { 581 int chan_width; 582 int chan_centre; 583 584 /* Fetch the channel centre frequency in MHz. */ 585 chan_centre = dfs_tlv_calc_freq_info(dfs, rs); 586 587 /* Convert to KHz. */ 588 chan_centre *= 1000; 589 590 /* 591 * XXX hard-code event width to be 2 * bin size for now; 592 * XXX this needs to take into account the core clock speed 593 * XXX for half/quarter rate mode. 594 */ 595 if (PERE_IS_OVERSAMPLING(dfs)) 596 chan_width = (44000 * 2 / 128); 597 else 598 chan_width = (40000 * 2 / 128); 599 600 /* XXX adjust chan_width for half/quarter rate! */ 601 602 /* Now we can do the math to figure out the correct channel range. */ 603 (*freq_centre) = (uint32_t) (chan_centre + rs->freq_offset); 604 (*freq_lo) = (uint32_t) ((chan_centre + rs->freq_offset) - chan_width); 605 (*freq_hi) = (uint32_t) ((chan_centre + rs->freq_offset) + chan_width); 606 607 return 1; 608 } 609 610 /** 611 * dfs_tlv_calc_event_freq_chirp() - Calculate the event freq. 612 * @dfs: pointer to wlan_dfs structure. 613 * @rs: pointer to rx_radar_status structure. 614 * @freq_centre: center frequency 615 * @freq_lo: lower bounds of frequency. 616 * @freq_hi: upper bounds of frequency. 617 * 618 * The chirp bandwidth in KHz is defined as: 619 * totalBW(KHz) = delta_peak(mean) 620 * * [ (bin resolution in KHz) / (radar_fft_long_period in uS) ] 621 * * pulse_duration (us) 622 * The bin resolution depends upon oversampling. 623 * For now, we treat the radar_fft_long_period as a hard-coded 8uS. 624 * 625 * Return: Returns 1 626 */ 627 static int dfs_tlv_calc_event_freq_chirp(struct wlan_dfs *dfs, 628 struct rx_radar_status *rs, 629 uint32_t *freq_centre, 630 uint32_t *freq_lo, 631 uint32_t *freq_hi) 632 { 633 int32_t bin_resolution; /* KHz * 100 */ 634 int32_t radar_fft_long_period = 8; /* microseconds */ 635 int32_t delta_peak; 636 int32_t pulse_duration; 637 int32_t total_bw; 638 int32_t chan_centre; 639 int32_t freq_1, freq_2; 640 641 /* 642 * KHz isn't enough resolution here! 643 * So treat it as deci-hertz (10Hz) and convert back to KHz later. 644 */ 645 646 if (PERE_IS_OVERSAMPLING(dfs)) 647 bin_resolution = (OVER_SAMPLING_FREQ * HUNDRED) / NUM_BINS; 648 else 649 bin_resolution = (SAMPLING_FREQ * HUNDRED) / NUM_BINS; 650 651 delta_peak = rs->delta_peak; 652 pulse_duration = rs->pulse_duration; 653 654 total_bw = delta_peak * (bin_resolution / radar_fft_long_period) * 655 pulse_duration; 656 657 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR | WLAN_DEBUG_DFS_PHYERR_SUM, 658 "delta_peak=%d, pulse_duration=%d, bin_resolution=%d.%dKHz, radar_fft_long_period=%d, total_bw=%d.%ldKHz", 659 delta_peak, pulse_duration, bin_resolution / THOUSAND, 660 bin_resolution % THOUSAND, radar_fft_long_period, 661 total_bw / HUNDRED, 662 (long)abs(total_bw % HUNDRED)); 663 664 total_bw /= HUNDRED; /* back to KHz */ 665 /* Grab the channel centre frequency in MHz. */ 666 chan_centre = dfs_tlv_calc_freq_info(dfs, rs); 667 668 /* Early abort! */ 669 if (chan_centre == 0) { 670 (*freq_centre) = 0; 671 return 0; 672 } 673 674 /* Convert to KHz. */ 675 chan_centre *= THOUSAND; 676 677 /* 678 * Sidx is the starting frequency; total_bw is a signed value and for 679 * negative chirps (ie, moving down in frequency rather than up) the end 680 * frequency may be less than the start frequency. 681 */ 682 if (total_bw > 0) { 683 freq_1 = chan_centre + rs->freq_offset; 684 freq_2 = chan_centre + rs->freq_offset + total_bw; 685 } else { 686 freq_1 = chan_centre + rs->freq_offset + total_bw; 687 freq_2 = chan_centre + rs->freq_offset; 688 } 689 690 (*freq_lo) = (uint32_t)(freq_1); 691 (*freq_hi) = (uint32_t)(freq_2); 692 (*freq_centre) = (uint32_t) (freq_1 + (abs(total_bw) / 2)); 693 694 return 1; 695 } 696 697 /** 698 * dfs_tlv_calc_event_freq() - Calculate the centre and band edge frequencies 699 * of the given radar event. 700 * @dfs: Pointer to wlan_dfs structure. 701 * @rs: Pointer to rx_radar_status structure. 702 * @freq_centre: Center frequency 703 * @freq_lo: Lower bounds of frequency. 704 * @freq_hi: Upper bounds of frequency. 705 */ 706 static int dfs_tlv_calc_event_freq(struct wlan_dfs *dfs, 707 struct rx_radar_status *rs, 708 uint32_t *freq_centre, 709 uint32_t *freq_lo, 710 uint32_t *freq_hi) 711 { 712 if (rs->is_chirp) 713 return dfs_tlv_calc_event_freq_chirp(dfs, rs, freq_centre, 714 freq_lo, freq_hi); 715 else 716 return dfs_tlv_calc_event_freq_pulse(dfs, rs, freq_centre, 717 freq_lo, freq_hi); 718 } 719 720 int dfs_process_phyerr_bb_tlv(struct wlan_dfs *dfs, 721 void *buf, 722 uint16_t datalen, 723 uint8_t rssi, 724 uint8_t ext_rssi, 725 uint32_t rs_tstamp, 726 uint64_t fulltsf, 727 struct dfs_phy_err *e) 728 { 729 struct rx_radar_status rs; 730 struct rx_search_fft_report rsfr; 731 int first_short_fft_peak_mag = 0; 732 int16_t psidx_diff; 733 734 qdf_mem_zero(&rs, sizeof(rs)); 735 qdf_mem_zero(&rsfr, sizeof(rsfr)); 736 737 /* 738 * Add the ppdu_start/ppdu_end fields given to us by the upper layers. 739 * The firmware gives us a summary set of parameters rather than the 740 * whole PPDU_START/PPDU_END descriptor contenst. 741 */ 742 rs.rssi = rssi; 743 rs.raw_tsf = rs_tstamp; 744 745 /* Try parsing the TLV set. */ 746 if (!dfs_tlv_parse_frame(dfs, &rs, &rsfr, buf, datalen, rssi, 747 &first_short_fft_peak_mag, &psidx_diff)) 748 return 0; 749 750 /* For debugging, print what we have parsed. */ 751 dfs_radar_summary_print(dfs, &rs); 752 753 /* Populate dfs_phy_err from rs. */ 754 qdf_mem_zero(e, sizeof(*e)); 755 e->rssi = rs.rssi; 756 e->dur = rs.pulse_duration; 757 e->is_pri = 1; /* Always PRI for now */ 758 e->is_ext = 0; 759 e->is_dc = 0; 760 e->is_early = 0; 761 762 /* 763 * XXX TODO: add a "chirp detection enabled" capability or config bit 764 * somewhere, in case for some reason the hardware chirp detection AND 765 * FFTs are disabled. 766 * For now, assume this hardware always does chirp detection. 767 */ 768 e->do_check_chirp = 1; 769 e->is_hw_chirp = !!(rs.is_chirp); 770 e->is_sw_chirp = 0; /* We don't yet do software chirp checking */ 771 772 e->fulltsf = fulltsf; 773 e->rs_tstamp = rs.raw_tsf - rs.tsf_offset; 774 775 /* XXX error check */ 776 (void)dfs_tlv_calc_event_freq(dfs, &rs, &e->freq, &e->freq_lo, 777 &e->freq_hi); 778 779 e->seg_id = rsfr.seg_id; 780 e->sidx = rs.sidx; 781 e->freq_offset_khz = rs.freq_offset; 782 e->peak_mag = first_short_fft_peak_mag; 783 e->total_gain = rs.agc_total_gain; 784 e->mb_gain = rs.agc_mb_gain; 785 e->relpwr_db = rsfr.relpwr_db; 786 e->pulse_delta_peak = rs.delta_peak; 787 e->pulse_psidx_diff = psidx_diff; 788 e->pulse_delta_diff = rs.delta_diff; 789 790 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR_SUM, 791 "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", 792 rs.sidx, (int) (rs.freq_offset / 1000), 793 (int) abs(rs.freq_offset % 1000), rs.raw_tsf, rs.tsf_offset, 794 e->rs_tstamp, rs.rssi, rs.pulse_duration, (int)rs.is_chirp, 795 (unsigned long long) fulltsf, (int)e->freq / 1000, 796 (int) abs(e->freq) % 1000, (int)e->freq_lo / 1000, 797 (int) abs(e->freq_lo) % 1000, (int)e->freq_hi / 1000, 798 (int) abs(e->freq_hi) % 1000); 799 800 dfs_debug(dfs, WLAN_DEBUG_DFS_FALSE_DET, 801 "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", 802 e->rs_tstamp, rs.pulse_duration, rs.rssi, 803 (int)e->freq_offset_khz / 1000, 804 (int)abs(e->freq_offset_khz) % 1000, (int)rs.is_chirp, 805 rsfr.seg_id, rsfr.peak_mag, rs.agc_total_gain, rs.agc_mb_gain, 806 rsfr.relpwr_db, 807 rs.delta_peak, 808 rs.delta_diff, 809 psidx_diff); 810 811 return 1; 812 } 813