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