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