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