1 /* 2 * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2002-2010, Atheros Communications Inc. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /** 19 * DOC: 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_set(e, sizeof(*e), 0); 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_set(e, sizeof(*e), 0); 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 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_set(&e, sizeof(e), 0); 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 (e.dur >= MAYBE_BIN5_DUR) && (e.dur < MAX_BIN5_DUR)) { 660 int add_dur; 661 int slope = 0, dc_found = 0; 662 663 /* 664 * Set the event chirping flags; as we're doing an 665 * actual chirp check. 666 */ 667 e.do_check_chirp = 1; 668 e.is_hw_chirp = 0; 669 e.is_sw_chirp = 0; 670 671 /* 672 * dfs_check_chirping() expects is_pri and is_ext to 673 * be '1' for true and '0' for false for now, as the 674 * function itself uses these values in constructing 675 * things rather than testing them 676 */ 677 add_dur = dfs_check_chirping(dfs, buf, datalen, 678 (e.is_pri ? 1 : 0), 679 (e.is_ext ? 1 : 0), &slope, &dc_found); 680 if (add_dur) { 681 dfs_bump_up_bin5_pulse_dur(dfs, &e, slope); 682 } else { 683 /* Set the duration so that it is rejected. */ 684 e.is_sw_chirp = 0; 685 e.dur = MAX_BIN5_DUR + 100; 686 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR, 687 "is_chirping = %d dur=%d", 688 add_dur, e.dur); 689 } 690 } else { 691 /* 692 * We have a pulse that is either bigger than 693 * MAX_BIN5_DUR or less than MAYBE_BIN5_DUR 694 */ 695 if ((dfs->dfsdomain == DFS_FCC_DOMAIN) || 696 (dfs->dfsdomain == DFS_MKK4_DOMAIN)) { 697 /* 698 * Would this result in very large pulses 699 * wrapping around to become short pulses? 700 */ 701 if (e.dur >= MAX_BIN5_DUR) { 702 /* 703 * Set the duration so that it is 704 * rejected. 705 */ 706 e.dur = MAX_BIN5_DUR + 50; 707 } 708 } 709 } 710 } 711 712 /* 713 * Add the parsed, checked and filtered entry to the radar pulse 714 * event list. This is then checked by dfs_radar_processevent(). 715 * 716 * XXX TODO: some filtering is still done below this point - fix this! 717 */ 718 WLAN_DFSEVENTQ_LOCK(dfs); 719 empty = STAILQ_EMPTY(&(dfs->dfs_eventq)); 720 WLAN_DFSEVENTQ_UNLOCK(dfs); 721 if (empty) 722 return; 723 724 /* 725 * If the channel is a turbo G channel, then the event is for the 726 * adaptive radio (AR) pattern matching rather than radar detection. 727 */ 728 if ((dfs->dfs_curchan->dfs_ch_flags & CHANNEL_108G) == CHANNEL_108G) { 729 if (!(dfs->dfs_proc_phyerr & DFS_AR_EN)) { 730 dfs_debug(dfs, WLAN_DEBUG_DFS2, 731 "DFS_AR_EN not enabled"); 732 return; 733 } 734 WLAN_DFSEVENTQ_LOCK(dfs); 735 event = STAILQ_FIRST(&(dfs->dfs_eventq)); 736 if (!event) { 737 WLAN_DFSEVENTQ_UNLOCK(dfs); 738 dfs_debug(dfs, WLAN_DEBUG_DFS, 739 "no more events space left"); 740 return; 741 } 742 STAILQ_REMOVE_HEAD(&(dfs->dfs_eventq), re_list); 743 WLAN_DFSEVENTQ_UNLOCK(dfs); 744 event->re_rssi = e.rssi; 745 event->re_dur = e.dur; 746 event->re_full_ts = e.fulltsf; 747 event->re_ts = (e.rs_tstamp) & DFS_TSMASK; 748 event->re_chanindex = dfs->dfs_curchan_radindex; 749 event->re_flags = 0; 750 751 /* Handle chirp flags. */ 752 if (e.do_check_chirp) { 753 event->re_flags |= DFS_EVENT_CHECKCHIRP; 754 if (e.is_hw_chirp) 755 event->re_flags |= DFS_EVENT_HW_CHIRP; 756 if (e.is_sw_chirp) 757 event->re_flags |= DFS_EVENT_SW_CHIRP; 758 } 759 760 WLAN_ARQ_LOCK(dfs); 761 STAILQ_INSERT_TAIL(&(dfs->dfs_arq), event, re_list); 762 WLAN_ARQ_UNLOCK(dfs); 763 } else { 764 if ((WLAN_IS_CHAN_DFS(dfs->dfs_curchan) || 765 ((WLAN_IS_CHAN_11AC_VHT160(dfs->dfs_curchan) || 766 WLAN_IS_CHAN_11AC_VHT80_80(dfs->dfs_curchan)) && 767 WLAN_IS_CHAN_DFS_CFREQ2(dfs->dfs_curchan))) || 768 (dfs_is_precac_timer_running(dfs))) { 769 770 int retval = 0; 771 772 if (!(dfs->dfs_proc_phyerr & DFS_RADAR_EN)) { 773 dfs_debug(dfs, WLAN_DEBUG_DFS3, 774 "DFS_RADAR_EN not enabled"); 775 return; 776 } 777 778 dfs_filter_short_pulses(dfs, &e, &retval); 779 if (retval) 780 return; 781 782 if (dfs_is_second_seg_radar_disabled(dfs, e.seg_id)) 783 return; 784 785 /* Add the event to the list, if there's space. */ 786 WLAN_DFSEVENTQ_LOCK(dfs); 787 event = STAILQ_FIRST(&(dfs->dfs_eventq)); 788 if (!event) { 789 WLAN_DFSEVENTQ_UNLOCK(dfs); 790 dfs_debug(dfs, WLAN_DEBUG_DFS, 791 "no more events space left"); 792 return; 793 } 794 STAILQ_REMOVE_HEAD(&(dfs->dfs_eventq), re_list); 795 WLAN_DFSEVENTQ_UNLOCK(dfs); 796 797 dfs->dfs_phyerr_queued_count++; 798 dfs->dfs_phyerr_w53_counter++; 799 800 event->re_dur = e.dur; 801 event->re_full_ts = e.fulltsf; 802 event->re_ts = (e.rs_tstamp) & DFS_TSMASK; 803 event->re_rssi = e.rssi; 804 805 event->re_seg_id = e.seg_id; 806 event->re_sidx = e.sidx; 807 event->re_freq_offset_khz = e.freq_offset_khz; 808 event->re_peak_mag = e.peak_mag; 809 event->re_total_gain = e.total_gain; 810 event->re_mb_gain = e.mb_gain; 811 event->re_relpwr_db = e.relpwr_db; 812 event->re_delta_diff = e.pulse_delta_diff; 813 event->re_delta_peak = e.pulse_delta_peak; 814 event->re_psidx_diff = e.pulse_psidx_diff; 815 event->re_flags = 0; 816 event->re_flags |= DFS_EVENT_VALID_PSIDX_DIFF; 817 /* Handle chirp flags. */ 818 if (e.do_check_chirp) { 819 event->re_flags |= DFS_EVENT_CHECKCHIRP; 820 if (e.is_hw_chirp) 821 event->re_flags |= DFS_EVENT_HW_CHIRP; 822 if (e.is_sw_chirp) 823 event->re_flags |= DFS_EVENT_SW_CHIRP; 824 } 825 826 /* Correctly set which channel is being reported on */ 827 dfs_set_chan_index(dfs, &e, event); 828 829 WLAN_DFSQ_LOCK(dfs); 830 STAILQ_INSERT_TAIL(&(dfs->dfs_radarq), event, re_list); 831 WLAN_DFSQ_UNLOCK(dfs); 832 } 833 } 834 835 /* 836 * Schedule the radar/AR task as appropriate. 837 * XXX isn't a lock needed for wlan_radar_tasksched? 838 */ 839 if (!STAILQ_EMPTY(&dfs->dfs_arq)) { 840 /* XXX shouldn't this be a task/timer too? */ 841 dfs_process_ar_event(dfs, dfs->dfs_curchan); 842 } 843 if (!STAILQ_EMPTY(&dfs->dfs_radarq) && !dfs->wlan_radar_tasksched) { 844 dfs->wlan_radar_tasksched = 1; 845 qdf_timer_mod(&dfs->wlan_dfs_task_timer, 0); 846 } 847 #undef EXT_CH_RADAR_FOUND 848 #undef PRI_CH_RADAR_FOUND 849 #undef EXT_CH_RADAR_EARLY_FOUND 850 } 851 852 #ifdef QCA_MCL_DFS_SUPPORT 853 void dfs_process_phyerr_filter_offload(struct wlan_dfs *dfs, 854 struct radar_event_info *wlan_radar_event) 855 { 856 struct dfs_event *event; 857 int empty; 858 int do_check_chirp = 0; 859 int is_hw_chirp = 0; 860 int is_sw_chirp = 0; 861 int is_pri = 0; 862 863 if (!dfs) { 864 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL"); 865 return; 866 } 867 868 if (dfs->dfs_ignore_dfs) { 869 dfs_debug(dfs, WLAN_DEBUG_DFS1, "ignoring dfs"); 870 return; 871 } 872 873 if (!(dfs->dfs_proc_phyerr & DFS_RADAR_EN)) { 874 dfs_debug(dfs, WLAN_DEBUG_DFS1, 875 "DFS_RADAR_EN not set in dfs->dfs_proc_phyerr"); 876 return; 877 } 878 879 if (WLAN_IS_CHAN_RADAR(dfs->dfs_curchan)) { 880 dfs_debug(dfs, WLAN_DEBUG_DFS1, 881 "Radar already found in the channel, do not queue radar data"); 882 return; 883 } 884 885 dfs->wlan_dfs_stats.total_phy_errors++; 886 if (dfs->dfs_caps.wlan_chip_is_bb_tlv) { 887 do_check_chirp = 1; 888 is_pri = 1; 889 is_hw_chirp = wlan_radar_event->pulse_is_chirp; 890 891 if ((uint32_t) dfs->dfs_phyerr_freq_min > 892 wlan_radar_event->pulse_center_freq) { 893 dfs->dfs_phyerr_freq_min = 894 (int)wlan_radar_event->pulse_center_freq; 895 } 896 897 if (dfs->dfs_phyerr_freq_max < 898 (int)wlan_radar_event->pulse_center_freq) { 899 dfs->dfs_phyerr_freq_max = 900 (int)wlan_radar_event->pulse_center_freq; 901 } 902 } 903 904 /* 905 * Now, add the parsed, checked and filtered 906 * radar phyerror event radar pulse event list. 907 * This event will then be processed by 908 * dfs_radar_processevent() to see if the pattern 909 * of pulses in radar pulse list match any radar 910 * singnature in the current regulatory domain. 911 */ 912 913 WLAN_DFSEVENTQ_LOCK(dfs); 914 empty = STAILQ_EMPTY(&(dfs->dfs_eventq)); 915 WLAN_DFSEVENTQ_UNLOCK(dfs); 916 if (empty) 917 return; 918 /* 919 * Add the event to the list, if there's space. 920 */ 921 WLAN_DFSEVENTQ_LOCK(dfs); 922 event = STAILQ_FIRST(&(dfs->dfs_eventq)); 923 if (!event) { 924 WLAN_DFSEVENTQ_UNLOCK(dfs); 925 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, 926 "%s: No more space left for queuing DFS Phyerror events", 927 __func__); 928 return; 929 } 930 STAILQ_REMOVE_HEAD(&(dfs->dfs_eventq), re_list); 931 WLAN_DFSEVENTQ_UNLOCK(dfs); 932 dfs->dfs_phyerr_queued_count++; 933 dfs->dfs_phyerr_w53_counter++; 934 event->re_dur = (uint8_t) wlan_radar_event->pulse_duration; 935 event->re_rssi = wlan_radar_event->rssi; 936 event->re_ts = wlan_radar_event->pulse_detect_ts & DFS_TSMASK; 937 event->re_full_ts = (((uint64_t) wlan_radar_event->upload_fullts_high) 938 << 32) | wlan_radar_event->upload_fullts_low; 939 940 /* 941 * Index of peak magnitude 942 */ 943 event->re_sidx = wlan_radar_event->peak_sidx; 944 event->re_delta_diff = wlan_radar_event->delta_diff; 945 event->re_delta_peak = wlan_radar_event->delta_peak; 946 event->re_flags = 0; 947 if (wlan_radar_event->is_psidx_diff_valid) { 948 event->re_flags |= DFS_EVENT_VALID_PSIDX_DIFF; 949 event->re_psidx_diff = wlan_radar_event->psidx_diff; 950 } 951 952 /* 953 * Handle chirp flags. 954 */ 955 if (do_check_chirp) { 956 event->re_flags |= DFS_EVENT_CHECKCHIRP; 957 if (is_hw_chirp) 958 event->re_flags |= DFS_EVENT_HW_CHIRP; 959 if (is_sw_chirp) 960 event->re_flags |= DFS_EVENT_SW_CHIRP; 961 } 962 /* 963 * Correctly set which channel is being reported on 964 */ 965 if (is_pri) { 966 event->re_chanindex = (uint8_t) dfs->dfs_curchan_radindex; 967 } else { 968 if (dfs->dfs_extchan_radindex == -1) 969 dfs_debug(dfs, WLAN_DEBUG_DFS1, 970 "%s phyerr on ext channel", __func__); 971 event->re_chanindex = (uint8_t) dfs->dfs_extchan_radindex; 972 dfs_debug(dfs, WLAN_DEBUG_DFS1, 973 "%s:New extension channel event is added to queue", 974 __func__); 975 } 976 977 WLAN_DFSQ_LOCK(dfs); 978 979 STAILQ_INSERT_TAIL(&(dfs->dfs_radarq), event, re_list); 980 981 empty = STAILQ_EMPTY(&dfs->dfs_radarq); 982 983 WLAN_DFSQ_UNLOCK(dfs); 984 985 if (!empty && !dfs->wlan_radar_tasksched) { 986 dfs->wlan_radar_tasksched = 1; 987 qdf_timer_mod(&dfs->wlan_dfs_task_timer, 0); 988 } 989 } 990 #endif 991 992 void dfs_is_radar_enabled(struct wlan_dfs *dfs, int *ignore_dfs) 993 { 994 *ignore_dfs = dfs->dfs_ignore_dfs; 995 } 996