1 /* 2 * Copyright (c) 2016-2019 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: DFS specs specify various types of radars to be detected. 20 * Each separate type is called a Bin and has different characteristics. 21 * This file contains the functionality to look at a group of pulses and 22 * to detect whether we have detected a valid radar waveform. To do that, 23 * it must match the group against each different Bin's characteristics. 24 */ 25 26 #include "../dfs.h" 27 #include "../dfs_process_radar_found_ind.h" 28 29 /** 30 * dfs_find_first_index_within_window() - Find first index within window 31 * @pl: Pointer to dfs_pulseline structure. 32 * @index: Index to dfs pulse elements. 33 * @start_ts: Start timestamp. 34 * 35 * Return: Returns index. 36 */ 37 static inline uint32_t dfs_find_first_index_within_window( 38 struct dfs_pulseline *pl, 39 uint32_t index, 40 uint64_t start_ts) 41 { 42 uint16_t i; 43 44 /* Find the index of first element in our window of interest. */ 45 for (i = 0; i < pl->pl_numelems; i++) { 46 index = (index - 1) & DFS_MAX_PULSE_BUFFER_MASK; 47 if (pl->pl_elems[index].p_time >= start_ts) { 48 continue; 49 } else { 50 index = (index) & DFS_MAX_PULSE_BUFFER_MASK; 51 break; 52 } 53 } 54 55 return index; 56 } 57 58 /** 59 * dfs_ts_within_window() - Calculate pulses for timestamp within window 60 * @dfs: Pointer to wlan_dfs structure. 61 * @pl: Pointer to dfs_pulseline structure. 62 * @index: Index to dfs pulse elements. 63 * @dur: Pulse duration/width 64 * @numpulses: Number of pulses 65 * 66 * Return: Returns 1 if pulse count is incremented else returns 0. 67 */ 68 static inline bool dfs_ts_within_window( 69 struct wlan_dfs *dfs, 70 struct dfs_pulseline *pl, 71 uint32_t *index, 72 uint32_t dur, 73 int *numpulses) 74 { 75 uint32_t deltadur; 76 77 deltadur = DFS_DIFF(pl->pl_elems[*index].p_dur, dur); 78 if ((pl->pl_elems[*index].p_dur == 1) || 79 ((dur != 1) && (deltadur <= 2))) { 80 (*numpulses)++; 81 dfs_debug(dfs, WLAN_DEBUG_DFS2, "numpulses %u", *numpulses); 82 return 1; 83 } 84 85 return 0; 86 } 87 88 /** 89 * dfs_ts_eq_prevts() - Calculate pulses for timestamp equals to prev event 90 * @dfs: Pointer to wlan_dfs structure. 91 * @pl: Pointer to dfs_pulseline structure. 92 * @index: Index to dfs pulse elements. 93 * @dur: Pulse duration/width 94 * @numpulses: Number of pulses 95 * 96 * Return: Returns 1 if pulse count is incremented else returns 0. 97 */ 98 static inline bool dfs_ts_eq_prevts( 99 struct wlan_dfs *dfs, 100 struct dfs_pulseline *pl, 101 uint64_t next_event_ts, 102 uint64_t event_ts, 103 uint32_t refpri, 104 uint32_t *index, 105 uint32_t dur, 106 int *numpulses) 107 108 { 109 uint32_t deltadur; 110 111 if (((next_event_ts - event_ts) > refpri) || 112 ((next_event_ts - event_ts) == 0)) { 113 deltadur = DFS_DIFF(pl->pl_elems[*index].p_dur, dur); 114 if ((pl->pl_elems[*index].p_dur == 1) || 115 ((pl->pl_elems[*index].p_dur != 1) && 116 (deltadur <= 2))) { 117 (*numpulses)++; 118 dfs_debug(dfs, WLAN_DEBUG_DFS2, 119 "zero PRI: numpulses %u", *numpulses); 120 return 1; 121 } 122 } 123 124 return 0; 125 } 126 127 /** 128 * dfs_pulses_within_window() - Calculate pulses within window 129 * @dfs: Pointer to wlan_dfs structure. 130 * @window_start: Start of the window. 131 * @window_end: End of the window. 132 * @index: Index to dfs pulse elements. 133 * @dur: Pulse duration/width. 134 * @refpri: reference PRI. 135 * 136 * Return: Returns 1 if pulse count is incremented else returns 0. 137 */ 138 static inline int dfs_pulses_within_window( 139 struct wlan_dfs *dfs, 140 uint64_t window_start, 141 uint64_t window_end, 142 uint32_t *index, 143 uint32_t dur, 144 uint32_t refpri) 145 { 146 int numpulses = 0; 147 uint32_t i; 148 struct dfs_pulseline *pl = dfs->pulses; 149 uint64_t event_ts, prev_event_ts, next_event_ts; 150 uint32_t next_index; 151 152 for (i = 0; i < pl->pl_numelems; i++) { 153 prev_event_ts = pl->pl_elems[*index].p_time; 154 *index = (*index+1) & DFS_MAX_PULSE_BUFFER_MASK; 155 event_ts = pl->pl_elems[*index].p_time; 156 next_index = (*index+1) & DFS_MAX_PULSE_BUFFER_MASK; 157 next_event_ts = pl->pl_elems[next_index].p_time; 158 dfs_debug(dfs, WLAN_DEBUG_DFS2, "ts %u", 159 (uint32_t)event_ts); 160 161 if ((event_ts <= window_end) && (event_ts >= window_start)) { 162 if (dfs_ts_within_window(dfs, pl, index, dur, 163 &numpulses)) 164 break; 165 } else if (event_ts > window_end) { 166 *index = (*index-1) & DFS_MAX_PULSE_BUFFER_MASK; 167 break; 168 } else if (event_ts == prev_event_ts) { 169 if (dfs_ts_eq_prevts(dfs, pl, next_event_ts, event_ts, 170 refpri, index, dur, &numpulses)) 171 break; 172 } 173 if (dfs->dfs_min_sidx > pl->pl_elems[*index].p_sidx) 174 dfs->dfs_min_sidx = pl->pl_elems[*index].p_sidx; 175 176 if (dfs->dfs_max_sidx < pl->pl_elems[*index].p_sidx) 177 dfs->dfs_max_sidx = pl->pl_elems[*index].p_sidx; 178 } 179 180 dfs->dfs_freq_offset = 181 DFS_SIDX_TO_FREQ_OFFSET((dfs->dfs_min_sidx + 182 dfs->dfs_min_sidx) / 2); 183 return numpulses; 184 } 185 186 /** 187 * dfs_count_pulses() - Count pulses 188 * @dfs: Pointer to wlan_dfs structure. 189 * @rf: Pointer to dfs_filter structure. 190 * @dur: Pulse duration/width. 191 * @ext_chan_flag : Ext channel flag. 192 * @primargin: Primary margin. 193 * @index: Index to dfs pulse elements. 194 * @refpri: reference PRI. 195 * @start_ts: Start timestamp. 196 * 197 * Return: Returns number of pulses within window. 198 */ 199 static inline int dfs_count_pulses( 200 struct wlan_dfs *dfs, 201 struct dfs_filter *rf, 202 uint32_t dur, 203 int ext_chan_flag, 204 int primargin, 205 uint32_t index, 206 uint32_t refpri, 207 uint64_t start_ts) 208 { 209 uint32_t n; 210 int numpulses = 0; 211 uint64_t window_start, window_end; 212 213 for (n = 0; n <= rf->rf_numpulses; n++) { 214 window_start = (start_ts + (refpri*n))-(primargin+n); 215 window_end = window_start + 2*(primargin+n); 216 dfs_debug(dfs, WLAN_DEBUG_DFS2, 217 "window_start %u window_end %u", 218 (uint32_t)window_start, (uint32_t)window_end); 219 numpulses += dfs_pulses_within_window(dfs, window_start, 220 window_end, &index, dur, refpri); 221 } 222 223 return numpulses; 224 } 225 226 /** 227 * dfs_bin_fixedpattern_check() - Fixed pattern check 228 * @dfs: Pointer to wlan_dfs structure. 229 * @rf: Pointer to dfs_filter structure. 230 * @dur: Pulse duration/width. 231 * @ext_chan_flag : Ext channel flag. 232 */ 233 static int dfs_bin_fixedpattern_check( 234 struct wlan_dfs *dfs, 235 struct dfs_filter *rf, 236 uint32_t dur, 237 int ext_chan_flag) 238 { 239 struct dfs_pulseline *pl = dfs->pulses; 240 int primargin, numpulses, fil_thresh; 241 uint64_t start_ts, end_ts; 242 uint32_t last_index, first_index; 243 uint32_t refpri; 244 245 refpri = (rf->rf_minpri + rf->rf_maxpri)/2; 246 last_index = pl->pl_lastelem; 247 end_ts = pl->pl_elems[last_index].p_time; 248 start_ts = end_ts - (refpri*rf->rf_numpulses); 249 250 dfs_debug(dfs, WLAN_DEBUG_DFS3, 251 "lastelem ts=%llu start_ts=%llu, end_ts=%llu", 252 (unsigned long long)pl->pl_elems[last_index].p_time, 253 (unsigned long long)start_ts, 254 (unsigned long long) end_ts); 255 256 first_index = dfs_find_first_index_within_window(pl, last_index, 257 start_ts); 258 259 /* For fixed pattern types, rf->rf_patterntype=1. */ 260 primargin = dfs_get_pri_margin(dfs, ext_chan_flag, 261 (rf->rf_patterntype == 1)); 262 263 numpulses = dfs_count_pulses(dfs, rf, dur, ext_chan_flag, primargin, 264 first_index, refpri, start_ts); 265 266 fil_thresh = dfs_get_filter_threshold(dfs, rf, ext_chan_flag); 267 268 if (numpulses >= fil_thresh) { 269 dfs_debug(dfs, WLAN_DEBUG_DFS1, 270 "FOUND filterID=%u numpulses=%d unadj thresh=%d", 271 rf->rf_pulseid, numpulses, rf->rf_threshold); 272 return 1; 273 } else { 274 return 0; 275 } 276 } 277 278 void dfs_add_pulse( 279 struct wlan_dfs *dfs, 280 struct dfs_filter *rf, 281 struct dfs_event *re, 282 uint32_t deltaT, 283 uint64_t this_ts) 284 { 285 uint32_t index, n, window; 286 struct dfs_delayline *dl; 287 288 dl = &rf->rf_dl; 289 /* Circular buffer of size 2^n */ 290 index = (dl->dl_lastelem + 1) & DFS_MAX_DL_MASK; 291 if ((dl->dl_numelems) == DFS_MAX_DL_SIZE) 292 dl->dl_firstelem = (dl->dl_firstelem + 1) & DFS_MAX_DL_MASK; 293 else 294 dl->dl_numelems++; 295 dl->dl_lastelem = index; 296 dl->dl_elems[index].de_time = deltaT; 297 dl->dl_elems[index].de_ts = this_ts; 298 window = deltaT; 299 dl->dl_elems[index].de_dur = re->re_dur; 300 dl->dl_elems[index].de_rssi = re->re_rssi; 301 dl->dl_elems[index].de_seg_id = re->re_seg_id; 302 dl->dl_elems[index].de_sidx = re->re_sidx; 303 dl->dl_elems[index].de_delta_peak = re->re_delta_peak; 304 dl->dl_elems[index].de_psidx_diff = re->re_psidx_diff; 305 dl->dl_elems[index].de_seq_num = dfs->dfs_seq_num; 306 307 dfs_debug(dfs, WLAN_DEBUG_DFS2, 308 "adding: filter id %d, dur=%d, rssi=%d, ts=%llu", 309 rf->rf_pulseid, re->re_dur, 310 re->re_rssi, (unsigned long long int)this_ts); 311 312 for (n = 0; n < dl->dl_numelems-1; n++) { 313 index = (index-1) & DFS_MAX_DL_MASK; 314 /* 315 * Calculate window based on full time stamp instead of deltaT 316 * deltaT (de_time) may result in incorrect window value 317 */ 318 window = (uint32_t) (this_ts - dl->dl_elems[index].de_ts); 319 320 if (window > rf->rf_filterlen) { 321 dl->dl_firstelem = (index+1) & DFS_MAX_DL_MASK; 322 dl->dl_numelems = n+1; 323 } 324 } 325 326 dfs_debug(dfs, WLAN_DEBUG_DFS2, "dl firstElem = %d lastElem = %d", 327 dl->dl_firstelem, dl->dl_lastelem); 328 } 329 330 /** 331 * dfs_find_lowestpri() - Find lowest PRI 332 * @dl: Pointer to dfs delayline. 333 * @lowpriindex: Low PRI index. 334 * @lowpri: Low PRI 335 */ 336 static inline void dfs_find_lowestpri( 337 struct dfs_delayline *dl, 338 uint32_t *lowpriindex, 339 uint32_t *lowpri) 340 { 341 int delayindex; 342 uint32_t refpri; 343 uint32_t n; 344 345 /* Find out the lowest pri. */ 346 for (n = 0; n < dl->dl_numelems; n++) { 347 delayindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK; 348 refpri = dl->dl_elems[delayindex].de_time; 349 if (refpri == 0) { 350 continue; 351 } else if (refpri < *lowpri) { 352 *lowpri = dl->dl_elems[delayindex].de_time; 353 *lowpriindex = n; 354 } 355 } 356 } 357 358 /** 359 * dfs_calculate_score() - Calculate score for the score index 360 * if PRI match is found 361 * @dl: Pointer to dfs delayline. 362 * @rf: Pointer to dfs_filter structure. 363 * @score: score array. 364 * @refpri: reference PRI. 365 * @primargin: PRI margin. 366 * @score_index: Score index. 367 */ 368 static inline void dfs_calculate_score( 369 struct dfs_delayline *dl, 370 struct dfs_filter *rf, 371 int *score, 372 uint32_t refpri, 373 uint32_t primargin, 374 uint32_t score_index) 375 { 376 int pri_match = 0; 377 int dindex; 378 uint32_t searchpri, deltapri, deltapri_2, deltapri_3; 379 uint32_t i; 380 381 for (i = 0; i < dl->dl_numelems; i++) { 382 dindex = (dl->dl_firstelem + i) & DFS_MAX_DL_MASK; 383 searchpri = dl->dl_elems[dindex].de_time; 384 deltapri = DFS_DIFF(searchpri, refpri); 385 deltapri_2 = DFS_DIFF(searchpri, 2*refpri); 386 deltapri_3 = DFS_DIFF(searchpri, 3*refpri); 387 if (rf->rf_ignore_pri_window == 2) 388 pri_match = ((deltapri < primargin) || 389 (deltapri_2 < primargin) || 390 (deltapri_3 < primargin)); 391 else 392 pri_match = (deltapri < primargin); 393 394 if (pri_match) 395 score[score_index]++; 396 } 397 } 398 399 /** 400 * dfs_find_priscores() - Find PRI score 401 * @dl: Pointer to dfs delayline. 402 * @rf: Pointer to dfs_filter structure. 403 * @score: score array. 404 * @primargin: PRI margin. 405 */ 406 static void dfs_find_priscores( 407 struct dfs_delayline *dl, 408 struct dfs_filter *rf, 409 int *score, 410 uint32_t primargin) 411 { 412 int delayindex; 413 uint32_t refpri; 414 uint32_t n; 415 416 qdf_mem_zero(score, sizeof(int)*DFS_MAX_DL_SIZE); 417 418 for (n = 0; n < dl->dl_numelems; n++) { 419 delayindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK; 420 refpri = dl->dl_elems[delayindex].de_time; 421 if (refpri == 0) 422 continue; 423 if (refpri < rf->rf_maxpri) { 424 /* Use only valid PRI range for high score. */ 425 dfs_calculate_score(dl, rf, score, refpri, primargin, 426 n); 427 } else { 428 score[n] = 0; 429 } 430 431 if (score[n] > rf->rf_threshold) { 432 /* 433 * We got the most possible candidate, 434 * no need to continue further. 435 */ 436 break; 437 } 438 } 439 } 440 441 /** 442 * dfs_find_highscore() - Find PRI high score 443 * @dl: Pointer to dfs delayline. 444 * @score: score array. 445 * @highscore: High score. 446 * @highscoreindex: High score index. 447 */ 448 static inline void dfs_find_highscore( 449 struct dfs_delayline *dl, 450 int *score, 451 uint32_t *highscore, 452 uint32_t *highscoreindex) 453 { 454 int delayindex, dindex; 455 uint32_t n; 456 457 *highscore = 0; 458 *highscoreindex = 0; 459 460 for (n = 0; n < dl->dl_numelems; n++) { 461 if (score[n] > *highscore) { 462 *highscore = score[n]; 463 *highscoreindex = n; 464 } else if (score[n] == *highscore) { 465 /* 466 * More than one pri has highscore take the least pri. 467 */ 468 delayindex = (dl->dl_firstelem + *highscoreindex) & 469 DFS_MAX_DL_MASK; 470 dindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK; 471 if (dl->dl_elems[dindex].de_time <= 472 dl->dl_elems[delayindex].de_time) { 473 *highscoreindex = n; 474 } 475 } 476 } 477 478 return; 479 } 480 481 /** 482 * dfs_get_durmargin() - Find duration margin 483 * @rf: Pointer to dfs_filter structure. 484 * @durmargin: Duration margin 485 */ 486 static inline void dfs_get_durmargin( 487 struct dfs_filter *rf, 488 uint32_t *durmargin) 489 { 490 #define DUR_THRESH 10 491 #define LOW_MARGIN 4 492 #define HIGH_MARGIN 6 493 494 if (rf->rf_maxdur < DUR_THRESH) 495 *durmargin = LOW_MARGIN; 496 else 497 *durmargin = HIGH_MARGIN; 498 499 #undef DUR_THRESH 500 #undef LOW_MARGIN 501 #undef HIGH_MARGIN 502 } 503 504 /** 505 * dfs_handle_fixedpattern() - Handle Fixed pattern radar 506 * @dfs: Pointer to wlan_dfs structure. 507 * @dl: Pointer to dfs delayline. 508 * @rf: Pointer to dfs_filter structure. 509 * @dur: Pulse duration/width 510 * @ext_chan_flag : Ext channel flag. 511 */ 512 static inline int dfs_handle_fixedpattern( 513 struct wlan_dfs *dfs, 514 struct dfs_delayline *dl, 515 struct dfs_filter *rf, 516 uint32_t dur, 517 int ext_chan_flag) 518 { 519 int found = 0; 520 521 found = dfs_bin_fixedpattern_check(dfs, rf, dur, ext_chan_flag); 522 if (found) 523 dl->dl_numelems = 0; 524 525 return found; 526 } 527 528 /** 529 * dfs_bin_basic_sanity() - Sanity check 530 * @dl: Pointer to dfs delayline. 531 * @rf: Pointer to dfs_filter structure. 532 * @deltaT: Delta time. 533 */ 534 static inline int dfs_bin_basic_sanity( 535 struct dfs_delayline *dl, 536 struct dfs_filter *rf, 537 uint32_t *deltaT) 538 { 539 if (dl->dl_numelems < (rf->rf_threshold-1)) 540 return 0; 541 542 if (*deltaT > rf->rf_filterlen) 543 return 0; 544 545 return 1; 546 } 547 548 /** 549 * dfs_pick_lowpri() - Pick lowpri as refpri 550 * @dfs: Pointer to wlan_dfs structure. 551 * @dl: Pointer to dfs delayline. 552 * @rf: Pointer to dfs_filter structure. 553 * @lowpriindex: Low PRI index. 554 * @scoreindex: score index. 555 * @primargin: PRI margin. 556 */ 557 #ifdef DFS_PRI_MULTIPLIER 558 static inline void dfs_pick_lowpri(struct wlan_dfs *dfs, 559 struct dfs_delayline *dl, 560 struct dfs_filter *rf, 561 uint32_t lowpriindex, 562 uint32_t *scoreindex, 563 uint32_t primargin) 564 { 565 uint32_t candidate_refpri, deltapri, lowpri; 566 uint32_t dindex_candidate, dindex_lowpri; 567 uint32_t i; 568 569 dindex_candidate = (dl->dl_firstelem + *scoreindex) & DFS_MAX_DL_MASK; 570 dindex_lowpri = (dl->dl_firstelem + lowpriindex) & DFS_MAX_DL_MASK; 571 572 candidate_refpri = dl->dl_elems[dindex_candidate].de_time; 573 lowpri = dl->dl_elems[dindex_lowpri].de_time; 574 575 if (rf->rf_ignore_pri_window == 0 && 576 candidate_refpri != lowpri) { 577 for (i = 1; i <= dfs->dfs_pri_multiplier; i++) { 578 deltapri = DFS_DIFF(candidate_refpri, i * lowpri); 579 if (deltapri < primargin) { 580 *scoreindex = lowpriindex; 581 break; 582 } 583 } 584 } 585 } 586 #else 587 static inline void dfs_pick_lowpri(struct wlan_dfs *dfs, 588 struct dfs_delayline *dl, 589 struct dfs_filter *rf, 590 uint32_t lowpriindex, 591 uint32_t *scoreindex, 592 uint32_t primargin) 593 { 594 } 595 #endif 596 597 /** 598 * dfs_find_scoreindex() - Find score index 599 * @rf: Pointer to dfs_filter structure. 600 * @highscore: High score. 601 * @lowpriindex: Low PRI index. 602 * @highscoreindex: High score index. 603 * @scoreindex: score index. 604 */ 605 static inline void dfs_find_scoreindex( 606 struct dfs_filter *rf, 607 uint32_t highscore, 608 uint32_t lowpriindex, 609 uint32_t highscoreindex, 610 uint32_t *scoreindex) 611 { 612 int lowprichk = 3; 613 614 if (rf->rf_ignore_pri_window > 0) 615 lowprichk = (rf->rf_threshold >> 1)+1; 616 else 617 lowprichk = 3; 618 619 if (highscore < lowprichk) 620 *scoreindex = lowpriindex; 621 else 622 *scoreindex = highscoreindex; 623 } 624 625 /** 626 * dfs_find_refs() - Find reference values. 627 * @dl: Pointer to dfs delayline. 628 * @rf: Pointer to dfs_filter structure. 629 * @scoreindex: score index. 630 * @refdur: Duration value. 631 * @refpri: Current "filter" time for start of pulse in usecs. 632 */ 633 static inline void dfs_find_refs( 634 struct dfs_delayline *dl, 635 struct dfs_filter *rf, 636 uint32_t scoreindex, 637 uint32_t *refdur, 638 uint32_t *refpri) 639 { 640 int delayindex; 641 642 delayindex = (dl->dl_firstelem + scoreindex) & DFS_MAX_DL_MASK; 643 *refdur = dl->dl_elems[delayindex].de_dur; 644 *refpri = dl->dl_elems[delayindex].de_time; 645 646 if (rf->rf_fixed_pri_radar_pulse) 647 *refpri = (rf->rf_minpri + rf->rf_maxpri)/2; 648 } 649 650 /** 651 * dfs_bin_success_print() - Debug print 652 * @dfs: Pointer to wlan_dfs structure. 653 * @rf: Pointer to dfs_filter structure. 654 * @ext_chan_flag: Extension channel flag. 655 * @numpulses: Number of pulses. 656 * @refpri: Current "filter" time for start of pulse in usecs. 657 * @refdur: Duration value. 658 * @primargin: PRI margin. 659 */ 660 static inline void dfs_bin_success_print( 661 struct wlan_dfs *dfs, 662 struct dfs_filter *rf, 663 int ext_chan_flag, 664 int numpulses, 665 uint32_t refpri, 666 uint32_t refdur, 667 uint32_t primargin) 668 { 669 dfs_debug(dfs, WLAN_DEBUG_DFS1, 670 "ext_flag=%d MATCH filter=%u numpulses=%u thresh=%u refdur=%d refpri=%d primargin=%d", 671 ext_chan_flag, rf->rf_pulseid, numpulses, 672 rf->rf_threshold, refdur, refpri, primargin); 673 dfs_print_delayline(dfs, &rf->rf_dl); 674 dfs_print_filter(dfs, rf); 675 } 676 677 int dfs_bin_check( 678 struct wlan_dfs *dfs, 679 struct dfs_filter *rf, 680 uint32_t deltaT, 681 uint32_t width, 682 int ext_chan_flag) 683 { 684 struct dfs_delayline *dl; 685 uint32_t refpri, refdur; 686 uint32_t highscoreindex; 687 uint32_t primargin, highscore; 688 int score[DFS_MAX_DL_SIZE], found = 0; 689 uint32_t scoreindex, lowpriindex = 0, lowpri = 0xffff; 690 int numpulses = 0; 691 int fil_thresh; 692 693 dl = &rf->rf_dl; 694 if (!dfs_bin_basic_sanity(dl, rf, &deltaT)) 695 return 0; 696 697 primargin = dfs_get_pri_margin(dfs, ext_chan_flag, 698 (rf->rf_patterntype == 1)); 699 700 701 if (rf->rf_patterntype == 1) 702 return dfs_handle_fixedpattern(dfs, dl, rf, width, 703 ext_chan_flag); 704 705 dfs_find_lowestpri(dl, &lowpriindex, &lowpri); 706 707 /* Find out the each delay element's pri score. */ 708 dfs_find_priscores(dl, rf, score, primargin); 709 710 /* Find out the high scorer. */ 711 dfs_find_highscore(dl, score, &highscore, &highscoreindex); 712 713 /* 714 * Find the average pri of pulses around the pri of highscore 715 * or the pulses around the lowest pri. 716 */ 717 dfs_find_scoreindex(rf, highscore, lowpriindex, highscoreindex, 718 &scoreindex); 719 720 /* 721 * Observed ETSI type2 while channel loading 31% with pulse pri: 722 * 1489, 2978, 2978, 2978, 1489, 2978, 1489 us. With above logic, 723 * the highscore will be 4 (2978), scoreindex is 5. In this case, 724 * index 0, 4, 6 pulses will be not matched later in 725 * dfs_count_the_other_delay_elements(), which leads to the radar was 726 * not detected. The fix is: compare the highscore pri with lowpri, 727 * if they have relationship, within primargin of 728 * [1, dfs_pri_multiplier] times of lowpri, choose lowpri as refpri. 729 */ 730 dfs_pick_lowpri(dfs, dl, rf, lowpriindex, &scoreindex, primargin); 731 732 /* We got the possible pri, save its parameters as reference. */ 733 dfs_find_refs(dl, rf, scoreindex, &refdur, &refpri); 734 735 numpulses = dfs_bin_pri_check(dfs, rf, dl, score[scoreindex], refpri, 736 refdur, ext_chan_flag, refpri); 737 738 fil_thresh = dfs_get_filter_threshold(dfs, rf, ext_chan_flag); 739 740 if (numpulses >= fil_thresh) { 741 found = 1; 742 dfs_bin_success_print(dfs, rf, ext_chan_flag, numpulses, 743 refpri, refdur, primargin); 744 } 745 746 return found; 747 } 748 749 /** 750 * dfs_update_min_and_max_sidx() - Calculate min and max sidx. 751 * @dl: Pointer to dfs_delayline structure. 752 * @delayindex: Delay index. 753 * @sidx_min: Sidx min. 754 * @sidx_max: Sidx max. 755 * @delta_peak_match_count: Delta peak match count. 756 * @psidx_diff_match_count: Psidx diff match count. 757 * @rf: Pointer to dfs_filter structure. 758 */ 759 static inline void dfs_update_min_and_max_sidx( 760 struct dfs_delayline *dl, 761 int delayindex, 762 int32_t *sidx_min, 763 int32_t *sidx_max, 764 uint8_t *delta_peak_match_count, 765 uint8_t *psidx_diff_match_count, 766 struct dfs_filter *rf) 767 { 768 /* update sidx min/max for false detection check later */ 769 if (*sidx_min > dl->dl_elems[delayindex].de_sidx) 770 *sidx_min = dl->dl_elems[delayindex].de_sidx; 771 772 if (*sidx_max < dl->dl_elems[delayindex].de_sidx) 773 *sidx_max = dl->dl_elems[delayindex].de_sidx; 774 775 if (rf->rf_check_delta_peak) { 776 if (dl->dl_elems[delayindex].de_delta_peak != 0) 777 (*delta_peak_match_count)++; 778 else if ((dl->dl_elems[delayindex].de_psidx_diff >= 779 DFS_MIN_PSIDX_DIFF) && 780 (dl->dl_elems[delayindex].de_psidx_diff <= 781 DFS_MAX_PSIDX_DIFF)) 782 (*psidx_diff_match_count)++; 783 } 784 } 785 786 /** 787 * dfs_check_pulses_for_delta_variance() - Check pulses for delta variance. 788 * @rf: Pointer to dfs_filter structure. 789 * @numpulsetochk: Number of pulses to check. 790 * @delta_time_stamps: Delta time stamp. 791 * @fundamentalpri: Highest PRI. 792 * @primargin: Primary margin. 793 * @numpulses: Number of pulses. 794 * @delayindex: Delay index. 795 * @sidx_min: Sidx min. 796 * @sidx_max: Sidx max. 797 * @delta_peak_match_count: Delta peak match count. 798 * @psidx_diff_match_count: Psidx diff match count. 799 * @dl: Pointer to dfs_delayline structure. 800 */ 801 static inline void dfs_check_pulses_for_delta_variance( 802 struct dfs_filter *rf, 803 int numpulsetochk, 804 uint32_t delta_time_stamps, 805 int fundamentalpri, 806 uint32_t primargin, 807 int *numpulses, 808 int delayindex, 809 int32_t *sidx_min, 810 int32_t *sidx_max, 811 uint8_t *delta_peak_match_count, 812 uint8_t *psidx_diff_match_count, 813 struct dfs_delayline *dl) 814 { 815 uint32_t delta_ts_variance, j; 816 817 for (j = 0; j < numpulsetochk; j++) { 818 delta_ts_variance = DFS_DIFF(delta_time_stamps, 819 ((j + 1) * fundamentalpri)); 820 if (delta_ts_variance < (2 * (j + 1) * primargin)) { 821 dl->dl_seq_num_stop = 822 dl->dl_elems[delayindex].de_seq_num; 823 dfs_update_min_and_max_sidx(dl, delayindex, 824 sidx_min, sidx_max, 825 delta_peak_match_count, 826 psidx_diff_match_count, 827 rf); 828 (*numpulses)++; 829 if (rf->rf_ignore_pri_window > 0) 830 break; 831 } 832 } 833 } 834 835 /** 836 * dfs_count_the_other_delay_elements() - Counts the ther delay elements. 837 * @dfs: Pointer to wlan_dfs structure. 838 * @rf: Pointer to dfs_filter structure. 839 * @dl: Pointer to dfs_delayline structure. 840 * @i: Index value. 841 * @refpri: Current "filter" time for start of pulse in usecs. 842 * @refdur: Duration value. 843 * @primargin: Primary margin. 844 * @durmargin: Duration margin. 845 * @numpulses: Number of pulses. 846 * @delta_peak_match_count: Pointer to delta_peak_match_count. 847 * @psidx_diff_match_count: Pointer to psidx_diff_match_count. 848 * @prev_good_timestamp: Previous good timestamp. 849 * @fundamentalpri: Highest PRI. 850 */ 851 static void dfs_count_the_other_delay_elements( 852 struct wlan_dfs *dfs, 853 struct dfs_filter *rf, 854 struct dfs_delayline *dl, 855 uint32_t i, 856 uint32_t refpri, 857 uint32_t refdur, 858 uint32_t primargin, 859 uint32_t durmargin, 860 int *numpulses, 861 uint8_t *delta_peak_match_count, 862 uint8_t *psidx_diff_match_count, 863 uint32_t *prev_good_timestamp, 864 int fundamentalpri) 865 { 866 int delayindex; 867 uint32_t searchpri, searchdur, deltadur; 868 uint32_t j = 0, delta_time_stamps, deltapri, k; 869 int dindex, primatch, numpulsetochk = 2; 870 int32_t sidx_min = DFS_BIG_SIDX; 871 int32_t sidx_max = -DFS_BIG_SIDX; 872 873 delayindex = (dl->dl_firstelem + i) & DFS_MAX_DL_MASK; 874 searchpri = dl->dl_elems[delayindex].de_time; 875 if (searchpri == 0) { 876 /* 877 * This events PRI is zero, take it as a valid pulse 878 * but decrement next event's PRI by refpri. 879 */ 880 dindex = (delayindex + 1) & DFS_MAX_DL_MASK; 881 dl->dl_elems[dindex].de_time -= refpri; 882 searchpri = refpri; 883 } 884 885 searchdur = dl->dl_elems[delayindex].de_dur; 886 deltadur = DFS_DIFF(searchdur, refdur); 887 deltapri = DFS_DIFF(searchpri, refpri); 888 primatch = 0; 889 890 if ((rf->rf_ignore_pri_window > 0) && (rf->rf_patterntype != 2)) { 891 for (j = 0; j < rf->rf_numpulses; j++) { 892 deltapri = DFS_DIFF(searchpri, (j + 1) * refpri); 893 if (deltapri < (2 * primargin)) { 894 primatch = 1; 895 break; 896 } 897 } 898 } else { 899 for (k = 1; k <= dfs->dfs_pri_multiplier; k++) { 900 deltapri = DFS_DIFF(searchpri, k * refpri); 901 if (deltapri < primargin) { 902 primatch = 1; 903 break; 904 } 905 } 906 } 907 908 if (primatch && (deltadur < durmargin)) { 909 if (*numpulses == 1) { 910 dl->dl_seq_num_second = 911 dl->dl_elems[delayindex].de_seq_num; 912 dfs_update_min_and_max_sidx(dl, delayindex, 913 &sidx_min, &sidx_max, 914 delta_peak_match_count, 915 psidx_diff_match_count, 916 rf); 917 (*numpulses)++; 918 } else { 919 delta_time_stamps = (dl->dl_elems[delayindex].de_ts - 920 *prev_good_timestamp); 921 if ((rf->rf_ignore_pri_window > 0)) { 922 numpulsetochk = rf->rf_numpulses; 923 if ((rf->rf_patterntype == 2) && 924 (fundamentalpri < refpri + 100)) { 925 numpulsetochk = 4; 926 } 927 } else { 928 numpulsetochk = 4; 929 } 930 931 dfs_check_pulses_for_delta_variance(rf, numpulsetochk, 932 delta_time_stamps, fundamentalpri, 933 primargin, numpulses, delayindex, 934 &sidx_min, &sidx_max, 935 delta_peak_match_count, 936 psidx_diff_match_count, 937 dl); 938 } 939 *prev_good_timestamp = dl->dl_elems[delayindex].de_ts; 940 dl->dl_search_pri = searchpri; 941 dl->dl_min_sidx = sidx_min; 942 dl->dl_max_sidx = sidx_max; 943 dl->dl_delta_peak_match_count = *delta_peak_match_count; 944 dl->dl_psidx_diff_match_count = *psidx_diff_match_count; 945 946 dfs_debug(dfs, WLAN_DEBUG_DFS2, 947 "rf->minpri=%d rf->maxpri=%d searchpri = %d index = %d numpulses = %d delta peak match count = %d psidx diff match count = %d deltapri=%d j=%d", 948 rf->rf_minpri, rf->rf_maxpri, searchpri, i, 949 *numpulses, *delta_peak_match_count, 950 *psidx_diff_match_count, deltapri, j); 951 } 952 } 953 954 int dfs_bin_pri_check( 955 struct wlan_dfs *dfs, 956 struct dfs_filter *rf, 957 struct dfs_delayline *dl, 958 uint32_t score, 959 uint32_t refpri, 960 uint32_t refdur, 961 int ext_chan_flag, 962 int fundamentalpri) 963 { 964 uint32_t searchpri, deltapri = 0; 965 uint32_t averagerefpri = 0, MatchCount = 0; 966 uint32_t prev_good_timestamp = 0; 967 int dindex; 968 uint32_t i, primargin, durmargin, highscore = score; 969 uint32_t highscoreindex = 0; 970 /* 971 * First pulse in the burst is most likely being filtered out based on 972 * maxfilterlen. 973 */ 974 int numpulses = 1; 975 uint8_t delta_peak_match_count = 1; 976 uint8_t psidx_diff_match_count = 1; 977 int priscorechk = 1; 978 979 /* Use the adjusted PRI margin to reduce false alarms 980 * For non fixed pattern types, rf->rf_patterntype=0. 981 */ 982 primargin = dfs_get_pri_margin(dfs, ext_chan_flag, 983 (rf->rf_patterntype == 1)); 984 985 if ((refpri > rf->rf_maxpri) || (refpri < rf->rf_minpri)) { 986 numpulses = 0; 987 return numpulses; 988 } 989 990 dfs_get_durmargin(rf, &durmargin); 991 992 if ((!rf->rf_fixed_pri_radar_pulse)) { 993 if (rf->rf_ignore_pri_window == 1) 994 priscorechk = (rf->rf_threshold >> 1); 995 else 996 priscorechk = 1; 997 998 MatchCount = 0; 999 if (score > priscorechk) { 1000 for (i = 0; i < dl->dl_numelems; i++) { 1001 dindex = (dl->dl_firstelem + i) & 1002 DFS_MAX_DL_MASK; 1003 searchpri = dl->dl_elems[dindex].de_time; 1004 deltapri = DFS_DIFF(searchpri, refpri); 1005 if (deltapri < primargin) { 1006 averagerefpri += searchpri; 1007 MatchCount++; 1008 } 1009 } 1010 if (rf->rf_patterntype != 2) { 1011 if (MatchCount > 0) 1012 refpri = (averagerefpri / MatchCount); 1013 } else { 1014 refpri = (averagerefpri / score); 1015 } 1016 } 1017 } 1018 1019 /* Note: Following primultiple calculation should be done 1020 * once per filter during initialization stage (dfs_attach) 1021 * and stored in its array atleast for fixed frequency 1022 * types like FCC Bin1 to save some CPU cycles. 1023 * multiplication, devide operators in the following code 1024 * are left as it is for readability hoping the complier 1025 * will use left/right shifts wherever possible. 1026 */ 1027 dfs_debug(dfs, WLAN_DEBUG_DFS2, 1028 "refpri = %d high score = %d index = %d numpulses = %d", 1029 refpri, highscore, highscoreindex, numpulses); 1030 /* 1031 * Count the other delay elements that have pri and dur with 1032 * in the acceptable range from the reference one. 1033 */ 1034 for (i = 0; i < dl->dl_numelems; i++) 1035 dfs_count_the_other_delay_elements(dfs, rf, dl, i, refpri, 1036 refdur, primargin, durmargin, &numpulses, 1037 &delta_peak_match_count, 1038 &psidx_diff_match_count, 1039 &prev_good_timestamp, fundamentalpri); 1040 1041 return numpulses; 1042 } 1043