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