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