1 /* 2 * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2002-2010, Atheros Communications Inc. 4 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. 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: For each radar pulse that the HW detects, a single radar PHY error is 21 * reported to the driver. This PHY error contains information like the RSSI, 22 * the pulse duration, the pulse location (primary/extension/DC) and possibly 23 * FFT data. 24 */ 25 26 #include "../dfs.h" 27 #include "../dfs_zero_cac.h" 28 #include "../dfs_channel.h" 29 #include "wlan_dfs_mlme_api.h" 30 #include "../dfs_internal.h" 31 32 #ifdef WLAN_DFS_PARTIAL_OFFLOAD 33 /** 34 * dfs_get_event_freqwidth() - Get frequency width. 35 * @dfs: Pointer to wlan_dfs structure. 36 * 37 * Return: Return the frequency width for the current operating channel. 38 * This isn't the channel width - it's how wide the reported event may be. 39 * For HT20 this is 20MHz. For HT40 on Howl and later it'll still be 20MHz 40 * - the hardware returns either pri or ext channel. 41 */ 42 static inline int dfs_get_event_freqwidth(struct wlan_dfs *dfs) 43 { 44 /* Handle edge cases during startup/transition, shouldn't happen! */ 45 if (!dfs) 46 return 0; 47 48 if (!dfs->dfs_curchan) 49 return 0; 50 51 /* 52 * For now, assume 20MHz wide - but this is incorrect when operating in 53 * half/quarter mode! 54 */ 55 return 20; 56 } 57 58 /** 59 * dfs_get_event_freqcentre() - Get event frequency centre. 60 * @dfs: Pointer to wlan_dfs structure. 61 * @is_pri: detected on primary channel. 62 * @is_ext: detected on extension channel. 63 * @is_dc: detected at DC. 64 * 65 * Return the centre frequency for the current operating channel and event. 66 * This is for post-Owl 11n chips which report pri/extension channel events. 67 */ 68 static inline uint16_t dfs_get_event_freqcentre(struct wlan_dfs *dfs, 69 int is_pri, 70 int is_ext, 71 int is_dc) 72 { 73 int chan_offset = 0, chan_width; 74 75 /* Handle edge cases during startup/transition, shouldn't happen! */ 76 if (!dfs) 77 return 0; 78 if (!dfs->dfs_curchan) 79 return 0; 80 81 /* 82 * For wide channels, DC and ext frequencies need a bit of hand-holding 83 * based on whether it's an upper or lower channel. 84 */ 85 chan_width = dfs_get_event_freqwidth(dfs); 86 87 if (WLAN_IS_CHAN_11N_HT40PLUS(dfs->dfs_curchan)) 88 chan_offset = chan_width; 89 else if (WLAN_IS_CHAN_11N_HT40MINUS(dfs->dfs_curchan)) 90 chan_offset = -chan_width; 91 else 92 chan_offset = 0; 93 94 /* 95 * Check for DC events first - the sowl code may just set all the bits 96 * together. 97 */ 98 if (is_dc) { 99 /* XXX TODO: Should DC events be considered 40MHz wide here? */ 100 return dfs_chan2freq( 101 dfs->dfs_curchan) + (chan_offset / 2); 102 } 103 104 /* 105 * For non-wide channels, the centre frequency is just dfs_ch_freq. 106 * The centre frequency for pri events is still dfs_ch_freq. 107 */ 108 if (is_pri) 109 return dfs_chan2freq(dfs->dfs_curchan); 110 111 if (is_ext) 112 return dfs_chan2freq(dfs->dfs_curchan) + chan_width; 113 114 return dfs_chan2freq(dfs->dfs_curchan); 115 } 116 117 /** 118 * dfs_process_phyerr_owl() - Process an Owl-style phy error. 119 * @dfs: Pointer to wlan_dfs structure. 120 * @buf: Phyerr buffer 121 * @datalen: Phyerr buf len 122 * @rssi: RSSI 123 * @ext_rssi: Extension RSSI. 124 * @rs_tstamp: Time stamp. 125 * @fulltsf: TSF64. 126 * @e: Pointer to dfs_phy_err structure. 127 * 128 * Return: Returns 1. 129 */ 130 static int dfs_process_phyerr_owl(struct wlan_dfs *dfs, 131 void *buf, 132 uint16_t datalen, 133 uint8_t rssi, 134 uint8_t ext_rssi, 135 uint32_t rs_tstamp, 136 uint64_t fulltsf, 137 struct dfs_phy_err *e) 138 { 139 const char *cbuf = (const char *) buf; 140 uint8_t dur; 141 int event_width; 142 143 dfs->wlan_dfs_stats.owl_phy_errors++; 144 145 /* 146 * HW cannot detect extension channel radar so it only passes us primary 147 * channel radar data. 148 */ 149 if (datalen == 0) 150 dur = 0; 151 else 152 dur = ((uint8_t *) cbuf)[0]; 153 154 /* This is a spurious event; toss. */ 155 if (rssi == 0 && dur == 0) { 156 dfs->wlan_dfs_stats.datalen_discards++; 157 return 0; 158 } 159 160 /* Fill out dfs_phy_err with the information we have at hand. */ 161 qdf_mem_zero(e, sizeof(*e)); 162 e->rssi = rssi; 163 e->dur = dur; 164 e->is_pri = 1; 165 e->is_ext = 0; 166 e->is_dc = 0; 167 e->is_early = 1; 168 e->fulltsf = fulltsf; 169 e->rs_tstamp = rs_tstamp; 170 171 /* 172 * Owl only ever reports events on the primary channel. It doesn't 173 * even see events on the secondary channel. 174 */ 175 event_width = dfs_get_event_freqwidth(dfs); 176 e->freq = dfs_get_event_freqcentre(dfs, 1, 0, 0) * 1000; 177 e->freq_lo = e->freq - (event_width / 2) * 1000; 178 e->freq_hi = e->freq + (event_width / 2) * 1000; 179 180 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR_SUM, 181 "rssi=%u dur=%u, freq=%d MHz, freq_lo=%d MHz, freq_hi=%d MHz", 182 rssi, dur, e->freq/1000, e->freq_lo/1000, 183 e->freq_hi / 1000); 184 185 return 1; 186 } 187 188 /** 189 * dfs_process_phyerr_sowl() -Process a Sowl/Howl style phy error. 190 * @dfs: Pointer to wlan_dfs structure. 191 * @buf: Phyerr buffer 192 * @datalen: Phyerr buf len 193 * @rssi: RSSI 194 * @ext_rssi: Extension RSSI. 195 * @rs_tstamp: Time stamp. 196 * @fulltsf: TSF64. 197 * @e: Pointer to dfs_phy_err structure. 198 * 199 * Return: Returns 1. 200 */ 201 static int dfs_process_phyerr_sowl(struct wlan_dfs *dfs, 202 void *buf, 203 uint16_t datalen, 204 uint8_t rssi, 205 uint8_t ext_rssi, 206 uint32_t rs_tstamp, 207 uint64_t fulltsf, 208 struct dfs_phy_err *e) 209 { 210 #define EXT_CH_RADAR_FOUND 0x02 211 #define PRI_CH_RADAR_FOUND 0x01 212 #define EXT_CH_RADAR_EARLY_FOUND 0x04 213 const char *cbuf = (const char *)buf; 214 uint8_t dur = 0; 215 uint8_t pulse_bw_info, pulse_length_ext, pulse_length_pri; 216 int pri_found = 0, ext_found = 0; 217 int early_ext = 0; 218 int event_width; 219 220 /* 221 * If radar can be detected on the extension channel, datalen zero 222 * pulses are bogus, discard them. 223 */ 224 if (!datalen) { 225 dfs->wlan_dfs_stats.datalen_discards++; 226 return 0; 227 } 228 229 /* Ensure that we have at least three bytes of payload. */ 230 if (datalen < 3) { 231 dfs_debug(dfs, WLAN_DEBUG_DFS, 232 "short error frame (%d bytes)", datalen); 233 dfs->wlan_dfs_stats.datalen_discards++; 234 return 0; 235 } 236 237 /* 238 * Fetch the payload directly - the compiler will happily generate 239 * byte-read instructions with a const char * cbuf pointer. 240 */ 241 pulse_length_pri = cbuf[datalen - 3]; 242 pulse_length_ext = cbuf[datalen - 2]; 243 pulse_bw_info = cbuf[datalen - 1]; 244 245 /* 246 * Only the last 3 bits of the BW info are relevant, they indicate 247 * which channel the radar was detected in. 248 */ 249 pulse_bw_info &= 0x07; 250 251 /* If pulse on DC, both primary and extension flags will be set */ 252 if (((pulse_bw_info & EXT_CH_RADAR_FOUND) && 253 (pulse_bw_info & PRI_CH_RADAR_FOUND))) { 254 /* 255 * Conducted testing, when pulse is on DC, both pri and ext 256 * durations are reported to be same. Radiated testing, when 257 * pulse is on DC, differentpri and ext durations are reported, 258 * so take the larger of the two. 259 */ 260 if (pulse_length_ext >= pulse_length_pri) { 261 dur = pulse_length_ext; 262 ext_found = 1; 263 } else { 264 dur = pulse_length_pri; 265 pri_found = 1; 266 } 267 dfs->wlan_dfs_stats.dc_phy_errors++; 268 } else { 269 if (pulse_bw_info & EXT_CH_RADAR_FOUND) { 270 dur = pulse_length_ext; 271 pri_found = 0; 272 ext_found = 1; 273 dfs->wlan_dfs_stats.ext_phy_errors++; 274 } 275 if (pulse_bw_info & PRI_CH_RADAR_FOUND) { 276 dur = pulse_length_pri; 277 pri_found = 1; 278 ext_found = 0; 279 dfs->wlan_dfs_stats.pri_phy_errors++; 280 } 281 if (pulse_bw_info & EXT_CH_RADAR_EARLY_FOUND) { 282 dur = pulse_length_ext; 283 pri_found = 0; 284 ext_found = 1; 285 early_ext = 1; 286 dfs->wlan_dfs_stats.early_ext_phy_errors++; 287 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR, 288 "EARLY ext channel dur=%u rssi=%u datalen=%d", 289 dur, rssi, datalen); 290 } 291 if (!pulse_bw_info) { 292 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR, 293 "ERROR channel dur=%u rssi=%u pulse_bw_info=0x%x datalen MOD 4 = %d", 294 dur, rssi, pulse_bw_info, (datalen & 0x3)); 295 /* 296 * Bogus bandwidth info received in descriptor, so 297 * ignore this PHY error. 298 */ 299 dfs->wlan_dfs_stats.bwinfo_errors++; 300 return 0; 301 } 302 } 303 304 /* 305 * Always use combined RSSI reported, unless RSSI reported on 306 * extension is stronger. 307 */ 308 if ((ext_rssi > rssi) && (ext_rssi < 128)) 309 rssi = ext_rssi; 310 311 /* Fill out the rssi/duration fields from above. */ 312 qdf_mem_zero(e, sizeof(*e)); 313 e->rssi = rssi; 314 e->dur = dur; 315 e->is_pri = pri_found; 316 e->is_ext = ext_found; 317 e->is_dc = !!(((pulse_bw_info & EXT_CH_RADAR_FOUND) && 318 (pulse_bw_info & PRI_CH_RADAR_FOUND))); 319 e->is_early = early_ext; 320 e->fulltsf = fulltsf; 321 e->rs_tstamp = rs_tstamp; 322 323 /* Sowl and later can report pri/ext events. */ 324 event_width = dfs_get_event_freqwidth(dfs); 325 e->freq = dfs_get_event_freqcentre(dfs, e->is_pri, e->is_ext, 326 e->is_dc) * 1000; 327 e->freq_lo = e->freq - (event_width / 2) * 1000; 328 e->freq_hi = e->freq + (event_width / 2) * 1000; 329 330 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR_SUM, 331 "pulse_bw_info=0x%x pulse_length_ext=%u pulse_length_pri=%u rssi=%u ext_rssi=%u, freq=%d MHz, freq_lo=%d MHz, freq_hi=%d MHz", 332 pulse_bw_info, pulse_length_ext, pulse_length_pri, 333 rssi, ext_rssi, e->freq/1000, e->freq_lo/1000, e->freq_hi/1000); 334 #undef EXT_CH_RADAR_FOUND 335 #undef PRI_CH_RADAR_FOUND 336 #undef EXT_CH_RADAR_EARLY_FOUND 337 338 return 1; 339 } 340 341 /** 342 * dfs_process_phyerr_merlin() - Process a Merlin/Osprey style phy error. 343 * dfs_phy_err struct. 344 * @dfs: Pointer to wlan_dfs structure. 345 * @buf: Phyerr buffer 346 * @datalen: Phyerr buf len 347 * @rssi: RSSI 348 * @ext_rssi: Extension RSSI. 349 * @rs_tstamp: Time stamp. 350 * @fulltsf: TSF64. 351 * @e: Pointer to dfs_phy_err structure. 352 * 353 * Return: Returns 1. 354 */ 355 static int dfs_process_phyerr_merlin(struct wlan_dfs *dfs, 356 void *buf, 357 uint16_t datalen, 358 uint8_t rssi, 359 uint8_t ext_rssi, 360 uint32_t rs_tstamp, 361 uint64_t fulltsf, 362 struct dfs_phy_err *e) 363 { 364 const char *cbuf = (const char *) buf; 365 uint8_t pulse_bw_info = 0; 366 367 /* Process using the sowl code. */ 368 if (!dfs_process_phyerr_sowl(dfs, buf, datalen, rssi, ext_rssi, 369 rs_tstamp, fulltsf, e)) { 370 return 0; 371 } 372 373 /* 374 * For osprey (and Merlin) bw_info has implication for selecting RSSI 375 * value. So re-fetch the bw_info field so the RSSI values can be 376 * appropriately overridden. 377 */ 378 pulse_bw_info = cbuf[datalen - 1]; 379 380 switch (pulse_bw_info & 0x03) { 381 case 0x00: 382 /* No radar in ctrl or ext channel */ 383 rssi = 0; 384 break; 385 case 0x01: 386 /* Radar in ctrl channel */ 387 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR, 388 "RAW RSSI: rssi=%u ext_rssi=%u", rssi, ext_rssi); 389 if (ext_rssi >= (rssi + 3)) { 390 /* 391 * Cannot use ctrl channel RSSI if extension channel is 392 * stronger. 393 */ 394 rssi = 0; 395 } 396 break; 397 case 0x02: 398 /* Radar in extension channel */ 399 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR, 400 "RAW RSSI: rssi=%u ext_rssi=%u", rssi, ext_rssi); 401 if (rssi >= (ext_rssi + 12)) { 402 /* 403 * Cannot use extension channel RSSI if control channel 404 * is stronger 405 */ 406 rssi = 0; 407 } else { 408 rssi = ext_rssi; 409 } 410 break; 411 case 0x03: 412 /* When both are present use stronger one */ 413 if (rssi < ext_rssi) 414 rssi = ext_rssi; 415 break; 416 } 417 418 /* 419 * Override the rssi decision made by the sowl code. The rest of the 420 * fields (duration, timestamp, etc) are left untouched. 421 */ 422 e->rssi = rssi; 423 424 return 1; 425 } 426 427 /** 428 * dfs_dump_phyerr_contents() - Dump the phyerr contents. 429 * @d: Phyerr buffer. 430 * @len: Phyerr buf length. 431 */ 432 433 static void dfs_dump_phyerr_contents(const char *d, int len) 434 { 435 int i, n, bufsize = 64; 436 437 /* 438 * This is statically sized for a 4-digit address + 16 * 2 digit data 439 * string. It's done so the printk() passed to the kernel is an entire 440 * line, so the kernel logging code will atomically print it. Otherwise 441 * we'll end up with interleaved lines with output from other kernel 442 * threads. 443 */ 444 char buf[64]; 445 446 /* Initial conditions */ 447 buf[0] = '\n'; 448 n = 0; 449 450 for (i = 0; i < len; i++) { 451 if (i % 16 == 0) 452 n += snprintf(buf + n, bufsize - n, "%04x: ", i); 453 454 n += snprintf(buf + n, bufsize - n, "%02x ", d[i] & 0xff); 455 if (i % 16 == 15) { 456 dfs_debug(NULL, WLAN_DEBUG_DFS_ALWAYS, "%s", buf); 457 n = 0; 458 buf[0] = '\0'; 459 } 460 } 461 462 /* Print the final line if we didn't print it above. */ 463 if (n != 0) 464 dfs_debug(NULL, WLAN_DEBUG_DFS_ALWAYS, "%s", buf); 465 } 466 467 /** 468 * dfs_bump_up_bin5_pulse_dur() - Bump up to a random BIN 5 pulse duration. 469 * @dfs: Pointer to wlan_dfs structure. 470 * @e: Pointer to dfs_phy_err structure. 471 * @slope: Slope value. 472 */ 473 static inline void dfs_bump_up_bin5_pulse_dur( 474 struct wlan_dfs *dfs, 475 struct dfs_phy_err *e, 476 int slope) 477 { 478 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR, "old dur %d slope =%d", 479 e->dur, slope); 480 481 e->is_sw_chirp = 1; 482 /* bump up to a random bin5 pulse duration */ 483 if (e->dur < MIN_BIN5_DUR) 484 e->dur = dfs_get_random_bin5_dur(dfs, e->fulltsf); 485 486 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR, "new dur %d", e->dur); 487 } 488 489 /** 490 * dfs_filter_short_pulses() - Filter short pulses. 491 * @dfs: Pointer to wlan_dfs structure. 492 * @e: Pointer to dfs_phy_err structure. 493 * @retval: Return value 494 * 495 * Rssi is not accurate for short pulses, so donot filter based on that for 496 * short duration pulses. 497 */ 498 static inline void dfs_filter_short_pulses( 499 struct wlan_dfs *dfs, 500 struct dfs_phy_err *e, 501 int *retval) 502 { 503 if (dfs->dfs_caps.wlan_dfs_ext_chan_ok) { 504 if ((e->rssi < dfs->dfs_rinfo.rn_minrssithresh && 505 (e->dur > MAX_DUR_FOR_LOW_RSSI)) || 506 e->dur > (dfs->dfs_rinfo.rn_maxpulsedur)) { 507 dfs->wlan_dfs_stats.rssi_discards++; 508 *retval = 1; 509 } 510 } else if (e->rssi < dfs->dfs_rinfo.rn_minrssithresh || 511 e->dur > dfs->dfs_rinfo.rn_maxpulsedur) { 512 dfs->wlan_dfs_stats.rssi_discards++; 513 *retval = 1; 514 } 515 516 if (*retval) { 517 dfs_debug(dfs, WLAN_DEBUG_DFS1, 518 "%s pulse is discarded: dur=%d, maxpulsedur=%d, rssi=%d, minrssi=%d", 519 (dfs->dfs_caps.wlan_dfs_ext_chan_ok) ? 520 "Extension channel" : "", 521 e->dur, dfs->dfs_rinfo.rn_maxpulsedur, 522 e->rssi, dfs->dfs_rinfo.rn_minrssithresh); 523 } 524 } 525 526 /** 527 * dfs_set_chan_index() - Set channel index. 528 * @dfs: Pointer to wlan_dfs structure. 529 * @e: Pointer to dfs_phy_err structure. 530 * @event: Pointer to dfs_event structure. 531 */ 532 static inline void dfs_set_chan_index( 533 struct wlan_dfs *dfs, 534 struct dfs_phy_err *e, 535 struct dfs_event *event) 536 { 537 if (e->is_pri) { 538 event->re_chanindex = dfs->dfs_curchan_radindex; 539 } else { 540 event->re_chanindex = dfs->dfs_extchan_radindex; 541 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR, 542 "%s New extension channel event is added to queue", 543 (event->re_chanindex == -1) ? 544 "- phyerr on ext channel" : ""); 545 } 546 } 547 548 /** 549 * dfs_is_second_seg_radar_disabled() - Check for second segment radar disabled. 550 * @dfs: Pointer to wlan_dfs structure. 551 * @seg_id: Segment id. 552 * 553 * Return: true if the second segment RADAR is enabled else false. 554 */ 555 static bool dfs_is_second_seg_radar_disabled( 556 struct wlan_dfs *dfs, int seg_id) 557 { 558 if ((seg_id == SEG_ID_SECONDARY) && 559 !(dfs->dfs_proc_phyerr & DFS_SECOND_SEGMENT_RADAR_EN)) { 560 dfs_debug(dfs, WLAN_DEBUG_DFS3, 561 "Second segment radar detection is disabled"); 562 return true; 563 } 564 565 return false; 566 } 567 568 void dfs_process_phyerr(struct wlan_dfs *dfs, void *buf, uint16_t datalen, 569 uint8_t r_rssi, uint8_t r_ext_rssi, uint32_t r_rs_tstamp, 570 uint64_t r_fulltsf) 571 { 572 struct dfs_event *event; 573 struct dfs_phy_err e; 574 int empty; 575 576 if (!dfs) { 577 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL"); 578 return; 579 } 580 581 if (dfs->dfs_ignore_dfs) { 582 dfs_debug(dfs, WLAN_DEBUG_DFS1, "ignoring dfs"); 583 return; 584 } 585 586 /* 587 * EV 129487: If radar detection is disabled, do not process PHY error 588 * data. 589 */ 590 591 if (!(dfs->dfs_proc_phyerr & DFS_RADAR_EN)) { 592 dfs_debug(dfs, WLAN_DEBUG_DFS1, 593 "DFS_RADAR_EN not set in dfs->dfs_proc_phyerr"); 594 return; 595 } 596 597 /* 598 * The combined_rssi_ok support has been removed. This was only clear 599 * for Owl. 600 * XXX TODO: re-add this; it requires passing in the ctl/ext 601 * RSSI set from the RX status descriptor. 602 * XXX TODO : this may be done for us from the legacy phy error path in 603 * wlan_dev; please review that code. 604 */ 605 606 /* 607 * At this time we have a radar pulse that we need to examine and 608 * queue. But if dfs_process_radarevent already detected radar and set 609 * CHANNEL_INTERFERENCE flag then do not queue any more radar data. 610 * When we are in a new channel this flag will be clear and we will 611 * start queueing data for new channel. (EV74162) 612 */ 613 if (dfs->dfs_debug_mask & WLAN_DEBUG_DFS_PHYERR_PKT) 614 dfs_dump_phyerr_contents(buf, datalen); 615 616 if (WLAN_IS_CHAN_RADAR(dfs, dfs->dfs_curchan)) { 617 dfs_debug(dfs, WLAN_DEBUG_DFS1, 618 "Radar already found in the channel, do not queue radar data"); 619 return; 620 } 621 dfs->dfs_phyerr_count++; 622 dfs->wlan_dfs_stats.total_phy_errors++; 623 dfs_debug(dfs, WLAN_DEBUG_DFS2, "phyerr %d len %d", 624 dfs->wlan_dfs_stats.total_phy_errors, datalen); 625 626 /* 627 * Hardware stores this as 8 bit signed value. we will cap it at 0 if it 628 * is a negative number. 629 */ 630 if (r_rssi & 0x80) 631 r_rssi = 0; 632 633 if (r_ext_rssi & 0x80) 634 r_ext_rssi = 0; 635 636 qdf_mem_zero(&e, sizeof(e)); 637 638 /* 639 * This is a bit evil - instead of just passing in the chip version, the 640 * existing code uses a set of HAL capability bits to determine what is 641 * possible. 642 * The way I'm decoding it is thus: 643 * + DFS enhancement? Merlin or later 644 * + DFS extension channel? Sowl or later. (Howl?) 645 * + otherwise, Owl (and legacy.) 646 */ 647 if (dfs->dfs_caps.wlan_chip_is_bb_tlv) { 648 if (dfs_process_phyerr_bb_tlv(dfs, buf, datalen, r_rssi, 649 r_ext_rssi, r_rs_tstamp, r_fulltsf, &e) == 0) { 650 dfs->dfs_phyerr_reject_count++; 651 return; 652 } 653 654 if (dfs->dfs_phyerr_freq_min > e.freq) 655 dfs->dfs_phyerr_freq_min = e. freq; 656 657 if (dfs->dfs_phyerr_freq_max < e.freq) 658 dfs->dfs_phyerr_freq_max = e. freq; 659 } else if (dfs->dfs_caps.wlan_dfs_use_enhancement) { 660 if (dfs_process_phyerr_merlin(dfs, buf, datalen, r_rssi, 661 r_ext_rssi, r_rs_tstamp, r_fulltsf, &e) == 0) 662 return; 663 } else if (dfs->dfs_caps.wlan_dfs_ext_chan_ok) { 664 if (dfs_process_phyerr_sowl(dfs, buf, datalen, r_rssi, 665 r_ext_rssi, r_rs_tstamp, r_fulltsf, &e) == 0) 666 return; 667 } else { 668 if (dfs_process_phyerr_owl(dfs, buf, datalen, r_rssi, 669 r_ext_rssi, r_rs_tstamp, r_fulltsf, &e) == 0) 670 return; 671 } 672 673 /* 674 * If the hardware supports radar reporting on the extension channel 675 * it will supply FFT data for longer radar pulses. 676 * TLV chips don't go through this software check - the hardware 677 * check should be enough. If we want to do software checking 678 * later on then someone will have to craft an FFT parser 679 * suitable for the TLV FFT data format. 680 */ 681 if ((!dfs->dfs_caps.wlan_chip_is_bb_tlv) && 682 dfs->dfs_caps.wlan_dfs_ext_chan_ok) { 683 /* 684 * HW has a known issue with chirping pulses injected at or 685 * around DC in 40MHz mode. Such pulses are reported with much 686 * lower durations and SW then discards them because they do 687 * not fit the minimum bin5 pulse duration. To work around this 688 * issue, if a pulse is within a 10us range of the bin5 min 689 * duration, check if the pulse is chirping. If the pulse is 690 * chirping, bump up the duration to the minimum bin5 duration. 691 * This makes sure that a valid chirping pulse will not be 692 * discarded because of incorrect low duration. TBD - Is it 693 * possible to calculate the 'real' duration of the pulse using 694 * the slope of the FFT data? TBD - Use FFT data to 695 * differentiate between radar pulses and false PHY errors. 696 * This will let us reduce the number of false alarms seen. 697 * BIN 5 chirping pulses are only for FCC or Japan MMK4 domain 698 */ 699 if (((dfs->dfsdomain == DFS_FCC_DOMAIN) || 700 (dfs->dfsdomain == DFS_MKK4_DOMAIN) || 701 (dfs->dfsdomain == DFS_MKKN_DOMAIN)) && 702 (e.dur >= MAYBE_BIN5_DUR) && (e.dur < MAX_BIN5_DUR)) { 703 int add_dur; 704 int slope = 0, dc_found = 0; 705 706 /* 707 * Set the event chirping flags; as we're doing an 708 * actual chirp check. 709 */ 710 e.do_check_chirp = 1; 711 e.is_hw_chirp = 0; 712 e.is_sw_chirp = 0; 713 714 /* 715 * dfs_check_chirping() expects is_pri and is_ext to 716 * be '1' for true and '0' for false for now, as the 717 * function itself uses these values in constructing 718 * things rather than testing them 719 */ 720 add_dur = dfs_check_chirping(dfs, buf, datalen, 721 (e.is_pri ? 1 : 0), 722 (e.is_ext ? 1 : 0), &slope, &dc_found); 723 if (add_dur) { 724 dfs_bump_up_bin5_pulse_dur(dfs, &e, slope); 725 } else { 726 /* Set the duration so that it is rejected. */ 727 e.is_sw_chirp = 0; 728 e.dur = MAX_BIN5_DUR + 100; 729 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR, 730 "is_chirping = %d dur=%d", 731 add_dur, e.dur); 732 } 733 } else { 734 /* 735 * We have a pulse that is either bigger than 736 * MAX_BIN5_DUR or less than MAYBE_BIN5_DUR 737 */ 738 if ((dfs->dfsdomain == DFS_FCC_DOMAIN) || 739 (dfs->dfsdomain == DFS_MKK4_DOMAIN) || 740 (dfs->dfsdomain == DFS_MKKN_DOMAIN)) { 741 /* 742 * Would this result in very large pulses 743 * wrapping around to become short pulses? 744 */ 745 if (e.dur >= MAX_BIN5_DUR) { 746 /* 747 * Set the duration so that it is 748 * rejected. 749 */ 750 e.dur = MAX_BIN5_DUR + 50; 751 } 752 } 753 } 754 } 755 756 /* 757 * Add the parsed, checked and filtered entry to the radar pulse 758 * event list. This is then checked by dfs_radar_processevent(). 759 * 760 * XXX TODO: some filtering is still done below this point - fix this! 761 */ 762 WLAN_DFSEVENTQ_LOCK(dfs); 763 empty = STAILQ_EMPTY(&(dfs->dfs_eventq)); 764 WLAN_DFSEVENTQ_UNLOCK(dfs); 765 if (empty) 766 return; 767 768 /* 769 * If the channel is a turbo G channel, then the event is for the 770 * adaptive radio (AR) pattern matching rather than radar detection. 771 */ 772 if (WLAN_IS_CHAN_108G(dfs->dfs_curchan)) { 773 if (!(dfs->dfs_proc_phyerr & DFS_AR_EN)) { 774 dfs_debug(dfs, WLAN_DEBUG_DFS2, 775 "DFS_AR_EN not enabled"); 776 return; 777 } 778 WLAN_DFSEVENTQ_LOCK(dfs); 779 event = STAILQ_FIRST(&(dfs->dfs_eventq)); 780 if (!event) { 781 WLAN_DFSEVENTQ_UNLOCK(dfs); 782 dfs_debug(dfs, WLAN_DEBUG_DFS, 783 "no more events space left"); 784 return; 785 } 786 STAILQ_REMOVE_HEAD(&(dfs->dfs_eventq), re_list); 787 WLAN_DFSEVENTQ_UNLOCK(dfs); 788 event->re_rssi = e.rssi; 789 event->re_dur = e.dur; 790 event->re_full_ts = e.fulltsf; 791 event->re_ts = (e.rs_tstamp) & DFS_TSMASK; 792 event->re_chanindex = dfs->dfs_curchan_radindex; 793 event->re_flags = 0; 794 795 /* Handle chirp flags. */ 796 if (e.do_check_chirp) { 797 event->re_flags |= DFS_EVENT_CHECKCHIRP; 798 if (e.is_hw_chirp) 799 event->re_flags |= DFS_EVENT_HW_CHIRP; 800 if (e.is_sw_chirp) 801 event->re_flags |= DFS_EVENT_SW_CHIRP; 802 } 803 804 WLAN_ARQ_LOCK(dfs); 805 STAILQ_INSERT_TAIL(&(dfs->dfs_arq), event, re_list); 806 WLAN_ARQ_UNLOCK(dfs); 807 } else { 808 if ((WLAN_IS_CHAN_DFS(dfs->dfs_curchan) || 809 ((WLAN_IS_CHAN_11AC_VHT160(dfs->dfs_curchan) || 810 WLAN_IS_CHAN_11AC_VHT80_80(dfs->dfs_curchan)) && 811 WLAN_IS_CHAN_DFS_CFREQ2(dfs->dfs_curchan))) || 812 (dfs_is_precac_timer_running(dfs))) { 813 814 int retval = 0; 815 816 if (!(dfs->dfs_proc_phyerr & DFS_RADAR_EN)) { 817 dfs_debug(dfs, WLAN_DEBUG_DFS3, 818 "DFS_RADAR_EN not enabled"); 819 return; 820 } 821 822 dfs_filter_short_pulses(dfs, &e, &retval); 823 if (retval) 824 return; 825 826 if (dfs_is_second_seg_radar_disabled(dfs, e.seg_id)) 827 return; 828 829 /* Add the event to the list, if there's space. */ 830 WLAN_DFSEVENTQ_LOCK(dfs); 831 event = STAILQ_FIRST(&(dfs->dfs_eventq)); 832 if (!event) { 833 WLAN_DFSEVENTQ_UNLOCK(dfs); 834 dfs_debug(dfs, WLAN_DEBUG_DFS, 835 "no more events space left"); 836 return; 837 } 838 STAILQ_REMOVE_HEAD(&(dfs->dfs_eventq), re_list); 839 WLAN_DFSEVENTQ_UNLOCK(dfs); 840 841 dfs->dfs_phyerr_queued_count++; 842 dfs->dfs_phyerr_w53_counter++; 843 844 event->re_dur = e.dur; 845 event->re_full_ts = e.fulltsf; 846 event->re_ts = (e.rs_tstamp) & DFS_TSMASK; 847 event->re_rssi = e.rssi; 848 849 event->re_seg_id = e.seg_id; 850 event->re_sidx = e.sidx; 851 event->re_freq_offset_khz = e.freq_offset_khz; 852 event->re_peak_mag = e.peak_mag; 853 event->re_total_gain = e.total_gain; 854 event->re_mb_gain = e.mb_gain; 855 event->re_relpwr_db = e.relpwr_db; 856 event->re_delta_diff = e.pulse_delta_diff; 857 event->re_delta_peak = e.pulse_delta_peak; 858 event->re_psidx_diff = e.pulse_psidx_diff; 859 event->re_flags = 0; 860 event->re_flags |= DFS_EVENT_VALID_PSIDX_DIFF; 861 /* Handle chirp flags. */ 862 if (e.do_check_chirp) { 863 event->re_flags |= DFS_EVENT_CHECKCHIRP; 864 if (e.is_hw_chirp) 865 event->re_flags |= DFS_EVENT_HW_CHIRP; 866 if (e.is_sw_chirp) 867 event->re_flags |= DFS_EVENT_SW_CHIRP; 868 } 869 870 /* Correctly set which channel is being reported on */ 871 dfs_set_chan_index(dfs, &e, event); 872 873 WLAN_DFSQ_LOCK(dfs); 874 STAILQ_INSERT_TAIL(&(dfs->dfs_radarq), event, re_list); 875 WLAN_DFSQ_UNLOCK(dfs); 876 } 877 } 878 879 /* 880 * Schedule the radar/AR task as appropriate. 881 * XXX isn't a lock needed for wlan_radar_tasksched? 882 */ 883 if (!STAILQ_EMPTY(&dfs->dfs_arq)) { 884 /* XXX shouldn't this be a task/timer too? */ 885 dfs_process_ar_event(dfs, dfs->dfs_curchan); 886 } 887 if (!STAILQ_EMPTY(&dfs->dfs_radarq) && !dfs->wlan_radar_tasksched) { 888 dfs->wlan_radar_tasksched = 1; 889 qdf_timer_mod(&dfs->wlan_dfs_task_timer, 0); 890 } 891 #undef EXT_CH_RADAR_FOUND 892 #undef PRI_CH_RADAR_FOUND 893 #undef EXT_CH_RADAR_EARLY_FOUND 894 } 895 #endif /* WLAN_DFS_PARTIAL_OFFLOAD */ 896 897 #ifdef MOBILE_DFS_SUPPORT 898 void dfs_process_phyerr_filter_offload(struct wlan_dfs *dfs, 899 struct radar_event_info *wlan_radar_event) 900 { 901 struct dfs_event *event; 902 int empty; 903 int do_check_chirp = 0; 904 int is_hw_chirp = 0; 905 int is_sw_chirp = 0; 906 int is_pri = 0; 907 908 if (!dfs) { 909 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL"); 910 return; 911 } 912 913 if (dfs->dfs_ignore_dfs) { 914 dfs_debug(dfs, WLAN_DEBUG_DFS1, "ignoring dfs"); 915 return; 916 } 917 918 if (!(dfs->dfs_proc_phyerr & DFS_RADAR_EN)) { 919 dfs_debug(dfs, WLAN_DEBUG_DFS1, 920 "DFS_RADAR_EN not set in dfs->dfs_proc_phyerr"); 921 return; 922 } 923 924 if (WLAN_IS_CHAN_RADAR(dfs, dfs->dfs_curchan)) { 925 dfs_debug(dfs, WLAN_DEBUG_DFS1, 926 "Radar already found in the channel, do not queue radar data"); 927 return; 928 } 929 930 dfs->wlan_dfs_stats.total_phy_errors++; 931 if (dfs->dfs_caps.wlan_chip_is_bb_tlv) { 932 do_check_chirp = 1; 933 is_pri = 1; 934 is_hw_chirp = wlan_radar_event->pulse_is_chirp; 935 936 if ((uint32_t) dfs->dfs_phyerr_freq_min > 937 wlan_radar_event->pulse_center_freq) { 938 dfs->dfs_phyerr_freq_min = 939 (int)wlan_radar_event->pulse_center_freq; 940 } 941 942 if (dfs->dfs_phyerr_freq_max < 943 (int)wlan_radar_event->pulse_center_freq) { 944 dfs->dfs_phyerr_freq_max = 945 (int)wlan_radar_event->pulse_center_freq; 946 } 947 } 948 949 /* 950 * Now, add the parsed, checked and filtered 951 * radar phyerror event radar pulse event list. 952 * This event will then be processed by 953 * dfs_radar_processevent() to see if the pattern 954 * of pulses in radar pulse list match any radar 955 * singnature in the current regulatory domain. 956 */ 957 958 WLAN_DFSEVENTQ_LOCK(dfs); 959 empty = STAILQ_EMPTY(&(dfs->dfs_eventq)); 960 WLAN_DFSEVENTQ_UNLOCK(dfs); 961 if (empty) 962 return; 963 /* 964 * Add the event to the list, if there's space. 965 */ 966 WLAN_DFSEVENTQ_LOCK(dfs); 967 event = STAILQ_FIRST(&(dfs->dfs_eventq)); 968 if (!event) { 969 WLAN_DFSEVENTQ_UNLOCK(dfs); 970 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, 971 "No more space left for queuing DFS Phyerror events"); 972 return; 973 } 974 STAILQ_REMOVE_HEAD(&(dfs->dfs_eventq), re_list); 975 WLAN_DFSEVENTQ_UNLOCK(dfs); 976 dfs->dfs_phyerr_queued_count++; 977 dfs->dfs_phyerr_w53_counter++; 978 event->re_dur = (uint8_t) wlan_radar_event->pulse_duration; 979 event->re_rssi = wlan_radar_event->rssi; 980 event->re_ts = wlan_radar_event->pulse_detect_ts & DFS_TSMASK; 981 event->re_full_ts = (((uint64_t) wlan_radar_event->upload_fullts_high) 982 << 32) | wlan_radar_event->upload_fullts_low; 983 984 /* 985 * Index of peak magnitude 986 */ 987 event->re_sidx = wlan_radar_event->peak_sidx; 988 event->re_delta_diff = wlan_radar_event->delta_diff; 989 event->re_delta_peak = wlan_radar_event->delta_peak; 990 event->re_flags = 0; 991 if (wlan_radar_event->is_psidx_diff_valid) { 992 event->re_flags |= DFS_EVENT_VALID_PSIDX_DIFF; 993 event->re_psidx_diff = wlan_radar_event->psidx_diff; 994 } 995 996 /* 997 * Handle chirp flags. 998 */ 999 if (do_check_chirp) { 1000 event->re_flags |= DFS_EVENT_CHECKCHIRP; 1001 if (is_hw_chirp) 1002 event->re_flags |= DFS_EVENT_HW_CHIRP; 1003 if (is_sw_chirp) 1004 event->re_flags |= DFS_EVENT_SW_CHIRP; 1005 } 1006 /* 1007 * Correctly set which channel is being reported on 1008 */ 1009 if (is_pri) { 1010 event->re_chanindex = (uint8_t) dfs->dfs_curchan_radindex; 1011 } else { 1012 if (dfs->dfs_extchan_radindex == -1) 1013 dfs_debug(dfs, WLAN_DEBUG_DFS1, 1014 "phyerr on ext channel"); 1015 event->re_chanindex = (uint8_t) dfs->dfs_extchan_radindex; 1016 dfs_debug(dfs, WLAN_DEBUG_DFS1, 1017 "New extension channel event is added to queue"); 1018 } 1019 1020 WLAN_DFSQ_LOCK(dfs); 1021 1022 STAILQ_INSERT_TAIL(&(dfs->dfs_radarq), event, re_list); 1023 1024 empty = STAILQ_EMPTY(&dfs->dfs_radarq); 1025 1026 WLAN_DFSQ_UNLOCK(dfs); 1027 1028 if (!empty && !dfs->wlan_radar_tasksched) { 1029 dfs->wlan_radar_tasksched = 1; 1030 qdf_timer_mod(&dfs->wlan_dfs_task_timer, 0); 1031 } 1032 } 1033 #endif 1034 1035 void dfs_is_radar_enabled(struct wlan_dfs *dfs, int *ignore_dfs) 1036 { 1037 *ignore_dfs = dfs->dfs_ignore_dfs; 1038 } 1039