1 /* 2 * Copyright (c) 2016-2018 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 dfs_debug(dfs, WLAN_DEBUG_DFS2, "dl firstElem = %d lastElem = %d", 326 dl->dl_firstelem, dl->dl_lastelem); 327 } 328 329 /** 330 * dfs_find_lowestpri() - Find lowest PRI 331 * @dl: Pointer to dfs delayline. 332 * @lowpriindex: Low PRI index. 333 * @lowpri: Low PRI 334 */ 335 static inline void dfs_find_lowestpri( 336 struct dfs_delayline *dl, 337 uint32_t *lowpriindex, 338 uint32_t *lowpri) 339 { 340 int delayindex; 341 uint32_t refpri; 342 uint32_t n; 343 344 /* Find out the lowest pri. */ 345 for (n = 0; n < dl->dl_numelems; n++) { 346 delayindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK; 347 refpri = dl->dl_elems[delayindex].de_time; 348 if (refpri == 0) { 349 continue; 350 } else if (refpri < *lowpri) { 351 *lowpri = dl->dl_elems[delayindex].de_time; 352 *lowpriindex = n; 353 } 354 } 355 } 356 357 /** 358 * dfs_calculate_score() - Calculate score for the score index 359 * if PRI match is found 360 * @dl: Pointer to dfs delayline. 361 * @rf: Pointer to dfs_filter structure. 362 * @score: score array. 363 * @refpri: reference PRI. 364 * @primargin: PRI margin. 365 * @score_index: Score index. 366 */ 367 static inline void dfs_calculate_score( 368 struct dfs_delayline *dl, 369 struct dfs_filter *rf, 370 int *score, 371 uint32_t refpri, 372 uint32_t primargin, 373 uint32_t score_index) 374 { 375 int pri_match = 0; 376 int dindex; 377 uint32_t searchpri, deltapri, deltapri_2, deltapri_3; 378 uint32_t i; 379 380 for (i = 0; i < dl->dl_numelems; i++) { 381 dindex = (dl->dl_firstelem + i) & DFS_MAX_DL_MASK; 382 searchpri = dl->dl_elems[dindex].de_time; 383 deltapri = DFS_DIFF(searchpri, refpri); 384 deltapri_2 = DFS_DIFF(searchpri, 2*refpri); 385 deltapri_3 = DFS_DIFF(searchpri, 3*refpri); 386 if (rf->rf_ignore_pri_window == 2) 387 pri_match = ((deltapri < primargin) || 388 (deltapri_2 < primargin) || 389 (deltapri_3 < primargin)); 390 else 391 pri_match = (deltapri < primargin); 392 393 if (pri_match) 394 score[score_index]++; 395 } 396 } 397 398 /** 399 * dfs_find_priscores() - Find PRI score 400 * @dl: Pointer to dfs delayline. 401 * @rf: Pointer to dfs_filter structure. 402 * @score: score array. 403 * @primargin: PRI margin. 404 */ 405 static void dfs_find_priscores( 406 struct dfs_delayline *dl, 407 struct dfs_filter *rf, 408 int *score, 409 uint32_t primargin) 410 { 411 int delayindex; 412 uint32_t refpri; 413 uint32_t n; 414 415 qdf_mem_zero(score, sizeof(int)*DFS_MAX_DL_SIZE); 416 417 for (n = 0; n < dl->dl_numelems; n++) { 418 delayindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK; 419 refpri = dl->dl_elems[delayindex].de_time; 420 if (refpri == 0) 421 continue; 422 if (refpri < rf->rf_maxpri) { 423 /* Use only valid PRI range for high score. */ 424 dfs_calculate_score(dl, rf, score, refpri, primargin, 425 n); 426 } else { 427 score[n] = 0; 428 } 429 430 if (score[n] > rf->rf_threshold) { 431 /* 432 * We got the most possible candidate, 433 * no need to continue further. 434 */ 435 break; 436 } 437 } 438 } 439 440 /** 441 * dfs_find_highscore() - Find PRI high score 442 * @dl: Pointer to dfs delayline. 443 * @score: score array. 444 * @highscore: High score. 445 * @highscoreindex: High score index. 446 */ 447 static inline void dfs_find_highscore( 448 struct dfs_delayline *dl, 449 int *score, 450 uint32_t *highscore, 451 uint32_t *highscoreindex) 452 { 453 int delayindex, dindex; 454 uint32_t n; 455 456 *highscore = 0; 457 *highscoreindex = 0; 458 459 for (n = 0; n < dl->dl_numelems; n++) { 460 if (score[n] > *highscore) { 461 *highscore = score[n]; 462 *highscoreindex = n; 463 } else if (score[n] == *highscore) { 464 /* 465 * More than one pri has highscore take the least pri. 466 */ 467 delayindex = (dl->dl_firstelem + *highscoreindex) & 468 DFS_MAX_DL_MASK; 469 dindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK; 470 if (dl->dl_elems[dindex].de_time <= 471 dl->dl_elems[delayindex].de_time) { 472 *highscoreindex = n; 473 } 474 } 475 } 476 477 return; 478 } 479 480 /** 481 * dfs_get_durmargin() - Find duration margin 482 * @rf: Pointer to dfs_filter structure. 483 * @durmargin: Duration margin 484 */ 485 static inline void dfs_get_durmargin( 486 struct dfs_filter *rf, 487 uint32_t *durmargin) 488 { 489 #define DUR_THRESH 10 490 #define LOW_MARGIN 4 491 #define HIGH_MARGIN 6 492 493 if (rf->rf_maxdur < DUR_THRESH) 494 *durmargin = LOW_MARGIN; 495 else 496 *durmargin = HIGH_MARGIN; 497 498 #undef DUR_THRESH 499 #undef LOW_MARGIN 500 #undef HIGH_MARGIN 501 } 502 503 /** 504 * dfs_handle_fixedpattern() - Handle Fixed pattern radar 505 * @dfs: Pointer to wlan_dfs structure. 506 * @dl: Pointer to dfs delayline. 507 * @rf: Pointer to dfs_filter structure. 508 * @dur: Pulse duration/width 509 * @ext_chan_flag : Ext channel flag. 510 */ 511 static inline int dfs_handle_fixedpattern( 512 struct wlan_dfs *dfs, 513 struct dfs_delayline *dl, 514 struct dfs_filter *rf, 515 uint32_t dur, 516 int ext_chan_flag) 517 { 518 int found = 0; 519 520 found = dfs_bin_fixedpattern_check(dfs, rf, dur, ext_chan_flag); 521 if (found) 522 dl->dl_numelems = 0; 523 524 return found; 525 } 526 527 /** 528 * dfs_bin_basic_sanity() - Sanity check 529 * @dl: Pointer to dfs delayline. 530 * @rf: Pointer to dfs_filter structure. 531 * @deltaT: Delta time. 532 */ 533 static inline int dfs_bin_basic_sanity( 534 struct dfs_delayline *dl, 535 struct dfs_filter *rf, 536 uint32_t *deltaT) 537 { 538 if (dl->dl_numelems < (rf->rf_threshold-1)) 539 return 0; 540 541 if (*deltaT > rf->rf_filterlen) 542 return 0; 543 544 return 1; 545 } 546 547 /** 548 * dfs_find_scoreindex() - Find score index 549 * @rf: Pointer to dfs_filter structure. 550 * @highscore: High score. 551 * @lowpriindex: Low PRI index. 552 * @highscoreindex: High score index. 553 * @scoreindex: score index. 554 */ 555 static inline void dfs_find_scoreindex( 556 struct dfs_filter *rf, 557 uint32_t highscore, 558 uint32_t lowpriindex, 559 uint32_t highscoreindex, 560 uint32_t *scoreindex) 561 { 562 int lowprichk = 3; 563 564 if (rf->rf_ignore_pri_window > 0) 565 lowprichk = (rf->rf_threshold >> 1)+1; 566 else 567 lowprichk = 3; 568 569 if (highscore < lowprichk) 570 *scoreindex = lowpriindex; 571 else 572 *scoreindex = highscoreindex; 573 } 574 575 /** 576 * dfs_find_refs() - Find reference values. 577 * @dl: Pointer to dfs delayline. 578 * @rf: Pointer to dfs_filter structure. 579 * @scoreindex: score index. 580 * @refdur: Duration value. 581 * @refpri: Current "filter" time for start of pulse in usecs. 582 */ 583 static inline void dfs_find_refs( 584 struct dfs_delayline *dl, 585 struct dfs_filter *rf, 586 uint32_t scoreindex, 587 uint32_t *refdur, 588 uint32_t *refpri) 589 { 590 int delayindex; 591 592 delayindex = (dl->dl_firstelem + scoreindex) & DFS_MAX_DL_MASK; 593 *refdur = dl->dl_elems[delayindex].de_dur; 594 *refpri = dl->dl_elems[delayindex].de_time; 595 596 if (rf->rf_fixed_pri_radar_pulse) 597 *refpri = (rf->rf_minpri + rf->rf_maxpri)/2; 598 } 599 600 /** 601 * dfs_bin_success_print() - Debug print 602 * @dfs: Pointer to wlan_dfs structure. 603 * @rf: Pointer to dfs_filter structure. 604 * @ext_chan_flag: Extension channel flag. 605 * @numpulses: Number of pulses. 606 * @refpri: Current "filter" time for start of pulse in usecs. 607 * @refdur: Duration value. 608 * @primargin: PRI margin. 609 */ 610 static inline void dfs_bin_success_print( 611 struct wlan_dfs *dfs, 612 struct dfs_filter *rf, 613 int ext_chan_flag, 614 int numpulses, 615 uint32_t refpri, 616 uint32_t refdur, 617 uint32_t primargin) 618 { 619 dfs_debug(dfs, WLAN_DEBUG_DFS1, 620 "ext_flag=%d MATCH filter=%u numpulses=%u thresh=%u refdur=%d refpri=%d primargin=%d", 621 ext_chan_flag, rf->rf_pulseid, numpulses, 622 rf->rf_threshold, refdur, refpri, primargin); 623 dfs_print_delayline(dfs, &rf->rf_dl); 624 dfs_print_filter(dfs, rf); 625 } 626 627 int dfs_bin_check( 628 struct wlan_dfs *dfs, 629 struct dfs_filter *rf, 630 uint32_t deltaT, 631 uint32_t width, 632 int ext_chan_flag) 633 { 634 struct dfs_delayline *dl; 635 uint32_t refpri, refdur; 636 uint32_t highscoreindex; 637 uint32_t primargin, highscore; 638 int score[DFS_MAX_DL_SIZE], found = 0; 639 uint32_t scoreindex, lowpriindex = 0, lowpri = 0xffff; 640 int numpulses = 0; 641 int fil_thresh; 642 643 dl = &rf->rf_dl; 644 if (!dfs_bin_basic_sanity(dl, rf, &deltaT)) 645 return 0; 646 647 primargin = dfs_get_pri_margin(dfs, ext_chan_flag, 648 (rf->rf_patterntype == 1)); 649 650 651 if (rf->rf_patterntype == 1) 652 return dfs_handle_fixedpattern(dfs, dl, rf, width, 653 ext_chan_flag); 654 655 dfs_find_lowestpri(dl, &lowpriindex, &lowpri); 656 657 /* Find out the each delay element's pri score. */ 658 dfs_find_priscores(dl, rf, score, primargin); 659 660 /* Find out the high scorer. */ 661 dfs_find_highscore(dl, score, &highscore, &highscoreindex); 662 663 /* 664 * Find the average pri of pulses around the pri of highscore 665 * or the pulses around the lowest pri. 666 */ 667 dfs_find_scoreindex(rf, highscore, lowpriindex, highscoreindex, 668 &scoreindex); 669 670 /* We got the possible pri, save its parameters as reference. */ 671 dfs_find_refs(dl, rf, scoreindex, &refdur, &refpri); 672 673 numpulses = dfs_bin_pri_check(dfs, rf, dl, score[scoreindex], refpri, 674 refdur, ext_chan_flag, refpri); 675 676 fil_thresh = dfs_get_filter_threshold(dfs, rf, ext_chan_flag); 677 678 if (numpulses >= fil_thresh) { 679 found = 1; 680 dfs_bin_success_print(dfs, rf, ext_chan_flag, numpulses, 681 refpri, refdur, primargin); 682 } 683 684 return found; 685 } 686 687 /** 688 * dfs_update_min_and_max_sidx() - Calculate min and max sidx. 689 * @dl: Pointer to dfs_delayline structure. 690 * @delayindex: Delay index. 691 * @sidx_min: Sidx min. 692 * @sidx_max: Sidx max. 693 * @delta_peak_match_count: Delta peak match count. 694 * @psidx_diff_match_count: Psidx diff match count. 695 * @rf: Pointer to dfs_filter structure. 696 */ 697 static inline void dfs_update_min_and_max_sidx( 698 struct dfs_delayline *dl, 699 int delayindex, 700 int32_t *sidx_min, 701 int32_t *sidx_max, 702 uint8_t *delta_peak_match_count, 703 uint8_t *psidx_diff_match_count, 704 struct dfs_filter *rf) 705 { 706 /* update sidx min/max for false detection check later */ 707 if (*sidx_min > dl->dl_elems[delayindex].de_sidx) 708 *sidx_min = dl->dl_elems[delayindex].de_sidx; 709 710 if (*sidx_max < dl->dl_elems[delayindex].de_sidx) 711 *sidx_max = dl->dl_elems[delayindex].de_sidx; 712 713 if (rf->rf_check_delta_peak) { 714 if (dl->dl_elems[delayindex].de_delta_peak != 0) 715 (*delta_peak_match_count)++; 716 else if ((dl->dl_elems[delayindex].de_psidx_diff >= 717 DFS_MIN_PSIDX_DIFF) && 718 (dl->dl_elems[delayindex].de_psidx_diff <= 719 DFS_MAX_PSIDX_DIFF)) 720 (*psidx_diff_match_count)++; 721 } 722 } 723 724 /** 725 * dfs_check_pulses_for_delta_variance() - Check pulses for delta variance. 726 * @rf: Pointer to dfs_filter structure. 727 * @numpulsetochk: Number of pulses to check. 728 * @delta_time_stamps: Delta time stamp. 729 * @fundamentalpri: Highest PRI. 730 * @primargin: Primary margin. 731 * @numpulses: Number of pulses. 732 * @delayindex: Delay index. 733 * @sidx_min: Sidx min. 734 * @sidx_max: Sidx max. 735 * @delta_peak_match_count: Delta peak match count. 736 * @psidx_diff_match_count: Psidx diff match count. 737 * @dl: Pointer to dfs_delayline structure. 738 */ 739 static inline void dfs_check_pulses_for_delta_variance( 740 struct dfs_filter *rf, 741 int numpulsetochk, 742 uint32_t delta_time_stamps, 743 int fundamentalpri, 744 uint32_t primargin, 745 int *numpulses, 746 int delayindex, 747 int32_t *sidx_min, 748 int32_t *sidx_max, 749 uint8_t *delta_peak_match_count, 750 uint8_t *psidx_diff_match_count, 751 struct dfs_delayline *dl) 752 { 753 uint32_t delta_ts_variance, j; 754 755 for (j = 0; j < numpulsetochk; j++) { 756 delta_ts_variance = DFS_DIFF(delta_time_stamps, 757 ((j + 1) * fundamentalpri)); 758 if (delta_ts_variance < (2 * (j + 1) * primargin)) { 759 dl->dl_seq_num_stop = 760 dl->dl_elems[delayindex].de_seq_num; 761 dfs_update_min_and_max_sidx(dl, delayindex, 762 sidx_min, sidx_max, 763 delta_peak_match_count, 764 psidx_diff_match_count, 765 rf); 766 (*numpulses)++; 767 if (rf->rf_ignore_pri_window > 0) 768 break; 769 } 770 } 771 } 772 773 /** 774 * dfs_count_the_other_delay_elements() - Counts the ther delay elements. 775 * @dfs: Pointer to wlan_dfs structure. 776 * @rf: Pointer to dfs_filter structure. 777 * @dl: Pointer to dfs_delayline structure. 778 * @i: Index value. 779 * @refpri: Current "filter" time for start of pulse in usecs. 780 * @refdur: Duration value. 781 * @primargin: Primary margin. 782 * @durmargin: Duration margin. 783 * @numpulses: Number of pulses. 784 * @delta_peak_match_count: Pointer to delta_peak_match_count. 785 * @psidx_diff_match_count: Pointer to psidx_diff_match_count. 786 * @prev_good_timestamp: Previous good timestamp. 787 * @fundamentalpri: Highest PRI. 788 */ 789 static void dfs_count_the_other_delay_elements( 790 struct wlan_dfs *dfs, 791 struct dfs_filter *rf, 792 struct dfs_delayline *dl, 793 uint32_t i, 794 uint32_t refpri, 795 uint32_t refdur, 796 uint32_t primargin, 797 uint32_t durmargin, 798 int *numpulses, 799 uint8_t *delta_peak_match_count, 800 uint8_t *psidx_diff_match_count, 801 uint32_t *prev_good_timestamp, 802 int fundamentalpri) 803 { 804 int delayindex; 805 uint32_t searchpri, searchdur, deltadur, deltapri1, deltapri2; 806 uint32_t j = 0, delta_time_stamps, deltapri; 807 int dindex, primatch, numpulsetochk = 2; 808 int32_t sidx_min = DFS_BIG_SIDX; 809 int32_t sidx_max = -DFS_BIG_SIDX; 810 811 delayindex = (dl->dl_firstelem + i) & DFS_MAX_DL_MASK; 812 searchpri = dl->dl_elems[delayindex].de_time; 813 if (searchpri == 0) { 814 /* 815 * This events PRI is zero, take it as a valid pulse 816 * but decrement next event's PRI by refpri. 817 */ 818 dindex = (delayindex + 1) & DFS_MAX_DL_MASK; 819 dl->dl_elems[dindex].de_time -= refpri; 820 searchpri = refpri; 821 } 822 searchdur = dl->dl_elems[delayindex].de_dur; 823 deltadur = DFS_DIFF(searchdur, refdur); 824 deltapri = DFS_DIFF(searchpri, refpri); 825 deltapri1 = DFS_DIFF(searchpri, refpri); 826 deltapri2 = DFS_DIFF(searchpri, 2 * refpri); 827 primatch = 0; 828 829 if ((rf->rf_ignore_pri_window > 0) && (rf->rf_patterntype != 2)) { 830 for (j = 0; j < rf->rf_numpulses; j++) { 831 deltapri1 = DFS_DIFF(searchpri, (j + 1) * refpri); 832 if (deltapri1 < (2 * primargin)) { 833 primatch = 1; 834 break; 835 } 836 } 837 } else if ((deltapri1 < primargin) || (deltapri2 < primargin)) { 838 primatch = 1; 839 } 840 841 if (primatch && (deltadur < durmargin)) { 842 if (*numpulses == 1) { 843 dl->dl_seq_num_second = 844 dl->dl_elems[delayindex].de_seq_num; 845 dfs_update_min_and_max_sidx(dl, delayindex, 846 &sidx_min, &sidx_max, 847 delta_peak_match_count, 848 psidx_diff_match_count, 849 rf); 850 (*numpulses)++; 851 } else { 852 delta_time_stamps = (dl->dl_elems[delayindex].de_ts - 853 *prev_good_timestamp); 854 if ((rf->rf_ignore_pri_window > 0)) { 855 numpulsetochk = rf->rf_numpulses; 856 if ((rf->rf_patterntype == 2) && 857 (fundamentalpri < refpri + 100)) { 858 numpulsetochk = 4; 859 } 860 } else { 861 numpulsetochk = 4; 862 } 863 864 dfs_check_pulses_for_delta_variance(rf, numpulsetochk, 865 delta_time_stamps, fundamentalpri, 866 primargin, numpulses, delayindex, 867 &sidx_min, &sidx_max, 868 delta_peak_match_count, 869 psidx_diff_match_count, 870 dl); 871 } 872 *prev_good_timestamp = dl->dl_elems[delayindex].de_ts; 873 dl->dl_search_pri = searchpri; 874 dl->dl_min_sidx = sidx_min; 875 dl->dl_max_sidx = sidx_max; 876 dl->dl_delta_peak_match_count = *delta_peak_match_count; 877 dl->dl_psidx_diff_match_count = *psidx_diff_match_count; 878 879 dfs_debug(dfs, WLAN_DEBUG_DFS2, 880 "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", 881 rf->rf_minpri, rf->rf_maxpri, searchpri, i, 882 *numpulses, *delta_peak_match_count, 883 *psidx_diff_match_count, deltapri, j); 884 } 885 } 886 887 int dfs_bin_pri_check( 888 struct wlan_dfs *dfs, 889 struct dfs_filter *rf, 890 struct dfs_delayline *dl, 891 uint32_t score, 892 uint32_t refpri, 893 uint32_t refdur, 894 int ext_chan_flag, 895 int fundamentalpri) 896 { 897 uint32_t searchpri, deltapri = 0; 898 uint32_t averagerefpri = 0, MatchCount = 0; 899 uint32_t prev_good_timestamp = 0; 900 int dindex; 901 uint32_t i, primargin, durmargin, highscore = score; 902 uint32_t highscoreindex = 0; 903 /* 904 * First pulse in the burst is most likely being filtered out based on 905 * maxfilterlen. 906 */ 907 int numpulses = 1; 908 uint8_t delta_peak_match_count = 1; 909 uint8_t psidx_diff_match_count = 1; 910 int priscorechk = 1; 911 912 /* Use the adjusted PRI margin to reduce false alarms 913 * For non fixed pattern types, rf->rf_patterntype=0. 914 */ 915 primargin = dfs_get_pri_margin(dfs, ext_chan_flag, 916 (rf->rf_patterntype == 1)); 917 918 if ((refpri > rf->rf_maxpri) || (refpri < rf->rf_minpri)) { 919 numpulses = 0; 920 return numpulses; 921 } 922 923 dfs_get_durmargin(rf, &durmargin); 924 925 if ((!rf->rf_fixed_pri_radar_pulse)) { 926 if (rf->rf_ignore_pri_window == 1) 927 priscorechk = (rf->rf_threshold >> 1); 928 else 929 priscorechk = 1; 930 931 MatchCount = 0; 932 if (score > priscorechk) { 933 for (i = 0; i < dl->dl_numelems; i++) { 934 dindex = (dl->dl_firstelem + i) & 935 DFS_MAX_DL_MASK; 936 searchpri = dl->dl_elems[dindex].de_time; 937 deltapri = DFS_DIFF(searchpri, refpri); 938 if (deltapri < primargin) { 939 averagerefpri += searchpri; 940 MatchCount++; 941 } 942 } 943 if (rf->rf_patterntype != 2) { 944 if (MatchCount > 0) 945 refpri = (averagerefpri / MatchCount); 946 } else { 947 refpri = (averagerefpri / score); 948 } 949 } 950 } 951 952 /* Note: Following primultiple calculation should be done 953 * once per filter during initialization stage (dfs_attach) 954 * and stored in its array atleast for fixed frequency 955 * types like FCC Bin1 to save some CPU cycles. 956 * multiplication, devide operators in the following code 957 * are left as it is for readability hoping the complier 958 * will use left/right shifts wherever possible. 959 */ 960 dfs_debug(dfs, WLAN_DEBUG_DFS2, 961 "refpri = %d high score = %d index = %d numpulses = %d", 962 refpri, highscore, highscoreindex, numpulses); 963 /* 964 * Count the other delay elements that have pri and dur with 965 * in the acceptable range from the reference one. 966 */ 967 for (i = 0; i < dl->dl_numelems; i++) 968 dfs_count_the_other_delay_elements(dfs, rf, dl, i, refpri, 969 refdur, primargin, durmargin, &numpulses, 970 &delta_peak_match_count, 971 &psidx_diff_match_count, 972 &prev_good_timestamp, fundamentalpri); 973 974 return numpulses; 975 } 976