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_channel.h" 27 #include "wlan_dfs_mlme_api.h" 28 #include "../dfs_internal.h" 29 30 /** 31 * dfs_get_event_freqwidth() - Get frequency width. 32 * @dfs: Pointer to wlan_dfs structure. 33 * 34 * Return: Return the frequency width for the current operating channel. 35 * This isn't the channel width - it's how wide the reported event may be. 36 * For HT20 this is 20MHz. For HT40 on Howl and later it'll still be 20MHz 37 * - the hardware returns either pri or ext channel. 38 */ 39 static inline int dfs_get_event_freqwidth(struct wlan_dfs *dfs) 40 { 41 /* Handle edge cases during startup/transition, shouldn't happen! */ 42 if (!dfs) 43 return 0; 44 45 if (!dfs->dfs_curchan) 46 return 0; 47 48 /* 49 * For now, assume 20MHz wide - but this is incorrect when operating in 50 * half/quarter mode! 51 */ 52 return 20; 53 } 54 55 /** 56 * dfs_get_event_freqcentre() - Get event frequency centre. 57 * @dfs: Pointer to wlan_dfs structure. 58 * @is_pri: detected on primary channel. 59 * @is_ext: detected on extension channel. 60 * @is_dc: detected at DC. 61 * 62 * Return the centre frequency for the current operating channel and event. 63 * This is for post-Owl 11n chips which report pri/extension channel events. 64 */ 65 static inline uint16_t dfs_get_event_freqcentre(struct wlan_dfs *dfs, 66 int is_pri, 67 int is_ext, 68 int is_dc) 69 { 70 int chan_offset = 0, chan_width; 71 72 /* Handle edge cases during startup/transition, shouldn't happen! */ 73 if (!dfs) 74 return 0; 75 if (!dfs->dfs_curchan) 76 return 0; 77 78 /* 79 * For wide channels, DC and ext frequencies need a bit of hand-holding 80 * based on whether it's an upper or lower channel. 81 */ 82 chan_width = dfs_get_event_freqwidth(dfs); 83 84 if (WLAN_IS_CHAN_11N_HT40PLUS(dfs->dfs_curchan)) 85 chan_offset = chan_width; 86 else if (WLAN_IS_CHAN_11N_HT40MINUS(dfs->dfs_curchan)) 87 chan_offset = -chan_width; 88 else 89 chan_offset = 0; 90 91 /* 92 * Check for DC events first - the sowl code may just set all the bits 93 * together. 94 */ 95 if (is_dc) { 96 /* XXX TODO: Should DC events be considered 40MHz wide here? */ 97 return dfs_chan2freq( 98 dfs->dfs_curchan) + (chan_offset / 2); 99 } 100 101 /* 102 * For non-wide channels, the centre frequency is just dfs_ch_freq. 103 * The centre frequency for pri events is still dfs_ch_freq. 104 */ 105 if (is_pri) 106 return dfs_chan2freq(dfs->dfs_curchan); 107 108 if (is_ext) 109 return dfs_chan2freq(dfs->dfs_curchan) + chan_width; 110 111 return dfs_chan2freq(dfs->dfs_curchan); 112 } 113 114 int dfs_process_phyerr_owl(struct wlan_dfs *dfs, 115 void *buf, 116 uint16_t datalen, 117 uint8_t rssi, 118 uint8_t ext_rssi, 119 uint32_t rs_tstamp, 120 uint64_t fulltsf, 121 struct dfs_phy_err *e) 122 { 123 const char *cbuf = (const char *) buf; 124 uint8_t dur; 125 int event_width; 126 127 dfs->wlan_dfs_stats.owl_phy_errors++; 128 129 /* 130 * HW cannot detect extension channel radar so it only passes us primary 131 * channel radar data. 132 */ 133 if (datalen == 0) 134 dur = 0; 135 else 136 dur = ((uint8_t *) cbuf)[0]; 137 138 /* This is a spurious event; toss. */ 139 if (rssi == 0 && dur == 0) 140 dfs->wlan_dfs_stats.datalen_discards++; 141 return 0; 142 143 /* Fill out dfs_phy_err with the information we have at hand. */ 144 qdf_mem_set(e, sizeof(*e), 0); 145 e->rssi = rssi; 146 e->dur = dur; 147 e->is_pri = 1; 148 e->is_ext = 0; 149 e->is_dc = 0; 150 e->is_early = 1; 151 e->fulltsf = fulltsf; 152 e->rs_tstamp = rs_tstamp; 153 154 /* 155 * Owl only ever reports events on the primary channel. It doesn't 156 * even see events on the secondary channel. 157 */ 158 event_width = dfs_get_event_freqwidth(dfs); 159 e->freq = dfs_get_event_freqcentre(dfs, 1, 0, 0) * 1000; 160 e->freq_lo = e->freq - (event_width / 2) * 1000; 161 e->freq_hi = e->freq + (event_width / 2) * 1000; 162 163 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR_SUM, 164 "rssi=%u dur=%u, freq=%d MHz, freq_lo=%d MHz, freq_hi=%d MHz", 165 rssi, dur, e->freq/1000, e->freq_lo/1000, 166 e->freq_hi / 1000); 167 168 return 1; 169 } 170 171 int dfs_process_phyerr_sowl(struct wlan_dfs *dfs, 172 void *buf, 173 uint16_t datalen, 174 uint8_t rssi, 175 uint8_t ext_rssi, 176 uint32_t rs_tstamp, 177 uint64_t fulltsf, 178 struct dfs_phy_err *e) 179 { 180 #define EXT_CH_RADAR_FOUND 0x02 181 #define PRI_CH_RADAR_FOUND 0x01 182 #define EXT_CH_RADAR_EARLY_FOUND 0x04 183 const char *cbuf = (const char *)buf; 184 uint8_t dur = 0; 185 uint8_t pulse_bw_info, pulse_length_ext, pulse_length_pri; 186 int pri_found = 0, ext_found = 0; 187 int early_ext = 0; 188 int event_width; 189 190 /* 191 * If radar can be detected on the extension channel, datalen zero 192 * pulses are bogus, discard them. 193 */ 194 if (!datalen) { 195 dfs->wlan_dfs_stats.datalen_discards++; 196 return 0; 197 } 198 199 /* Ensure that we have at least three bytes of payload. */ 200 if (datalen < 3) { 201 dfs_debug(dfs, WLAN_DEBUG_DFS, 202 "short error frame (%d bytes)", datalen); 203 dfs->wlan_dfs_stats.datalen_discards++; 204 return 0; 205 } 206 207 /* 208 * Fetch the payload directly - the compiler will happily generate 209 * byte-read instructions with a const char * cbuf pointer. 210 */ 211 pulse_length_pri = cbuf[datalen - 3]; 212 pulse_length_ext = cbuf[datalen - 2]; 213 pulse_bw_info = cbuf[datalen - 1]; 214 215 /* 216 * Only the last 3 bits of the BW info are relevant, they indicate 217 * which channel the radar was detected in. 218 */ 219 pulse_bw_info &= 0x07; 220 221 /* If pulse on DC, both primary and extension flags will be set */ 222 if (((pulse_bw_info & EXT_CH_RADAR_FOUND) && 223 (pulse_bw_info & PRI_CH_RADAR_FOUND))) { 224 /* 225 * Conducted testing, when pulse is on DC, both pri and ext 226 * durations are reported to be same. Radiated testing, when 227 * pulse is on DC, differentpri and ext durations are reported, 228 * so take the larger of the two. 229 */ 230 if (pulse_length_ext >= pulse_length_pri) { 231 dur = pulse_length_ext; 232 ext_found = 1; 233 } else { 234 dur = pulse_length_pri; 235 pri_found = 1; 236 } 237 dfs->wlan_dfs_stats.dc_phy_errors++; 238 } else { 239 if (pulse_bw_info & EXT_CH_RADAR_FOUND) { 240 dur = pulse_length_ext; 241 pri_found = 0; 242 ext_found = 1; 243 dfs->wlan_dfs_stats.ext_phy_errors++; 244 } 245 if (pulse_bw_info & PRI_CH_RADAR_FOUND) { 246 dur = pulse_length_pri; 247 pri_found = 1; 248 ext_found = 0; 249 dfs->wlan_dfs_stats.pri_phy_errors++; 250 } 251 if (pulse_bw_info & EXT_CH_RADAR_EARLY_FOUND) { 252 dur = pulse_length_ext; 253 pri_found = 0; 254 ext_found = 1; 255 early_ext = 1; 256 dfs->wlan_dfs_stats.early_ext_phy_errors++; 257 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR, 258 "EARLY ext channel dur=%u rssi=%u datalen=%d", 259 dur, rssi, datalen); 260 } 261 if (!pulse_bw_info) { 262 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR, 263 "ERROR channel dur=%u rssi=%u pulse_bw_info=0x%x datalen MOD 4 = %d", 264 dur, rssi, pulse_bw_info, (datalen & 0x3)); 265 /* 266 * Bogus bandwidth info received in descriptor, so 267 * ignore this PHY error. 268 */ 269 dfs->wlan_dfs_stats.bwinfo_errors++; 270 return 0; 271 } 272 } 273 274 /* 275 * Always use combined RSSI reported, unless RSSI reported on 276 * extension is stronger. 277 */ 278 if ((ext_rssi > rssi) && (ext_rssi < 128)) 279 rssi = ext_rssi; 280 281 /* Fill out the rssi/duration fields from above. */ 282 qdf_mem_set(e, sizeof(*e), 0); 283 e->rssi = rssi; 284 e->dur = dur; 285 e->is_pri = pri_found; 286 e->is_ext = ext_found; 287 e->is_dc = !!(((pulse_bw_info & EXT_CH_RADAR_FOUND) && 288 (pulse_bw_info & PRI_CH_RADAR_FOUND))); 289 e->is_early = early_ext; 290 e->fulltsf = fulltsf; 291 e->rs_tstamp = rs_tstamp; 292 293 /* Sowl and later can report pri/ext events. */ 294 event_width = dfs_get_event_freqwidth(dfs); 295 e->freq = dfs_get_event_freqcentre(dfs, e->is_pri, e->is_ext, 296 e->is_dc) * 1000; 297 e->freq_lo = e->freq - (event_width / 2) * 1000; 298 e->freq_hi = e->freq + (event_width / 2) * 1000; 299 300 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR_SUM, 301 "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", 302 pulse_bw_info, pulse_length_ext, pulse_length_pri, 303 rssi, ext_rssi, e->freq/1000, e->freq_lo/1000, e->freq_hi/1000); 304 #undef EXT_CH_RADAR_FOUND 305 #undef PRI_CH_RADAR_FOUND 306 #undef EXT_CH_RADAR_EARLY_FOUND 307 308 return 1; 309 } 310 311 int dfs_process_phyerr_merlin(struct wlan_dfs *dfs, 312 void *buf, 313 uint16_t datalen, 314 uint8_t rssi, 315 uint8_t ext_rssi, 316 uint32_t rs_tstamp, 317 uint64_t fulltsf, 318 struct dfs_phy_err *e) 319 { 320 const char *cbuf = (const char *) buf; 321 uint8_t pulse_bw_info = 0; 322 323 /* Process using the sowl code. */ 324 if (!dfs_process_phyerr_sowl(dfs, buf, datalen, rssi, ext_rssi, 325 rs_tstamp, fulltsf, e)) { 326 return 0; 327 } 328 329 /* 330 * For osprey (and Merlin) bw_info has implication for selecting RSSI 331 * value. So re-fetch the bw_info field so the RSSI values can be 332 * appropriately overridden. 333 */ 334 pulse_bw_info = cbuf[datalen - 1]; 335 336 switch (pulse_bw_info & 0x03) { 337 case 0x00: 338 /* No radar in ctrl or ext channel */ 339 rssi = 0; 340 break; 341 case 0x01: 342 /* Radar in ctrl channel */ 343 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR, 344 "RAW RSSI: rssi=%u ext_rssi=%u", rssi, ext_rssi); 345 if (ext_rssi >= (rssi + 3)) { 346 /* 347 * Cannot use ctrl channel RSSI if extension channel is 348 * stronger. 349 */ 350 rssi = 0; 351 } 352 break; 353 case 0x02: 354 /* Radar in extension channel */ 355 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR, 356 "RAW RSSI: rssi=%u ext_rssi=%u", rssi, ext_rssi); 357 if (rssi >= (ext_rssi + 12)) { 358 /* 359 * Cannot use extension channel RSSI if control channel 360 * is stronger 361 */ 362 rssi = 0; 363 } else { 364 rssi = ext_rssi; 365 } 366 break; 367 case 0x03: 368 /* When both are present use stronger one */ 369 if (rssi < ext_rssi) 370 rssi = ext_rssi; 371 break; 372 } 373 374 /* 375 * Override the rssi decision made by the sowl code. The rest of the 376 * fields (duration, timestamp, etc) are left untouched. 377 */ 378 e->rssi = rssi; 379 380 return 1; 381 } 382 383 /** 384 * dfs_dump_phyerr_contents() - Dump the phyerr contents. 385 * @d: Phyerr buffer. 386 * @len: Phyerr buf length. 387 */ 388 389 static void dfs_dump_phyerr_contents(const char *d, int len) 390 { 391 int i, n, bufsize = 64; 392 393 /* 394 * This is statically sized for a 4-digit address + 16 * 2 digit data 395 * string. It's done so the printk() passed to the kernel is an entire 396 * line, so the kernel logging code will atomically print it. Otherwise 397 * we'll end up with interleaved lines with output from other kernel 398 * threads. 399 */ 400 char buf[64]; 401 402 /* Initial conditions */ 403 buf[0] = '\n'; 404 n = 0; 405 406 for (i = 0; i < len; i++) { 407 if (i % 16 == 0) 408 n += snprintf(buf + n, bufsize - n, "%04x: ", i); 409 410 n += snprintf(buf + n, bufsize - n, "%02x ", d[i] & 0xff); 411 if (i % 16 == 15) { 412 dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS, "%s", buf); 413 n = 0; 414 buf[0] = '\0'; 415 } 416 } 417 418 /* Print the final line if we didn't print it above. */ 419 if (n != 0) 420 dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS, "%s", buf); 421 } 422 423 /** 424 * dfs_bump_up_bin5_pulse_dur() - Bump up to a random BIN 5 pulse duration. 425 * @dfs: Pointer to wlan_dfs structure. 426 * @e: Pointer to dfs_phy_err structure. 427 * @slope: Slope value. 428 */ 429 static inline void dfs_bump_up_bin5_pulse_dur( 430 struct wlan_dfs *dfs, 431 struct dfs_phy_err *e, 432 int slope) 433 { 434 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR, "old dur %d slope =%d", 435 e->dur, slope); 436 437 e->is_sw_chirp = 1; 438 /* bump up to a random bin5 pulse duration */ 439 if (e->dur < MIN_BIN5_DUR) 440 e->dur = dfs_get_random_bin5_dur(dfs, e->fulltsf); 441 442 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR, "new dur %d", e->dur); 443 } 444 445 /** 446 * dfs_filter_short_pulses() - Filter short pulses. 447 * @dfs: Pointer to wlan_dfs structure. 448 * @e: Pointer to dfs_phy_err structure. 449 * @retval: Return value 450 * 451 * Rssi is not accurate for short pulses, so donot filter based on that for 452 * short duration pulses. 453 */ 454 static inline void dfs_filter_short_pulses( 455 struct wlan_dfs *dfs, 456 struct dfs_phy_err *e, 457 int *retval) 458 { 459 if (dfs->dfs_caps.wlan_dfs_ext_chan_ok) { 460 if ((e->rssi < dfs->dfs_rinfo.rn_minrssithresh && 461 (e->dur > MAX_DUR_FOR_LOW_RSSI)) || 462 e->dur > (dfs->dfs_rinfo.rn_maxpulsedur)) { 463 dfs->wlan_dfs_stats.rssi_discards++; 464 *retval = 1; 465 } 466 } else if (e->rssi < dfs->dfs_rinfo.rn_minrssithresh || 467 e->dur > dfs->dfs_rinfo.rn_maxpulsedur) { 468 dfs->wlan_dfs_stats.rssi_discards++; 469 *retval = 1; 470 } 471 472 if (*retval) { 473 dfs_debug(dfs, WLAN_DEBUG_DFS1, 474 "%s pulse is discarded: dur=%d, maxpulsedur=%d, rssi=%d, minrssi=%d", 475 (dfs->dfs_caps.wlan_dfs_ext_chan_ok) ? 476 "Extension channel" : "", 477 e->dur, dfs->dfs_rinfo.rn_maxpulsedur, 478 e->rssi, dfs->dfs_rinfo.rn_minrssithresh); 479 } 480 } 481 482 /** 483 * dfs_is_second_seg_radar_disabled() - Check for second segment radar disabled. 484 * @dfs: Pointer to wlan_dfs structure. 485 * @seg_id: Segment id. 486 * 487 * Return: true if the second segment RADAR is enabled else false. 488 */ 489 static inline bool dfs_is_second_seg_radar_disabled( 490 struct wlan_dfs *dfs, 491 int seg_id) 492 { 493 if ((seg_id == SEG_ID_SECONDARY) && 494 !(dfs->dfs_proc_phyerr & 495 DFS_SECOND_SEGMENT_RADAR_EN)) { 496 dfs_debug(dfs, WLAN_DEBUG_DFS3, 497 "Do not process PHY error data from Second segment, DFS_SECOND_SEGMENT_RADAR_EN is not enabled"); 498 return true; 499 } 500 501 return false; 502 } 503 504 /** 505 * dfs_set_chan_index() - Set channel index. 506 * @dfs: Pointer to wlan_dfs structure. 507 * @e: Pointer to dfs_phy_err structure. 508 * @event: Pointer to dfs_event structure. 509 */ 510 static inline void dfs_set_chan_index( 511 struct wlan_dfs *dfs, 512 struct dfs_phy_err *e, 513 struct dfs_event *event) 514 { 515 if (e->is_pri) { 516 event->re_chanindex = dfs->dfs_curchan_radindex; 517 } else { 518 event->re_chanindex = dfs->dfs_extchan_radindex; 519 dfs_debug(dfs, WLAN_DEBUG_DFS_PHYERR, 520 "%s New extension channel event is added to queue", 521 (event->re_chanindex == -1) ? 522 "- phyerr on ext channel" : ""); 523 } 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 /* Handle chirp flags. */ 815 if (e.do_check_chirp) { 816 event->re_flags |= DFS_EVENT_CHECKCHIRP; 817 if (e.is_hw_chirp) 818 event->re_flags |= DFS_EVENT_HW_CHIRP; 819 if (e.is_sw_chirp) 820 event->re_flags |= DFS_EVENT_SW_CHIRP; 821 } 822 823 /* Correctly set which channel is being reported on */ 824 dfs_set_chan_index(dfs, &e, event); 825 826 WLAN_DFSQ_LOCK(dfs); 827 STAILQ_INSERT_TAIL(&(dfs->dfs_radarq), event, re_list); 828 WLAN_DFSQ_UNLOCK(dfs); 829 } 830 } 831 832 /* 833 * Schedule the radar/AR task as appropriate. 834 * XXX isn't a lock needed for wlan_radar_tasksched? 835 */ 836 if (!STAILQ_EMPTY(&dfs->dfs_arq)) { 837 /* XXX shouldn't this be a task/timer too? */ 838 dfs_process_ar_event(dfs, dfs->dfs_curchan); 839 } 840 if (!STAILQ_EMPTY(&dfs->dfs_radarq) && !dfs->wlan_radar_tasksched) { 841 dfs->wlan_radar_tasksched = 1; 842 qdf_timer_mod(&dfs->wlan_dfs_task_timer, 0); 843 } 844 #undef EXT_CH_RADAR_FOUND 845 #undef PRI_CH_RADAR_FOUND 846 #undef EXT_CH_RADAR_EARLY_FOUND 847 } 848 849 #ifdef QCA_MCL_DFS_SUPPORT 850 void dfs_process_phyerr_filter_offload(struct wlan_dfs *dfs, 851 struct radar_event_info *wlan_radar_event) 852 { 853 struct dfs_event *event; 854 int empty; 855 int do_check_chirp = 0; 856 int is_hw_chirp = 0; 857 int is_sw_chirp = 0; 858 int is_pri = 0; 859 860 if (!dfs) { 861 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL"); 862 return; 863 } 864 865 if (dfs->dfs_ignore_dfs) { 866 dfs_debug(dfs, WLAN_DEBUG_DFS1, "ignoring dfs"); 867 return; 868 } 869 870 if (!(dfs->dfs_proc_phyerr & DFS_RADAR_EN)) { 871 dfs_debug(dfs, WLAN_DEBUG_DFS1, 872 "DFS_RADAR_EN not set in dfs->dfs_proc_phyerr"); 873 return; 874 } 875 876 if (WLAN_IS_CHAN_RADAR(dfs->dfs_curchan)) { 877 dfs_debug(dfs, WLAN_DEBUG_DFS1, 878 "Radar already found in the channel, do not queue radar data"); 879 return; 880 } 881 882 dfs->wlan_dfs_stats.total_phy_errors++; 883 if (dfs->dfs_caps.wlan_chip_is_bb_tlv) { 884 do_check_chirp = 1; 885 is_pri = 1; 886 is_hw_chirp = wlan_radar_event->pulse_is_chirp; 887 888 if ((uint32_t) dfs->dfs_phyerr_freq_min > 889 wlan_radar_event->pulse_center_freq) { 890 dfs->dfs_phyerr_freq_min = 891 (int)wlan_radar_event->pulse_center_freq; 892 } 893 894 if (dfs->dfs_phyerr_freq_max < 895 (int)wlan_radar_event->pulse_center_freq) { 896 dfs->dfs_phyerr_freq_max = 897 (int)wlan_radar_event->pulse_center_freq; 898 } 899 } 900 901 /* 902 * Now, add the parsed, checked and filtered 903 * radar phyerror event radar pulse event list. 904 * This event will then be processed by 905 * dfs_radar_processevent() to see if the pattern 906 * of pulses in radar pulse list match any radar 907 * singnature in the current regulatory domain. 908 */ 909 910 WLAN_DFSEVENTQ_LOCK(dfs); 911 empty = STAILQ_EMPTY(&(dfs->dfs_eventq)); 912 WLAN_DFSEVENTQ_UNLOCK(dfs); 913 if (empty) 914 return; 915 /* 916 * Add the event to the list, if there's space. 917 */ 918 WLAN_DFSEVENTQ_LOCK(dfs); 919 event = STAILQ_FIRST(&(dfs->dfs_eventq)); 920 if (!event) { 921 WLAN_DFSEVENTQ_UNLOCK(dfs); 922 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, 923 "%s: No more space left for queuing DFS Phyerror events", 924 __func__); 925 return; 926 } 927 STAILQ_REMOVE_HEAD(&(dfs->dfs_eventq), re_list); 928 WLAN_DFSEVENTQ_UNLOCK(dfs); 929 dfs->dfs_phyerr_queued_count++; 930 dfs->dfs_phyerr_w53_counter++; 931 event->re_dur = (uint8_t) wlan_radar_event->pulse_duration; 932 event->re_rssi = wlan_radar_event->rssi; 933 event->re_ts = wlan_radar_event->pulse_detect_ts & DFS_TSMASK; 934 event->re_full_ts = (((uint64_t) wlan_radar_event->upload_fullts_high) 935 << 32) | wlan_radar_event->upload_fullts_low; 936 937 /* 938 * Index of peak magnitude 939 */ 940 event->re_sidx = wlan_radar_event->peak_sidx; 941 event->re_delta_diff = wlan_radar_event->delta_diff; 942 event->re_delta_peak = wlan_radar_event->delta_peak; 943 event->re_flags = 0; 944 945 /* 946 * Handle chirp flags. 947 */ 948 if (do_check_chirp) { 949 event->re_flags |= DFS_EVENT_CHECKCHIRP; 950 if (is_hw_chirp) 951 event->re_flags |= DFS_EVENT_HW_CHIRP; 952 if (is_sw_chirp) 953 event->re_flags |= DFS_EVENT_SW_CHIRP; 954 } 955 /* 956 * Correctly set which channel is being reported on 957 */ 958 if (is_pri) { 959 event->re_chanindex = (uint8_t) dfs->dfs_curchan_radindex; 960 } else { 961 if (dfs->dfs_extchan_radindex == -1) 962 dfs_debug(dfs, WLAN_DEBUG_DFS1, 963 "%s phyerr on ext channel", __func__); 964 event->re_chanindex = (uint8_t) dfs->dfs_extchan_radindex; 965 dfs_debug(dfs, WLAN_DEBUG_DFS1, 966 "%s:New extension channel event is added to queue", 967 __func__); 968 } 969 970 WLAN_DFSQ_LOCK(dfs); 971 972 STAILQ_INSERT_TAIL(&(dfs->dfs_radarq), event, re_list); 973 974 empty = STAILQ_EMPTY(&dfs->dfs_radarq); 975 976 WLAN_DFSQ_UNLOCK(dfs); 977 978 if (!empty && !dfs->wlan_radar_tasksched) { 979 dfs->wlan_radar_tasksched = 1; 980 qdf_timer_mod(&dfs->wlan_dfs_task_timer, 0); 981 } 982 } 983 #endif 984