1 /* 2 * Copyright (c) 2012, 2016-2018 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 static int dfs_tlv_calc_freq_info(struct wlan_dfs *dfs, 449 struct rx_radar_status *rs) 450 { 451 uint32_t chan_centre; 452 uint32_t chan_width; 453 int chan_offset; 454 455 /* For now, just handle up to VHT80 correctly. */ 456 if (!dfs->dfs_curchan) { 457 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs_curchan is null"); 458 return 0; 459 /* 460 * For now, the only 11ac channel with freq1/freq2 setup is 461 * VHT80. Should have a flag macro to check this! 462 */ 463 } else if (WLAN_IS_CHAN_11AC_VHT80(dfs->dfs_curchan)) { 464 /* 465 * 11AC, so cfreq1/cfreq2 are setup. 466 * If it's 80+80 this won't work - need to use seg 467 * appropriately! 468 */ 469 chan_centre = dfs_mlme_ieee2mhz(dfs->dfs_pdev_obj, 470 dfs->dfs_curchan->dfs_ch_vhtop_ch_freq_seg1, 471 dfs->dfs_curchan->dfs_ch_flags); 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_chan2freq(dfs->dfs_curchan); 482 483 /* Calculate offset based on HT40U/HT40D and VHT40U/VHT40D. */ 484 if (WLAN_IS_CHAN_11N_HT40PLUS(dfs->dfs_curchan) || 485 dfs->dfs_curchan->dfs_ch_flags & 486 WLAN_CHAN_VHT40PLUS) 487 chan_offset = chan_width; 488 else if (WLAN_IS_CHAN_11N_HT40MINUS(dfs->dfs_curchan) || 489 dfs->dfs_curchan->dfs_ch_flags & 490 WLAN_CHAN_VHT40MINUS) 491 chan_offset = -chan_width; 492 else 493 chan_offset = 0; 494 495 /* Calculate new _real_ channel centre. */ 496 chan_centre += (chan_offset / 2); 497 } 498 499 /* Return ev_chan_centre in MHz. */ 500 return chan_centre; 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 */ 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 */ 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 */ 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 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_set(e, sizeof(*e), 0); 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