1 /* 2 * Copyright (c) 2013, 2016-2020 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. 4 * Copyright (c) 2002-2010, Atheros Communications Inc. 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /** 20 * DOC: FCC Bin5 are special type of radars because they "chirp". Basically the 21 * pulses move across the frequency band and are called chirping pulses. 22 * dfs_check_chirping() actually examines the FFT data contained in the PHY 23 * error information to figure out whether the pulse is moving across 24 * frequencies. 25 */ 26 27 #include "../dfs.h" 28 #include "wlan_dfs_mlme_api.h" 29 #include "../dfs_channel.h" 30 31 int dfs_bin5_check_pulse(struct wlan_dfs *dfs, struct dfs_event *re, 32 struct dfs_bin5radars *br) 33 { 34 int b5_rssithresh = br->br_pulse.b5_rssithresh; 35 36 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_PULSE, 37 "re_dur=%d, rssi=%d, check_chirp=%d, hw_chirp=%d, sw_chirp=%d", 38 (int)re->re_dur, (int)re->re_rssi, 39 !!(re->re_flags & DFS_EVENT_CHECKCHIRP), 40 !!(re->re_flags & DFS_EVENT_HW_CHIRP), 41 !!(re->re_flags & DFS_EVENT_SW_CHIRP)); 42 43 /* If the SW/HW chirp detection says to fail the pulse,do so. */ 44 if (DFS_EVENT_NOTCHIRP(re)) { 45 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5, 46 "rejecting chirp: ts=%llu, dur=%d, rssi=%d checkchirp=%d, hwchirp=%d, swchirp=%d", 47 (unsigned long long)re->re_full_ts, 48 (int)re->re_dur, (int)re->re_rssi, 49 !!(re->re_flags & DFS_EVENT_CHECKCHIRP), 50 !!(re->re_flags & DFS_EVENT_HW_CHIRP), 51 !!(re->re_flags & DFS_EVENT_SW_CHIRP)); 52 53 return 0; 54 } 55 56 /* Adjust the filter threshold for rssi in non TURBO mode. */ 57 if (!WLAN_IS_CHAN_TURBO(dfs->dfs_curchan)) 58 b5_rssithresh += br->br_pulse.b5_rssimargin; 59 60 /* Check if the pulse is within duration and rssi thresholds. */ 61 if ((re->re_dur >= br->br_pulse.b5_mindur) && 62 (re->re_dur <= br->br_pulse.b5_maxdur) && 63 (re->re_rssi >= b5_rssithresh)) { 64 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5, 65 "dur=%d, rssi=%d - adding!", 66 (int)re->re_dur, (int)re->re_rssi); 67 return 1; 68 } 69 70 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5, 71 "too low to be Bin5 pulse tsf=%llu, dur=%d, rssi=%d", 72 (unsigned long long)re->re_full_ts, 73 (int)re->re_dur, (int)re->re_rssi); 74 75 return 0; 76 } 77 78 int dfs_bin5_addpulse(struct wlan_dfs *dfs, 79 struct dfs_bin5radars *br, 80 struct dfs_event *re, 81 uint64_t thists) 82 { 83 uint32_t index, stop; 84 uint64_t tsDelta; 85 86 /* 87 * Check if this pulse is a valid pulse in terms of repetition, 88 * if not, return without adding it to the queue. PRI : Pulse 89 * Repitetion Interval. 90 * BRI : Burst Repitetion Interval. 91 */ 92 if (br->br_numelems != 0) { 93 index = br->br_lastelem; 94 tsDelta = thists - br->br_elems[index].be_ts; 95 if ((tsDelta < DFS_BIN5_PRI_LOWER_LIMIT) || 96 ((tsDelta > DFS_BIN5_PRI_HIGHER_LIMIT) && 97 (tsDelta < DFS_BIN5_BRI_LOWER_LIMIT))) { 98 return 0; 99 } 100 } 101 102 if (dfs->dfs_min_sidx > re->re_sidx) 103 dfs->dfs_min_sidx = re->re_sidx; 104 105 if (dfs->dfs_max_sidx < re->re_sidx) 106 dfs->dfs_max_sidx = re->re_sidx; 107 /* Circular buffer of size 2^n. */ 108 index = (br->br_lastelem + 1) & DFS_MAX_B5_MASK; 109 br->br_lastelem = index; 110 if (br->br_numelems == DFS_MAX_B5_SIZE) 111 br->br_firstelem = (br->br_firstelem + 1) & DFS_MAX_B5_MASK; 112 else 113 br->br_numelems++; 114 115 br->br_elems[index].be_ts = thists; 116 br->br_elems[index].be_rssi = re->re_rssi; 117 br->br_elems[index].be_dur = re->re_dur; /* This is in u-sec */ 118 stop = 0; 119 index = br->br_firstelem; 120 while ((!stop) && (br->br_numelems - 1) > 0) { 121 if ((thists - br->br_elems[index].be_ts) > 122 ((uint64_t)br->br_pulse.b5_timewindow)) { 123 br->br_numelems--; 124 br->br_firstelem = 125 (br->br_firstelem + 1) & DFS_MAX_B5_MASK; 126 index = br->br_firstelem; 127 } else { 128 stop = 1; 129 } 130 } 131 132 return 1; 133 } 134 135 /** 136 * dfs_calculate_bursts_for_same_rssi() - Calculate bursts for same rssi. 137 * @dfs: Pointer to wlan_dfs structure. 138 * @br: Pointer to dfs_bin5radars structure. 139 * @bursts: Bursts. 140 * @numevents: Number of events. 141 * @prev: prev index. 142 * @this: index to br_elems[]. 143 * @index: index array. 144 */ 145 static inline void dfs_calculate_bursts_for_same_rssi( 146 struct wlan_dfs *dfs, 147 struct dfs_bin5radars *br, 148 uint32_t *bursts, 149 uint32_t *numevents, 150 uint32_t prev, 151 uint32_t this, 152 int *index) 153 { 154 uint32_t rssi_diff; 155 156 if (br->br_elems[this].be_rssi >= br->br_elems[prev].be_rssi) 157 rssi_diff = (br->br_elems[this].be_rssi - 158 br->br_elems[prev].be_rssi); 159 else 160 rssi_diff = (br->br_elems[prev].be_rssi - 161 br->br_elems[this].be_rssi); 162 163 if (rssi_diff <= DFS_BIN5_RSSI_MARGIN) { 164 (*bursts)++; 165 /* 166 * Save the indexes of this pair for later 167 * width variance check. 168 */ 169 if ((*numevents) >= 2) { 170 /* 171 * Make sure the event is not duplicated, possible in 172 * a 3 pulse burst. 173 */ 174 if (index[(*numevents)-1] != prev) 175 index[(*numevents)++] = prev; 176 } else { 177 index[(*numevents)++] = prev; 178 } 179 180 index[(*numevents)++] = this; 181 } else { 182 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5, 183 "Bin5 rssi_diff=%d", rssi_diff); 184 } 185 } 186 187 void bin5_rules_check_internal(struct wlan_dfs *dfs, 188 struct dfs_bin5radars *br, 189 uint32_t *bursts, 190 uint32_t *numevents, 191 uint32_t prev, 192 uint32_t i, 193 uint32_t this, 194 int *index) 195 { 196 uint64_t pri = 0; 197 uint32_t width_diff = 0; 198 199 /* Rule 1: 1000 <= PRI <= 2000 + some margin. */ 200 if (br->br_elems[this].be_ts >= br->br_elems[prev].be_ts) { 201 pri = br->br_elems[this].be_ts - br->br_elems[prev].be_ts; 202 } else { 203 /* Roll over case */ 204 pri = br->br_elems[this].be_ts; 205 } 206 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5, 207 " pri=%llu this.ts=%llu this.dur=%d this.rssi=%d prev.ts=%llu", 208 (uint64_t)pri, 209 (uint64_t) br->br_elems[this].be_ts, 210 (int) br->br_elems[this].be_dur, 211 (int) br->br_elems[this].be_rssi, 212 (uint64_t)br->br_elems[prev].be_ts); 213 214 if (((pri >= DFS_BIN5_PRI_LOWER_LIMIT) && 215 /*pri: pulse repetition interval in us. */ 216 (pri <= DFS_BIN5_PRI_HIGHER_LIMIT))) { 217 /* 218 * Rule 2: pulse width of the pulses in the 219 * burst should be same (+/- margin). 220 */ 221 if (br->br_elems[this].be_dur >= br->br_elems[prev].be_dur) { 222 width_diff = (br->br_elems[this].be_dur 223 - br->br_elems[prev].be_dur); 224 } else { 225 width_diff = (br->br_elems[prev].be_dur 226 - br->br_elems[this].be_dur); 227 } 228 229 if (width_diff <= DFS_BIN5_WIDTH_MARGIN) 230 /* 231 * Rule 3: RSSI of the pulses in the 232 * burst should be same (+/- margin) 233 */ 234 dfs_calculate_bursts_for_same_rssi(dfs, br, bursts, 235 numevents, prev, this, index); 236 else 237 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5, 238 "Bin5 width_diff=%d", width_diff); 239 } else if ((pri >= DFS_BIN5_BRI_LOWER_LIMIT) && 240 (pri <= DFS_BIN5_BRI_UPPER_LIMIT)) { 241 /* Check pulse width to make sure it is in range of bin 5. */ 242 (*bursts)++; 243 } else{ 244 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5, 245 "Bin5 PRI check fail pri=%llu", (uint64_t)pri); 246 } 247 } 248 249 int dfs_bin5_check(struct wlan_dfs *dfs) 250 { 251 struct dfs_bin5radars *br; 252 uint32_t n = 0, i = 0, i1 = 0, this = 0, prev = 0; 253 uint32_t bursts = 0, total_diff = 0, average_diff = 0; 254 uint32_t total_width = 0, average_width = 0, numevents = 0; 255 int index[DFS_MAX_B5_SIZE]; 256 257 if (!dfs) { 258 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL"); 259 return 1; 260 } 261 262 for (n = 0; n < dfs->dfs_rinfo.rn_numbin5radars; n++) { 263 br = &(dfs->dfs_b5radars[n]); 264 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5, "Num elems = %d", 265 br->br_numelems); 266 267 /* Find a valid bin 5 pulse and use it as reference. */ 268 for (i1 = 0; i1 < br->br_numelems; i1++) { 269 this = ((br->br_firstelem + i1) & DFS_MAX_B5_MASK); 270 if ((br->br_elems[this].be_dur >= MIN_BIN5_DUR_MICROSEC) 271 && (br->br_elems[this].be_dur <= 272 MAX_BIN5_DUR_MICROSEC)) { 273 break; 274 } 275 } 276 277 prev = this; 278 for (i = i1 + 1; i < br->br_numelems; i++) { 279 this = ((br->br_firstelem + i) & DFS_MAX_B5_MASK); 280 /* 281 * First make sure it is a bin 5 pulse by checking 282 * the duration. 283 */ 284 if ((br->br_elems[this].be_dur < MIN_BIN5_DUR_MICROSEC) 285 || (br->br_elems[this].be_dur > 286 MAX_BIN5_DUR_MICROSEC)) { 287 continue; 288 } 289 bin5_rules_check_internal(dfs, br, &bursts, &numevents, 290 prev, i, this, index); 291 prev = this; 292 } 293 294 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5, 295 "bursts=%u numevents=%u", bursts, numevents); 296 if (bursts >= br->br_pulse.b5_threshold) { 297 if ((br->br_elems[br->br_lastelem].be_ts - 298 br->br_elems[br->br_firstelem].be_ts) < 299 3000000) 300 return 0; 301 302 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5, 303 "bursts=%u numevents=%u total_width=%d average_width=%d total_diff=%d average_diff=%d", 304 bursts, numevents, total_width, 305 average_width, total_diff, 306 average_diff); 307 dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS, 308 "bin 5 radar detected, bursts=%d", 309 bursts); 310 return 1; 311 } 312 } 313 314 return 0; 315 } 316 317 /** 318 * dfs_check_chirping_sowl() - Chirp detection for Sowl/Howl. 319 * @dfs: Pointer to wlan_dfs structure. 320 * @buf: Phyerr buffer. 321 * @datalen: Phyerr buf length 322 * @is_ctl: detected on primary channel. 323 * @is_ext: detected on extension channel. 324 * @slope: Slope 325 * @is_dc: DC found 326 * 327 * Return: Return TRUE if chirping pulse, FALSE if not. Decision is made 328 * based on processing the FFT data included with the PHY error. 329 * Calculate the slope using the maximum bin index reported in 330 * the FFT data. Calculate slope between FFT packet 0 and packet 331 * n-1. Also calculate slope between packet 1 and packet n. If a 332 * pulse is chirping, a slope of 5 and greater is seen. 333 * Non-chirping pulses have slopes of 0, 1, 2 or 3. 334 */ 335 static int dfs_check_chirping_sowl(struct wlan_dfs *dfs, 336 void *buf, 337 uint16_t datalen, 338 int is_ctl, 339 int is_ext, 340 int *slope, 341 int *is_dc) 342 { 343 #define FFT_LEN 70 344 #define FFT_LOWER_BIN_MAX_INDEX_BYTE 66 345 #define FFT_UPPER_BIN_MAX_INDEX_BYTE 69 346 #define MIN_CHIRPING_SLOPE 4 347 int is_chirp = 0; 348 int p, num_fft_packets = 0; 349 int ctl_slope = 0, ext_slope = 0; 350 int ctl_high0 = 0, ctl_low0 = 0, ctl_slope0 = 0; 351 int ext_high0 = 0, ext_low0 = 0, ext_slope0 = 0; 352 int ctl_high1 = 0, ctl_low1 = 0, ctl_slope1 = 0; 353 int ext_high1 = 0, ext_low1 = 0, ext_slope1 = 0; 354 uint8_t *fft_data_ptr; 355 356 *slope = 0; 357 *is_dc = 0; 358 num_fft_packets = datalen / FFT_LEN; 359 fft_data_ptr = (uint8_t *)buf; 360 361 /* DEBUG - Print relevant portions of the FFT data. */ 362 for (p = 0; p < num_fft_packets; p++) { 363 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT, 364 "fft_data_ptr=0x%pK\t", fft_data_ptr); 365 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT, 366 "[66]=%d [69]=%d", 367 *(fft_data_ptr + FFT_LOWER_BIN_MAX_INDEX_BYTE) >> 2, 368 *(fft_data_ptr + FFT_UPPER_BIN_MAX_INDEX_BYTE) >> 2); 369 fft_data_ptr += FFT_LEN; 370 } 371 372 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT, 373 "datalen=%d num_fft_packets=%d", datalen, num_fft_packets); 374 375 /* 376 * There is not enough FFT data to figure out whether the pulse 377 * is chirping or not. 378 */ 379 if (num_fft_packets < 4) 380 return 0; 381 382 fft_data_ptr = (uint8_t *)buf; 383 384 if (is_ctl) { 385 fft_data_ptr = (uint8_t *)buf; 386 ctl_low0 = *(fft_data_ptr + FFT_LOWER_BIN_MAX_INDEX_BYTE) >> 2; 387 fft_data_ptr += FFT_LEN; 388 ctl_low1 = *(fft_data_ptr + FFT_LOWER_BIN_MAX_INDEX_BYTE) >> 2; 389 390 /* Last packet with first packet. */ 391 fft_data_ptr = 392 (uint8_t *)buf + (FFT_LEN * (num_fft_packets - 1)); 393 ctl_high1 = *(fft_data_ptr + FFT_LOWER_BIN_MAX_INDEX_BYTE) >> 2; 394 395 /* Second last packet with 0th packet. */ 396 fft_data_ptr = 397 (uint8_t *)buf + (FFT_LEN * (num_fft_packets - 2)); 398 ctl_high0 = *(fft_data_ptr + FFT_LOWER_BIN_MAX_INDEX_BYTE) >> 2; 399 400 ctl_slope0 = ctl_high0 - ctl_low0; 401 if (ctl_slope0 < 0) 402 ctl_slope0 *= (-1); 403 404 ctl_slope1 = ctl_high1 - ctl_low1; 405 if (ctl_slope1 < 0) 406 ctl_slope1 *= (-1); 407 408 ctl_slope = 409 ((ctl_slope0 > ctl_slope1) ? ctl_slope0 : ctl_slope1); 410 *slope = ctl_slope; 411 412 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT, 413 "ctl_slope0=%d ctl_slope1=%d ctl_slope=%d", 414 ctl_slope0, ctl_slope1, ctl_slope); 415 } else if (is_ext) { 416 fft_data_ptr = (uint8_t *)buf; 417 ext_low0 = *(fft_data_ptr + FFT_UPPER_BIN_MAX_INDEX_BYTE) >> 2; 418 419 fft_data_ptr += FFT_LEN; 420 ext_low1 = *(fft_data_ptr + FFT_UPPER_BIN_MAX_INDEX_BYTE) >> 2; 421 422 fft_data_ptr = 423 (uint8_t *)buf + (FFT_LEN * (num_fft_packets - 1)); 424 ext_high1 = *(fft_data_ptr + FFT_UPPER_BIN_MAX_INDEX_BYTE) >> 2; 425 fft_data_ptr = 426 (uint8_t *)buf + (FFT_LEN * (num_fft_packets - 2)); 427 428 ext_high0 = *(fft_data_ptr + FFT_UPPER_BIN_MAX_INDEX_BYTE) >> 2; 429 430 ext_slope0 = ext_high0 - ext_low0; 431 if (ext_slope0 < 0) 432 ext_slope0 *= (-1); 433 434 ext_slope1 = ext_high1 - ext_low1; 435 if (ext_slope1 < 0) 436 ext_slope1 *= (-1); 437 438 ext_slope = ((ext_slope0 > ext_slope1) ? 439 ext_slope0 : ext_slope1); 440 *slope = ext_slope; 441 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT | WLAN_DEBUG_DFS_BIN5, 442 "ext_slope0=%d ext_slope1=%d ext_slope=%d", 443 ext_slope0, ext_slope1, ext_slope); 444 } else 445 return 0; 446 447 if ((ctl_slope >= MIN_CHIRPING_SLOPE) || 448 (ext_slope >= MIN_CHIRPING_SLOPE)) { 449 is_chirp = 1; 450 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5 | WLAN_DEBUG_DFS_BIN5_FFT | 451 WLAN_DEBUG_DFS_PHYERR_SUM, "is_chirp=%d is_dc=%d", 452 is_chirp, *is_dc); 453 } 454 455 return is_chirp; 456 457 #undef FFT_LEN 458 #undef FFT_LOWER_BIN_MAX_INDEX_BYTE 459 #undef FFT_UPPER_BIN_MAX_INDEX_BYTE 460 #undef MIN_CHIRPING_SLOPE 461 } 462 463 /** 464 * dfs_check_chirping_merlin() - Merlin (and Osprey, etc) chirp radar chirp 465 * detection. 466 * @dfs: Pointer to wlan_dfs structure. 467 * @buf: Phyerr buffer 468 * @datalen: Phyerr buf length 469 * @is_ctl: detected on primary channel. 470 * @is_ext: detected on extension channel. 471 * @slope: Slope 472 * @is_dc: DC found 473 */ 474 static int dfs_check_chirping_merlin(struct wlan_dfs *dfs, 475 void *buf, 476 uint16_t datalen, 477 int is_ctl, 478 int is_ext, 479 int *slope, 480 int *is_dc) 481 { 482 #define ABS_DIFF(_x, _y) ((int)_x > (int)_y ? (int)_x - (int)_y : \ 483 (int)_y - (int)_x) 484 #define ABS(_x) ((int)_x > 0 ? (int)_x : -(int)_x) 485 /* This should be between 1 and 3. Default is 1. */ 486 #define DELTA_STEP 1 487 /* Number of Diffs to compute. valid range is 2-4. */ 488 #define NUM_DIFFS 3 489 /* Threshold for difference of delta peaks. */ 490 #define MAX_DIFF 2 491 /* Max. number of strong bins for narrow band. */ 492 #define BIN_COUNT_MAX 6 493 494 /* Dynamic 20/40 mode FFT packet format related definition. */ 495 #define NUM_FFT_BYTES_HT40 70 496 #define NUM_BIN_BYTES_HT40 64 497 #define NUM_SUBCHAN_BINS_HT40 64 498 #define LOWER_INDEX_BYTE_HT40 66 499 #define UPPER_INDEX_BYTE_HT40 69 500 #define LOWER_WEIGHT_BYTE_HT40 64 501 #define UPPER_WEIGHT_BYTE_HT40 67 502 #define LOWER_MAG_BYTE_HT40 65 503 #define UPPER_MAG_BYTE_HT40 68 504 505 /* Static 20 mode FFT packet format related definition. */ 506 #define NUM_FFT_BYTES_HT20 31 507 #define NUM_BIN_BYTES_HT20 28 508 #define NUM_SUBCHAN_BINS_HT20 56 509 #define LOWER_INDEX_BYTE_HT20 30 510 #define UPPER_INDEX_BYTE_HT20 30 511 #define LOWER_WEIGHT_BYTE_HT20 28 512 #define UPPER_WEIGHT_BYTE_HT20 28 513 #define LOWER_MAG_BYTE_HT20 29 514 #define UPPER_MAG_BYTE_HT20 29 515 516 int num_fft_packets; /* number of FFT packets reported to software */ 517 int num_fft_bytes; 518 int num_bin_bytes; 519 int num_subchan_bins; 520 int lower_index_byte; 521 int upper_index_byte; 522 int lower_weight_byte; 523 int upper_weight_byte; 524 int lower_mag_byte; 525 int upper_mag_byte; 526 int max_index_lower[DELTA_STEP + NUM_DIFFS]; 527 int max_index_upper[DELTA_STEP + NUM_DIFFS]; 528 int max_mag_lower[DELTA_STEP + NUM_DIFFS]; 529 int max_mag_upper[DELTA_STEP + NUM_DIFFS]; 530 int bin_wt_lower[DELTA_STEP + NUM_DIFFS]; 531 int bin_wt_upper[DELTA_STEP + NUM_DIFFS]; 532 int max_mag_sel[DELTA_STEP + NUM_DIFFS]; 533 int max_mag[DELTA_STEP + NUM_DIFFS]; 534 int max_index[DELTA_STEP + NUM_DIFFS]; 535 int max_d[] = {10, 19, 28}; 536 int min_d[] = {1, 2, 3}; 537 uint8_t *ptr; /* pointer to FFT data */ 538 int i; 539 int fft_start; 540 int chirp_found; 541 int delta_peak[NUM_DIFFS]; 542 int j; 543 int bin_count; 544 int bw_mask; 545 int delta_diff; 546 int same_sign; 547 int temp; 548 549 if (WLAN_IS_CHAN_11N_HT40(dfs->dfs_curchan)) { 550 num_fft_bytes = NUM_FFT_BYTES_HT40; 551 num_bin_bytes = NUM_BIN_BYTES_HT40; 552 num_subchan_bins = NUM_SUBCHAN_BINS_HT40; 553 lower_index_byte = LOWER_INDEX_BYTE_HT40; 554 upper_index_byte = UPPER_INDEX_BYTE_HT40; 555 lower_weight_byte = LOWER_WEIGHT_BYTE_HT40; 556 upper_weight_byte = UPPER_WEIGHT_BYTE_HT40; 557 lower_mag_byte = LOWER_MAG_BYTE_HT40; 558 upper_mag_byte = UPPER_MAG_BYTE_HT40; 559 560 /* If we are in HT40MINUS then swap primary and extension. */ 561 if (WLAN_IS_CHAN_11N_HT40MINUS(dfs->dfs_curchan)) { 562 temp = is_ctl; 563 is_ctl = is_ext; 564 is_ext = temp; 565 } 566 } else { 567 num_fft_bytes = NUM_FFT_BYTES_HT20; 568 num_bin_bytes = NUM_BIN_BYTES_HT20; 569 num_subchan_bins = NUM_SUBCHAN_BINS_HT20; 570 lower_index_byte = LOWER_INDEX_BYTE_HT20; 571 upper_index_byte = UPPER_INDEX_BYTE_HT20; 572 lower_weight_byte = LOWER_WEIGHT_BYTE_HT20; 573 upper_weight_byte = UPPER_WEIGHT_BYTE_HT20; 574 lower_mag_byte = LOWER_MAG_BYTE_HT20; 575 upper_mag_byte = UPPER_MAG_BYTE_HT20; 576 } 577 578 ptr = (uint8_t *)buf; 579 /* Sanity check for FFT buffer. */ 580 if (!ptr || (datalen == 0)) { 581 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT, 582 "FFT buffer pointer is null or size is 0"); 583 return 0; 584 } 585 586 num_fft_packets = (datalen - 3) / num_fft_bytes; 587 if (num_fft_packets < (NUM_DIFFS + DELTA_STEP)) { 588 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT, 589 "datalen = %d, num_fft_packets = %d, too few packets... (exiting)", 590 datalen, num_fft_packets); 591 return 0; 592 } 593 594 if ((((datalen - 3) % num_fft_bytes) == 2) && 595 (datalen > num_fft_bytes)) { 596 ptr += 2; 597 datalen -= 2; 598 } 599 600 for (i = 0; i < (NUM_DIFFS + DELTA_STEP); i++) { 601 fft_start = i * num_fft_bytes; 602 bin_wt_lower[i] = ptr[fft_start + lower_weight_byte] & 0x3f; 603 bin_wt_upper[i] = ptr[fft_start + upper_weight_byte] & 0x3f; 604 max_index_lower[i] = ptr[fft_start + lower_index_byte] >> 2; 605 max_index_upper[i] = (ptr[fft_start + upper_index_byte] >> 2) + 606 num_subchan_bins; 607 608 if (!WLAN_IS_CHAN_11N_HT40(dfs->dfs_curchan)) { 609 /* For HT20 mode indices are 6 bit signed number. */ 610 max_index_lower[i] ^= 0x20; 611 max_index_upper[i] = 0; 612 } 613 614 /* 615 * Reconstruct the maximum magnitude for each sub-channel. 616 * Also select and flag the max overall magnitude between 617 * the two sub-channels. 618 */ 619 620 max_mag_lower[i] = 621 ((ptr[fft_start + lower_index_byte] & 0x03) << 8) + 622 ptr[fft_start + lower_mag_byte]; 623 max_mag_upper[i] = 624 ((ptr[fft_start + upper_index_byte] & 0x03) << 8) + 625 ptr[fft_start + upper_mag_byte]; 626 bw_mask = ((bin_wt_lower[i] == 0) ? 0 : is_ctl) + 627 (((bin_wt_upper[i] == 0) ? 0 : is_ext) << 1); 628 629 /* 630 * Limit the max bin based on channel bandwidth 631 * If the upper sub-channel max index is stuck at '1', 632 * the signal is dominated * by residual DC 633 * (or carrier leak) and should be ignored. 634 */ 635 636 if (bw_mask == 1) { 637 max_mag_sel[i] = 0; 638 max_mag[i] = max_mag_lower[i]; 639 max_index[i] = max_index_lower[i]; 640 } else if (bw_mask == 2) { 641 max_mag_sel[i] = 1; 642 max_mag[i] = max_mag_upper[i]; 643 max_index[i] = max_index_upper[i]; 644 } else if (max_index_upper[i] == num_subchan_bins) { 645 max_mag_sel[i] = 0; /* Ignore DC bin. */ 646 max_mag[i] = max_mag_lower[i]; 647 max_index[i] = max_index_lower[i]; 648 } else { 649 if (max_mag_upper[i] > max_mag_lower[i]) { 650 max_mag_sel[i] = 1; 651 max_mag[i] = max_mag_upper[i]; 652 max_index[i] = max_index_upper[i]; 653 } else { 654 max_mag_sel[i] = 0; 655 max_mag[i] = max_mag_lower[i]; 656 max_index[i] = max_index_lower[i]; 657 } 658 } 659 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT, 660 "i=%d, max_index[i]=%d, max_index_lower[i]=%d, max_index_upper[i]=%d", 661 i, max_index[i], max_index_lower[i], 662 max_index_upper[i]); 663 } 664 665 chirp_found = 1; 666 delta_diff = 0; 667 same_sign = 1; 668 669 /* 670 * delta_diff computation -- look for movement in peak. 671 * make sure that the chirp direction (i.e. sign) is 672 * always the same, i.e. sign of the two peaks should 673 * be same. 674 */ 675 for (i = 0; i < NUM_DIFFS; i++) { 676 delta_peak[i] = max_index[i + DELTA_STEP] - max_index[i]; 677 if (i > 0) { 678 delta_diff = delta_peak[i] - delta_peak[i-1]; 679 same_sign = !((delta_peak[i] & 0x80) ^ 680 (delta_peak[i-1] & 0x80)); 681 } 682 chirp_found &= 683 (ABS(delta_peak[i]) >= min_d[DELTA_STEP - 1]) && 684 (ABS(delta_peak[i]) <= max_d[DELTA_STEP - 1]) && 685 same_sign && (ABS(delta_diff) <= MAX_DIFF); 686 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT, 687 "i=%d, delta_peak[i]=%d, delta_diff=%d", 688 i, delta_peak[i], delta_diff); 689 } 690 691 if (chirp_found) { 692 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT, 693 "CHIRPING_BEFORE_STRONGBIN_YES"); 694 } else { 695 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT, 696 "CHIRPING_BEFORE_STRONGBIN_NO"); 697 } 698 699 /* 700 * Work around for potential hardware data corruption bug. 701 * Check for wide band signal by counting strong bins 702 * indicated by bitmap flags. This check is done if 703 * chirp_found is true. We do this as a final check to 704 * weed out corrupt FFTs bytes. This looks expensive but 705 * in most cases it will exit early. 706 */ 707 708 for (i = 0; (i < (NUM_DIFFS + DELTA_STEP)) && 709 (chirp_found == 1); i++) { 710 bin_count = 0; 711 /* 712 * Point to the start of the 1st byte of the selected 713 * sub-channel. 714 */ 715 fft_start = (i * num_fft_bytes) + (max_mag_sel[i] ? 716 (num_subchan_bins >> 1) : 0); 717 for (j = 0; j < (num_subchan_bins >> 1); j++) { 718 /* 719 * If either bin is flagged "strong", accumulate 720 * the bin_count. It's not accurate, but good 721 * enough... 722 */ 723 bin_count += (ptr[fft_start + j] & 0x88) ? 1 : 0; 724 } 725 chirp_found &= (bin_count > BIN_COUNT_MAX) ? 0 : 1; 726 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT, 727 "i=%d, computed bin_count=%d", 728 i, bin_count); 729 } 730 731 if (chirp_found) { 732 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT | 733 WLAN_DEBUG_DFS_PHYERR_SUM, 734 "CHIRPING_YES"); 735 } else { 736 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5_FFT | 737 WLAN_DEBUG_DFS_PHYERR_SUM, 738 "CHIRPING_NO"); 739 } 740 741 return chirp_found; 742 #undef ABS_DIFF 743 #undef ABS 744 #undef DELTA_STEP 745 #undef NUM_DIFFS 746 #undef MAX_DIFF 747 #undef BIN_COUNT_MAX 748 749 #undef NUM_FFT_BYTES_HT40 750 #undef NUM_BIN_BYTES_HT40 751 #undef NUM_SUBCHAN_BINS_HT40 752 #undef LOWER_INDEX_BYTE_HT40 753 #undef UPPER_INDEX_BYTE_HT40 754 #undef LOWER_WEIGHT_BYTE_HT40 755 #undef UPPER_WEIGHT_BYTE_HT40 756 #undef LOWER_MAG_BYTE_HT40 757 #undef UPPER_MAG_BYTE_HT40 758 759 #undef NUM_FFT_BYTES_HT40 760 #undef NUM_BIN_BYTES_HT40 761 #undef NUM_SUBCHAN_BINS_HT40 762 #undef LOWER_INDEX_BYTE_HT40 763 #undef UPPER_INDEX_BYTE_HT40 764 #undef LOWER_WEIGHT_BYTE_HT40 765 #undef UPPER_WEIGHT_BYTE_HT40 766 #undef LOWER_MAG_BYTE_HT40 767 #undef UPPER_MAG_BYTE_HT40 768 } 769 770 int dfs_check_chirping(struct wlan_dfs *dfs, 771 void *buf, 772 uint16_t datalen, 773 int is_ctl, 774 int is_ext, 775 int *slope, 776 int *is_dc) 777 { 778 if (dfs->dfs_caps.wlan_dfs_use_enhancement) { 779 return dfs_check_chirping_merlin(dfs, buf, datalen, is_ctl, 780 is_ext, slope, is_dc); 781 } else { 782 return dfs_check_chirping_sowl(dfs, buf, datalen, is_ctl, 783 is_ext, slope, is_dc); 784 } 785 } 786 787 uint8_t dfs_retain_bin5_burst_pattern(struct wlan_dfs *dfs, 788 uint32_t diff_ts, 789 uint8_t old_dur) 790 { 791 /* 792 * Pulses may get split into 2 during chirping, this print 793 * is only to show that it happened, we do not handle this 794 * condition if we cannot detect the chirping. 795 */ 796 /* SPLIT pulses will have a time stamp difference of < 50 */ 797 if (diff_ts < 50) { 798 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5, 799 "SPLIT pulse diffTs=%u dur=%d (old_dur=%d)", 800 diff_ts, 801 dfs->dfs_rinfo.dfs_last_bin5_dur, old_dur); 802 } 803 804 /* 805 * Check if this is the 2nd or 3rd pulse in the same burst, 806 * PRI will be between 1000 and 2000 us. 807 */ 808 if (((diff_ts >= DFS_BIN5_PRI_LOWER_LIMIT) && 809 (diff_ts <= DFS_BIN5_PRI_HIGHER_LIMIT))) { 810 /* 811 * This pulse belongs to the same burst as the pulse before, 812 * so return the same random duration for it. 813 */ 814 dfs_debug(dfs, WLAN_DEBUG_DFS_BIN5, 815 "this pulse belongs to the same burst as before, give it same dur=%d (old_dur=%d)", 816 dfs->dfs_rinfo.dfs_last_bin5_dur, old_dur); 817 return dfs->dfs_rinfo.dfs_last_bin5_dur; 818 } 819 820 /* This pulse does not belong to this burst, return unchanged duration*/ 821 return old_dur; 822 } 823 824 int dfs_get_random_bin5_dur(struct wlan_dfs *dfs, 825 uint64_t tstamp) 826 { 827 uint8_t new_dur = MIN_BIN5_DUR; 828 int range; 829 830 get_random_bytes(&new_dur, sizeof(uint8_t)); 831 range = (MAX_BIN5_DUR - MIN_BIN5_DUR + 1); 832 new_dur %= range; 833 new_dur += MIN_BIN5_DUR; 834 835 return new_dur; 836 } 837