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