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