1 /* 2 * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /** 21 * DOC: API for processing radar found indication. 22 * 23 */ 24 25 #include "../dfs.h" 26 #include "../dfs_zero_cac.h" 27 #include "../dfs_process_radar_found_ind.h" 28 #include <wlan_reg_services_api.h> 29 #include <wlan_objmgr_vdev_obj.h> 30 #include <wlan_dfs_utils_api.h> 31 #include <wlan_dfs_tgt_api.h> 32 #include "wlan_dfs_mlme_api.h" 33 #include "../dfs_internal.h" 34 /** 35 * TODO: The code is not according to the following description needs 36 * modification and correction. Code always adds left and right channels to 37 * NOL even if it is not a chirp radar. 38 * 39 * A) If chirp radar starts at boundary and ends at boundary then three channels 40 * will be affected. 41 * freq_offset.freq[0] = fn (Center frequency) 42 * freq_offset.freq[1] = fn-1 (Left of center) 43 * freq_offset.freq[2] = fn+1 (Right of center) 44 * 45 * Three channels, ch(n-1), ch(n)and ch(n+1) will be added to NOL. 46 * 47 * Chirp start freq Chirp end freq 48 * | | 49 * | | 50 * V V 51 * _______________________________________________________________________ 52 * | center freq | center freq | center freq | 53 * | ch(n-1) | ch(n) | ch(n+1) | 54 * | | | | | | | 55 * | | | | | | | 56 * | | | | | | | 57 * fn-1 fn boundary fn+1 58 * <-------- 20 Mhz ------> 59 * 60 * B) If chirp radar starts at one channel and continues up to another channel 61 * then two channels will be affected. 62 * freq_offset.freq[0] = fn 63 * freq_offset.freq[1] = 0 64 * freq_offset.freq[2] = fn+1 65 * 66 * Three channels, ch(n-1), ch(n)and ch(n+1) will be added to NOL. 67 * 68 * Chirp start freq Chirp end freq 69 * | | 70 * | | 71 * V V 72 * _______________________________________________________________________ 73 * | center freq | center freq | center freq | 74 * | ch(n-1) | ch(n) | ch(n+1) | 75 * | | | | | | | 76 * | | | | | | | 77 * | | | | | | | 78 * fn-1 fn boundary fn+1 79 * <-------- 20 Mhz ------> 80 * 81 * C) Radar found at boundary, two channels will be affected. 82 * freq_offset.freq[0] = fn 83 * freq_offset.freq[1] = 0 84 * freq_offset.freq[2] = fn+1 85 * 86 * Two channels, ch(n) and ch(n+1) will be added to NOL. 87 * 88 * dfs_freq_offset (radar found freq) 89 * | 90 * | 91 * V 92 * _______________________________________________________________________ 93 * | center freq | center freq | center freq | 94 * | ch(n-1) | ch(n) | ch(n+1) | 95 * | | | | | | | 96 * | | | | | | | 97 * | | | | | | | 98 * fn-1 fn boundary fn+1 99 * <-------- 20 Mhz ------> 100 * 101 * 102 * D) Else only one channel will be affected. 103 * freq_offset.freq[0] = fn 104 * freq_offset.freq[1] = 0 105 * freq_offset.freq[2] = 0 106 * 107 * One channel ch(n) will be added to NOL. 108 * 109 * 110 * dfs_freq_offset (radar found freq) 111 * | 112 * | 113 * V 114 * _______________________________________________________________________ 115 * | center freq | center freq | center freq | 116 * | ch(n-1) | ch(n) | ch(n+1) | 117 * | | | | | | | 118 * | | | | | | | 119 * | | | | | | | 120 * fn-1 fn boundary fn+1 121 * <-------- 20 Mhz ------> 122 */ 123 124 int dfs_set_nol_subchannel_marking(struct wlan_dfs *dfs, 125 bool nol_subchannel_marking) 126 { 127 QDF_STATUS status = QDF_STATUS_SUCCESS; 128 129 if (!dfs) 130 return -EIO; 131 132 dfs->dfs_use_nol_subchannel_marking = nol_subchannel_marking; 133 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "NOL subchannel marking is %s ", 134 (nol_subchannel_marking) ? "set" : "disabled"); 135 if (dfs->dfs_is_offload_enabled) 136 status = tgt_dfs_send_subchan_marking(dfs->dfs_pdev_obj, 137 nol_subchannel_marking); 138 139 return qdf_status_to_os_return(status); 140 } 141 142 int dfs_get_nol_subchannel_marking(struct wlan_dfs *dfs, 143 bool *nol_subchannel_marking) 144 { 145 if (!dfs) 146 return -EIO; 147 148 (*nol_subchannel_marking) = dfs->dfs_use_nol_subchannel_marking; 149 150 return 0; 151 } 152 153 #ifdef CONFIG_CHAN_FREQ_API 154 QDF_STATUS 155 dfs_radar_add_channel_list_to_nol_for_freq(struct wlan_dfs *dfs, 156 uint16_t *freq_list, 157 uint16_t *nol_freq_list, 158 uint8_t *num_channels) 159 { 160 int i; 161 uint16_t last_chan_freq = 0; 162 uint8_t num_ch = 0; 163 164 if (*num_channels > MAX_20MHZ_SUBCHANS) { 165 dfs_err(dfs, WLAN_DEBUG_DFS, 166 "Invalid num channels: %d", *num_channels); 167 return QDF_STATUS_E_FAILURE; 168 } 169 170 for (i = 0; i < *num_channels; i++) { 171 if (freq_list[i] == 0 || 172 freq_list[i] == last_chan_freq) 173 continue; 174 if (!utils_is_dfs_chan_for_freq(dfs->dfs_pdev_obj, 175 freq_list[i])) { 176 dfs_info(dfs, WLAN_DEBUG_DFS, "ch=%d is not dfs, skip", 177 freq_list[i]); 178 continue; 179 } 180 181 last_chan_freq = freq_list[i]; 182 DFS_NOL_ADD_CHAN_LOCKED(dfs, 183 freq_list[i], 184 dfs->wlan_dfs_nol_timeout); 185 nol_freq_list[num_ch++] = last_chan_freq; 186 utils_dfs_deliver_event(dfs->dfs_pdev_obj, 187 freq_list[i], 188 WLAN_EV_NOL_STARTED); 189 dfs_info(dfs, WLAN_DEBUG_DFS_NOL, "ch=%d Added to NOL", 190 last_chan_freq); 191 } 192 193 if (!num_ch) { 194 dfs_err(dfs, WLAN_DEBUG_DFS, 195 "dfs channels not found in channel list"); 196 return QDF_STATUS_E_FAILURE; 197 } 198 *num_channels = num_ch; 199 200 if (!dfs_get_disable_radar_marking(dfs)) { 201 utils_dfs_reg_update_nol_chan_for_freq(dfs->dfs_pdev_obj, 202 nol_freq_list, num_ch, 203 DFS_NOL_SET); 204 205 if (dfs->dfs_is_stadfs_enabled) 206 if (dfs_mlme_is_opmode_sta(dfs->dfs_pdev_obj)) 207 utils_dfs_reg_update_nol_history_chan_for_freq( 208 dfs->dfs_pdev_obj, nol_freq_list, 209 num_ch, DFS_NOL_HISTORY_SET); 210 } 211 212 dfs_nol_update(dfs); 213 utils_dfs_save_nol(dfs->dfs_pdev_obj); 214 215 return QDF_STATUS_SUCCESS; 216 } 217 #endif 218 219 /** 220 * dfs_find_20mhz_subchans_from_offsets()- Find frequency offsets 221 * that aligns with 20MHz sub-channel centers. 222 * 223 * @freq_offset: freq offset 224 * @center_freq: center frequency 225 * @ch_width: Channel Width value: 20/40/80/160/320MHz. 226 * Find frequency offsets for 80MHz 227 * 228 * Return: None 229 */ 230 static void 231 dfs_find_20mhz_subchans_from_offsets(struct freqs_offsets *freq_offset, 232 uint32_t center_freq, 233 uint16_t ch_width) 234 { 235 uint16_t first_chan20_cen = center_freq - (ch_width / 2) + BW_10; 236 uint16_t i, j; 237 uint8_t num_20mhz_subchans = ch_width / BW_20; 238 239 for (i = 0; i < DFS_NUM_FREQ_OFFSET; i++) { 240 uint16_t radar_found_freq = 241 center_freq + freq_offset->offset[i]; 242 uint16_t chan20_cen = first_chan20_cen; 243 244 for (j = 0; j < num_20mhz_subchans; j++) { 245 if ((radar_found_freq > chan20_cen - BW_10) && 246 (radar_found_freq < chan20_cen + BW_10)) { 247 freq_offset->freq[i] = chan20_cen; 248 break; 249 } 250 chan20_cen += BW_20; 251 } 252 } 253 } 254 255 #ifdef CONFIG_CHAN_FREQ_API 256 void 257 dfs_compute_radar_found_cfreq(struct wlan_dfs *dfs, 258 struct radar_found_info *radar_found, 259 uint32_t *freq_center) 260 { 261 struct dfs_channel *curchan = dfs->dfs_curchan; 262 263 /* In case of 11BE Chipsets, radar found center frequency is 264 * directly obtained from WMI. 265 */ 266 if (dfs->dfs_is_radar_found_chan_freq_eq_center_freq) { 267 *freq_center = radar_found->chan_freq; 268 return; 269 } 270 271 /* Radar found on agile detector ID. 272 * Applicable to chips that have a separate agile radar detector 273 * engine. 274 */ 275 if (radar_found->detector_id == dfs_get_agile_detector_id(dfs)) { 276 *freq_center = dfs->dfs_agile_precac_freq_mhz; 277 if (dfs->dfs_precac_chwidth == CH_WIDTH_160MHZ) { 278 if (radar_found->segment_id == PRIMARY_SEG) 279 *freq_center -= DFS_160MHZ_SECOND_SEG_OFFSET; 280 else 281 *freq_center += DFS_160MHZ_SECOND_SEG_OFFSET; 282 } else if (dfs->dfs_precac_chwidth == CH_WIDTH_80P80MHZ && 283 dfs->dfs_agile_precac_freq_mhz == 284 RESTRICTED_80P80_CHAN_CENTER_FREQ) { 285 /* 286 * The reason why left and right offsets 287 * are different. 288 * Center of 165 is 5730MHz. 289 * Center of left 80 is 5690MHz. 290 * Center of right 80 is 5775MHz. 291 */ 292 if (radar_found->segment_id == PRIMARY_SEG) 293 *freq_center -= 294 DFS_165MHZ_SECOND_SEG_OFFSET_LEFT; 295 else 296 *freq_center += 297 DFS_165MHZ_SECOND_SEG_OFFSET_RIGHT; 298 } 299 } else if (!radar_found->segment_id) { 300 *freq_center = curchan->dfs_ch_mhz_freq_seg1; 301 } else { 302 /* Radar found on secondary segment by the HW, when preCAC 303 * was not running in legacy chips or preCAC was running 304 * in Lithium chips. 305 */ 306 *freq_center = curchan->dfs_ch_mhz_freq_seg2; 307 if (WLAN_IS_CHAN_MODE_160(curchan)) { 308 /* If center frequency of entire 160 band 309 * is less than center frequency of primary 310 * segment, then the center frequency of 311 * secondary segment is -40 of center 312 * frequency of entire 160 segment. 313 */ 314 if (curchan->dfs_ch_mhz_freq_seg2 < 315 curchan->dfs_ch_mhz_freq_seg1) 316 *freq_center -= 317 DFS_160MHZ_SECOND_SEG_OFFSET; 318 else 319 *freq_center += 320 DFS_160MHZ_SECOND_SEG_OFFSET; 321 } 322 } 323 } 324 #endif 325 326 /** 327 * dfs_find_radar_affected_subchans_for_freq() - Find radar affected sub chans. 328 * @dfs: Pointer to wlan_dfs structure. 329 * @radar_found: Pointer to radar_found structure. 330 * @freq_list: Pointer to save radar affected channels. 331 * @freq_center: Freq_center of the radar affected chan. 332 * 333 * Return: Number of channels. 334 */ 335 #ifdef CONFIG_CHAN_FREQ_API 336 static uint8_t 337 dfs_find_radar_affected_subchans_for_freq(struct wlan_dfs *dfs, 338 struct radar_found_info *radar_found, 339 uint16_t *freq_list, 340 uint32_t freq_center) 341 { 342 int i, j; 343 uint8_t num_radar_subchans; 344 uint32_t flag; 345 int32_t sidx; 346 uint16_t candidate_subchan_freq; 347 uint16_t cur_subchans[MAX_20MHZ_SUBCHANS]; 348 uint8_t n_cur_subchans; 349 struct dfs_channel *curchan = dfs->dfs_curchan; 350 struct freqs_offsets freq_offset; 351 uint16_t ch_width; 352 353 qdf_mem_zero(&freq_offset, sizeof(freq_offset)); 354 flag = curchan->dfs_ch_flags; 355 356 for (i = 0; i < DFS_NUM_FREQ_OFFSET; i++) 357 freq_offset.offset[i] = radar_found->freq_offset; 358 359 sidx = DFS_FREQ_OFFSET_TO_SIDX(radar_found->freq_offset); 360 361 dfs_info(dfs, WLAN_DEBUG_DFS, 362 "seg=%d, det=%d, sidx=%d, offset=%d, chirp=%d, flag=%d, f=%d", 363 radar_found->segment_id, radar_found->detector_id, sidx, 364 radar_found->freq_offset, radar_found->is_chirp, 365 flag, freq_center); 366 367 ch_width = dfs_chan_to_ch_width(curchan); 368 if (ch_width == BW_INVALID) { 369 dfs_err(dfs, WLAN_DEBUG_DFS, 370 "channel flag=%d is invalid", flag); 371 return 0; 372 } 373 374 if (radar_found->is_chirp || !(abs(sidx) % DFS_BOUNDARY_SIDX)) { 375 freq_offset.offset[LEFT_CH] -= DFS_CHIRP_OFFSET; 376 freq_offset.offset[RIGHT_CH] += DFS_CHIRP_OFFSET; 377 } 378 379 dfs_find_20mhz_subchans_from_offsets(&freq_offset, freq_center, 380 ch_width); 381 382 n_cur_subchans = 383 dfs_get_bonding_channels_for_freq(dfs, curchan, 384 radar_found->segment_id, 385 radar_found->detector_id, 386 cur_subchans); 387 388 for (i = 0, num_radar_subchans = 0; i < DFS_NUM_FREQ_OFFSET; i++) { 389 candidate_subchan_freq = freq_offset.freq[i]; 390 for (j = 0; j < n_cur_subchans; j++) { 391 if (cur_subchans[j] == candidate_subchan_freq) { 392 freq_list[num_radar_subchans++] = 393 candidate_subchan_freq; 394 dfs_info(dfs, WLAN_DEBUG_DFS, 395 "offset=%d, channel=%d", 396 num_radar_subchans, 397 freq_list[num_radar_subchans - 1]); 398 break; 399 } 400 } 401 } 402 return num_radar_subchans; 403 } 404 #endif 405 406 /** 407 * dfs_calc_bonding_freqs: Calculate bonding channel frequencies from the 408 * channel width's center frequency and channel width. 409 * It is assumed that the caller has allocated sufficient memory for 'freq_list' 410 * so that it can hold all the output subchannels. 411 * 412 * center_freq: Center frequency of the channel width. 413 * ch_width: Channel width. 414 * freq_list: output array of sub-channel frequencies. 415 * 416 * Return: void 417 */ 418 static void 419 dfs_calc_bonding_freqs(qdf_freq_t center_freq, 420 uint16_t ch_width, 421 uint16_t *freq_list) 422 { 423 #define CHAN_SPACING_MHZ_5G 20 424 #define SUB20CHAN_BW_MHZ_5G 20 425 uint8_t nchans = ch_width / CHAN_SPACING_MHZ_5G; 426 qdf_freq_t first_subchan_cfreq = center_freq - (ch_width / 2) + 427 (SUB20CHAN_BW_MHZ_5G / 2); 428 uint8_t i; 429 430 for (i = 0; i < nchans; ++i) 431 freq_list[i] = first_subchan_cfreq + (i * CHAN_SPACING_MHZ_5G); 432 } 433 434 /** 435 * dfs_get_20mhz_bonding_channels() - Get bonding frequency list of 20MHz 436 * channel. 437 * @center_freq: Center frequency of the 20MHz channel. 438 * @freq_list: Pointer to frequency list. 439 * 440 * Return: void 441 */ 442 static 443 void dfs_get_20mhz_bonding_channels(uint16_t center_freq, uint16_t *freq_list) 444 { 445 uint16_t chwidth = BW_20; 446 447 dfs_calc_bonding_freqs(center_freq, chwidth, freq_list); 448 } 449 450 /** 451 * dfs_get_40mhz_bonding_channels() - Get bonding frequency list of 40MHz 452 * channel. 453 * @center_freq: Center frequency of the 40MHz channel. 454 * @freq_list: Pointer to frequency list. 455 * 456 * Return: void 457 */ 458 static 459 void dfs_get_40mhz_bonding_channels(uint16_t center_freq, uint16_t *freq_list) 460 { 461 uint16_t chwidth = BW_40; 462 463 dfs_calc_bonding_freqs(center_freq, chwidth, freq_list); 464 } 465 466 /** 467 * dfs_get_80mhz_bonding_channels() - Get bonding frequency list of 80MHz 468 * channel. 469 * @center_freq: Center frequency of the 80MHz channel. 470 * @freq_list: Pointer to frequency list. 471 * 472 * Return: void 473 */ 474 static 475 void dfs_get_80mhz_bonding_channels(uint16_t center_freq, uint16_t *freq_list) 476 { 477 uint16_t chwidth = BW_80; 478 479 dfs_calc_bonding_freqs(center_freq, chwidth, freq_list); 480 } 481 482 /** 483 * dfs_get_160mhz_bonding_channels() - Get bonding frequency list of 160MHz 484 * channel. 485 * @center_freq: Center frequency of the 160MHz channel. 486 * @freq_list: Pointer to frequency list. 487 * 488 * Return: void 489 */ 490 static 491 void dfs_get_160mhz_bonding_channels(uint16_t center_freq, uint16_t *freq_list) 492 { 493 uint16_t chwidth = BW_160; 494 495 dfs_calc_bonding_freqs(center_freq, chwidth, freq_list); 496 } 497 498 /** 499 * dfs_get_320mhz_bonding_channels() - Get bonding frequency list of 320MHz 500 * channel. 501 * @center_freq: Center frequency of the 320MHz channel. 502 * @freq_list: Pointer to frequency list. 503 * 504 * Return: void 505 */ 506 #ifdef WLAN_FEATURE_11BE 507 static 508 void dfs_get_320mhz_bonding_channels(uint16_t center_freq, uint16_t *freq_list, 509 uint8_t *nchannels) 510 { 511 uint16_t chwidth = 320; 512 513 /* 514 * In 5Ghz band, the 320Mhz channel is always 80Mhz punctured 515 * to the right. Therefore, it is actually a 240Mhz channel and 516 * has twelve 20Mhz subchannels. 517 */ 518 *nchannels = NUM_CHANNELS_240MHZ; 519 dfs_calc_bonding_freqs(center_freq, chwidth, freq_list); 520 } 521 #else 522 static 523 void dfs_get_320mhz_bonding_channels(uint16_t center_freq, uint16_t *freq_list, 524 uint8_t *nchannels) 525 { 526 *nchannels = 0; 527 dfs_debug(NULL, WLAN_DEBUG_DFS_ALWAYS, 528 "320MHz chan width for non 11be"); 529 } 530 #endif 531 532 /* 533 * dfs_get_bonding_channel_without_seg_info_for_freq() - Get bonding frequency 534 * list. 535 * @chan: Pointer to dfs_channel. 536 * @freq_list: Pointer to frequency list. 537 */ 538 #ifdef CONFIG_CHAN_FREQ_API 539 uint8_t 540 dfs_get_bonding_channel_without_seg_info_for_freq(struct dfs_channel *chan, 541 uint16_t *freq_list) 542 { 543 uint16_t center_freq; 544 uint8_t nchannels = 0; 545 546 center_freq = chan->dfs_ch_mhz_freq_seg1; 547 548 if (WLAN_IS_CHAN_MODE_20(chan)) { 549 nchannels = 1; 550 dfs_get_20mhz_bonding_channels(center_freq, 551 freq_list); 552 } else if (WLAN_IS_CHAN_MODE_40(chan)) { 553 nchannels = 2; 554 dfs_get_40mhz_bonding_channels(center_freq, 555 freq_list); 556 } else if (WLAN_IS_CHAN_MODE_80(chan)) { 557 nchannels = 4; 558 dfs_get_80mhz_bonding_channels(center_freq, 559 freq_list); 560 } else if (WLAN_IS_CHAN_MODE_80_80(chan)) { 561 nchannels = 8; 562 dfs_get_80mhz_bonding_channels(center_freq, 563 freq_list); 564 center_freq = chan->dfs_ch_mhz_freq_seg2; 565 dfs_get_80mhz_bonding_channels(center_freq, 566 freq_list + 4); 567 } else if (WLAN_IS_CHAN_MODE_160(chan)) { 568 nchannels = 8; 569 center_freq = chan->dfs_ch_mhz_freq_seg2; 570 dfs_get_160mhz_bonding_channels(center_freq, freq_list); 571 } else if (WLAN_IS_CHAN_MODE_320(chan)) { 572 center_freq = chan->dfs_ch_mhz_freq_seg2; 573 dfs_get_320mhz_bonding_channels(center_freq, freq_list, 574 &nchannels); 575 } 576 577 return nchannels; 578 } 579 #endif 580 581 #ifdef CONFIG_CHAN_FREQ_API 582 /* 583 * dfs_get_agile_subchans_for_curchan_160() - Get bonding frequency list of 584 * agile channels when current operating channel is 160MHz. 585 * 586 * @dfs: Pointer to DFS structure. 587 * @center_freq: Center frequency of the channel. 588 * @segment_id: Segment ID of interest. 0 for primary segment and 1 for 589 * secondary segment. 590 * @freq_list: Pointer to frequency list. 591 * @nchannels: Number of subchannel. 592 */ 593 static void 594 dfs_get_agile_subchans_for_curchan_160(struct wlan_dfs *dfs, 595 uint16_t center_freq, 596 uint32_t segment_id, 597 uint16_t *freq_list, 598 uint8_t *nchannels) 599 { 600 if (dfs->dfs_precac_chwidth == CH_WIDTH_80MHZ) { 601 /* 602 * The current operating channel is 160MHz and 603 * the agile channel is 80MHz. This can happen 604 * in HK only. 605 */ 606 *nchannels = 4; 607 dfs_get_80mhz_bonding_channels(center_freq, 608 freq_list); 609 } else if (dfs->dfs_precac_chwidth == CH_WIDTH_160MHZ) 610 /* 611 * The current operating channel is 160MHz and 612 * the agile channel is 160MHz. 613 * Pine ADFS specific. 614 */ 615 dfs_get_160mhz_bonding_channels(center_freq, 616 freq_list); 617 else if (dfs->dfs_precac_chwidth == CH_WIDTH_80P80MHZ) { 618 /* 619 * The current operating channel is 160MHz and the agile channel 620 * is 165MHz(restricted 80P80MHZ). Pine ADFS specific. 621 * If the segment id is primary segment 0, shift the center 622 * frequency 5730MHz to the center of left 80MHz segment 5690MHz 623 * and add the subchannels of the left 80MHz segment. 624 * If the segment id is secondary segment 1, shift the center 625 * frequency 5730MHz to the center of right 80MHz segment 626 * 5775MHz and add the subchannels of the right 80MHz segment. 627 */ 628 *nchannels = 4; 629 center_freq = (segment_id) ? 630 (center_freq + DFS_165MHZ_SECOND_SEG_OFFSET_RIGHT) : 631 (center_freq - DFS_165MHZ_SECOND_SEG_OFFSET_LEFT); 632 dfs_get_80mhz_bonding_channels(center_freq, 633 freq_list); 634 } 635 } 636 637 /* 638 * dfs_get_bonding_channels_for_freq() - Get bonding channel frequency. 639 * @dfs: Pointer to wlan_dfs. 640 * @curchan: Pointer to dfs_channel. 641 * @segment_id: Segment ID. 642 * @detector_id: Detector ID. 643 * @freq_list: Pointer to frequency list. 644 */ 645 uint8_t dfs_get_bonding_channels_for_freq(struct wlan_dfs *dfs, 646 struct dfs_channel *curchan, 647 uint32_t segment_id, 648 uint8_t detector_id, 649 uint16_t *freq_list) 650 { 651 uint16_t center_freq; 652 uint8_t nchannels = 0; 653 654 /* 655 * For radar in agile detector, use the center of the channel 656 * configured to the agile detector. 657 * For radar on a 160MHz home channel, use the center of 160MHz. 658 * For radar on all other bandwidths, use the center of the segment 659 * affected. 660 */ 661 if (detector_id == dfs_get_agile_detector_id(dfs)) 662 center_freq = dfs->dfs_agile_precac_freq_mhz; 663 else if (WLAN_IS_CHAN_MODE_160(curchan) || 664 WLAN_IS_CHAN_MODE_320(curchan)) 665 center_freq = curchan->dfs_ch_mhz_freq_seg2; 666 else if (!segment_id) 667 center_freq = curchan->dfs_ch_mhz_freq_seg1; 668 else 669 center_freq = curchan->dfs_ch_mhz_freq_seg2; 670 671 if (WLAN_IS_CHAN_MODE_20(curchan)) { 672 nchannels = 1; 673 dfs_get_20mhz_bonding_channels(center_freq, freq_list); 674 } else if (WLAN_IS_CHAN_MODE_40(curchan)) { 675 nchannels = 2; 676 dfs_get_40mhz_bonding_channels(center_freq, freq_list); 677 } else if (WLAN_IS_CHAN_MODE_80(curchan)) { 678 nchannels = 4; 679 dfs_get_80mhz_bonding_channels(center_freq, freq_list); 680 } else if (WLAN_IS_CHAN_MODE_160(curchan)) { 681 nchannels = 8; 682 if (detector_id == dfs_get_agile_detector_id(dfs)) 683 dfs_get_agile_subchans_for_curchan_160(dfs, 684 center_freq, 685 segment_id, 686 freq_list, 687 &nchannels); 688 else 689 dfs_get_160mhz_bonding_channels(center_freq, freq_list); 690 } else if (WLAN_IS_CHAN_MODE_320(curchan)) { 691 dfs_get_320mhz_bonding_channels(center_freq, freq_list, 692 &nchannels); 693 } else if (WLAN_IS_CHAN_MODE_80_80(curchan)) { 694 /* 695 * If the current channel's bandwidth is 80P80MHz, 696 * the corresponding agile Detector's bandwidth will be 160MHz 697 * in case of Pine ADFS. 698 */ 699 if (detector_id == dfs_get_agile_detector_id(dfs)) { 700 if (dfs->dfs_precac_chwidth == CH_WIDTH_160MHZ) { 701 nchannels = 8; 702 dfs_get_160mhz_bonding_channels(center_freq, 703 freq_list); 704 } else if (dfs->dfs_precac_chwidth == CH_WIDTH_80MHZ) { 705 nchannels = 4; 706 dfs_get_80mhz_bonding_channels(center_freq, 707 freq_list); 708 } else { 709 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, 710 "Incorrect precac width %u", 711 dfs->dfs_precac_chwidth); 712 } 713 } else { 714 /* 715 * If the radar is getting detected in 80P80MHz home 716 * channel, only the 80MHz segment that is infected with 717 * radar is of interest. The other 80MHz segment is 718 * ignored. The center frequency of the radar infected 719 * segment is dfs_ch_mhz_freq_seg1 if primary and 720 * dfs_ch_mhz_freq_seg2 in case of secondary. 721 */ 722 nchannels = 4; 723 dfs_get_80mhz_bonding_channels(center_freq, freq_list); 724 } 725 } 726 727 return nchannels; 728 } 729 #endif 730 731 void dfs_reset_bangradar(struct wlan_dfs *dfs) 732 { 733 dfs->dfs_bangradar_type = DFS_NO_BANGRADAR; 734 } 735 736 /** 737 * dfs_radar_found_event_basic_sanity() - Check if radar event is received on a 738 * DFS channel. 739 * @dfs: Pointer to wlan_dfs structure. 740 * @chan: Current channel. 741 * 742 * Return: If a radar event found on NON-DFS channel return false. Otherwise, 743 * return true. 744 */ 745 static 746 bool dfs_radar_found_event_basic_sanity(struct wlan_dfs *dfs, 747 struct dfs_channel *chan) 748 { 749 if (!chan) { 750 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, 751 "dfs->dfs_curchan is NULL"); 752 return false; 753 } 754 755 if (!(WLAN_IS_PRIMARY_OR_SECONDARY_CHAN_DFS(chan))) { 756 dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS, 757 "radar event on non-DFS chan"); 758 return false; 759 } 760 761 return true; 762 } 763 764 void dfs_send_csa_to_current_chan(struct wlan_dfs *dfs) 765 { 766 dfs->wlan_dfstest = 1; 767 dfs->wlan_dfstest_ieeechan = dfs->dfs_curchan->dfs_ch_ieee; 768 dfs->wlan_dfstesttime = 1; /* 1ms */ 769 qdf_timer_sync_cancel(&dfs->wlan_dfstesttimer); 770 qdf_timer_start(&dfs->wlan_dfstesttimer, dfs->wlan_dfstesttime); 771 } 772 773 int dfs_second_segment_radar_disable(struct wlan_dfs *dfs) 774 { 775 dfs->dfs_proc_phyerr &= ~DFS_SECOND_SEGMENT_RADAR_EN; 776 777 return 0; 778 } 779 780 #ifdef WLAN_DFS_FULL_OFFLOAD 781 void dfs_inc_num_radar(struct wlan_dfs *dfs) 782 { 783 dfs->wlan_dfs_stats.num_radar_detects++; 784 } 785 #endif /* WLAN_DFS_FULL_OFFLOAD */ 786 787 #if defined(WLAN_DFS_TRUE_160MHZ_SUPPORT) && defined(WLAN_DFS_FULL_OFFLOAD) 788 void dfs_translate_radar_params(struct wlan_dfs *dfs, 789 struct radar_found_info *radar_found) 790 { 791 struct dfs_channel *curchan = dfs->dfs_curchan; 792 bool is_primary_ch_right_of_center = false; 793 794 if (!dfs_is_true_160mhz_supported(dfs)) 795 return; 796 797 if (radar_found->detector_id == dfs_get_agile_detector_id(dfs)) { 798 dfs_translate_radar_params_for_agile_chan(dfs, radar_found); 799 return; 800 } 801 802 /* Is the primary channel ( or primary 80 segment) to the right 803 * of the center of 160/165Mhz channel. 804 */ 805 if (curchan->dfs_ch_freq > curchan->dfs_ch_mhz_freq_seg2) 806 is_primary_ch_right_of_center = true; 807 808 if (WLAN_IS_CHAN_MODE_160(curchan)) { 809 if (radar_found->freq_offset > 0) { 810 /* Offset positive: Equivalent to Upper IEEE 811 * 80Mhz chans Synthesizer. 812 */ 813 if (!is_primary_ch_right_of_center) 814 radar_found->segment_id = SEG_ID_SECONDARY; 815 radar_found->freq_offset -= 816 DFS_160MHZ_SECOND_SEG_OFFSET; 817 } else { 818 /* Offset negative: Equivalent to Lower IEEE 819 * 80Mhz chans Synthesizer. 820 */ 821 if (is_primary_ch_right_of_center) 822 radar_found->segment_id = SEG_ID_SECONDARY; 823 radar_found->freq_offset += 824 DFS_160MHZ_SECOND_SEG_OFFSET; 825 } 826 } else if (WLAN_IS_CHAN_MODE_165(dfs, curchan)) { 827 /* If offset is greater than 40MHz, radar is found on the 828 * secondary segment. 829 */ 830 if (abs(radar_found->freq_offset) > 40) { 831 radar_found->segment_id = SEG_ID_SECONDARY; 832 /* Update the freq. offset with respect to the 833 * secondary segment center freq. 834 */ 835 if (is_primary_ch_right_of_center) 836 radar_found->freq_offset += 837 DFS_80P80MHZ_SECOND_SEG_OFFSET; 838 else 839 radar_found->freq_offset -= 840 DFS_80P80MHZ_SECOND_SEG_OFFSET; 841 } 842 } 843 } 844 #endif /* WLAN_DFS_TRUE_160MHZ_SUPPORT */ 845 846 /** 847 * dfs_radar_action_for_hw_mode_switch()- Radar cannot be processed when HW 848 * switch is in progress. So save the radar found parameters for 849 * future processing. 850 * @dfs: Pointer to wlan_dfs structure. 851 * @radar_found: Pointer to radar found structure. 852 * 853 * Return: QDF_STATUS 854 */ 855 static QDF_STATUS 856 dfs_radar_action_for_hw_mode_switch(struct wlan_dfs *dfs, 857 struct radar_found_info *radar_found) 858 { 859 struct radar_found_info *radar_params = NULL; 860 861 radar_params = qdf_mem_malloc(sizeof(*radar_params)); 862 if (!radar_params) 863 return QDF_STATUS_E_NOMEM; 864 865 /* If CAC timer is running, cancel it here rather than 866 * after processing to avoid handling unnecessary CAC timeouts. 867 */ 868 if (dfs->dfs_cac_timer_running) 869 dfs_cac_stop(dfs); 870 871 /* If CAC timer is to be handled after mode switch and then 872 * we receive radar, no point in handling CAC completion. 873 */ 874 if (dfs->dfs_defer_params.is_cac_completed) 875 dfs->dfs_defer_params.is_cac_completed = false; 876 qdf_mem_copy(radar_params, radar_found, sizeof(*radar_params)); 877 dfs->dfs_defer_params.radar_params = radar_params; 878 dfs->dfs_defer_params.is_radar_detected = true; 879 880 return QDF_STATUS_SUCCESS; 881 } 882 883 #ifdef CONFIG_CHAN_FREQ_API 884 uint8_t 885 dfs_find_radar_affected_channels(struct wlan_dfs *dfs, 886 struct radar_found_info *radar_found, 887 uint16_t *freq_list, 888 uint32_t freq_center) 889 { 890 uint8_t num_channels; 891 892 if (dfs->dfs_bangradar_type == DFS_BANGRADAR_FOR_ALL_SUBCHANS) 893 num_channels = 894 dfs_get_bonding_channel_without_seg_info_for_freq 895 (dfs->dfs_curchan, freq_list); 896 /* BW reduction is dependent on subchannel marking */ 897 else if ((dfs->dfs_use_nol_subchannel_marking) && 898 (!(dfs->dfs_bangradar_type) || 899 (dfs->dfs_bangradar_type == 900 DFS_BANGRADAR_FOR_SPECIFIC_SUBCHANS))) 901 num_channels = 902 dfs_find_radar_affected_subchans_for_freq(dfs, 903 radar_found, 904 freq_list, 905 freq_center); 906 else 907 num_channels = dfs_get_bonding_channels_for_freq 908 (dfs, 909 dfs->dfs_curchan, 910 radar_found->segment_id, 911 radar_found->detector_id, 912 freq_list); 913 914 return num_channels; 915 } 916 917 #if defined(QCA_SUPPORT_AGILE_DFS) || defined(ATH_SUPPORT_ZERO_CAC_DFS) || \ 918 defined(QCA_SUPPORT_ADFS_RCAC) 919 /** 920 * dfs_is_radarsource_agile() - Indicates whether the radar event is received 921 * on the agile channel. 922 * @dfs: Pointer to wlan_dfs structure. 923 * @radar_found: Pointer to radar_found_info structure. 924 * 925 * Return: QDF_STATUS 926 */ 927 static 928 bool dfs_is_radarsource_agile(struct wlan_dfs *dfs, 929 struct radar_found_info *radar_found) 930 { 931 bool is_radar_from_agile_dfs = 932 ((dfs_is_agile_precac_enabled(dfs) && 933 dfs_is_precac_timer_running(dfs)) || 934 dfs_is_agile_rcac_enabled(dfs)) && 935 (radar_found->detector_id == dfs_get_agile_detector_id(dfs)); 936 937 dfs_debug(dfs, WLAN_DEBUG_DFS_AGILE, 938 "radar on PreCAC segment: ADFS:%d", 939 is_radar_from_agile_dfs); 940 941 return is_radar_from_agile_dfs; 942 } 943 #else 944 static 945 bool dfs_is_radarsource_agile(struct wlan_dfs *dfs, 946 struct radar_found_info *radar_found) 947 { 948 return false; 949 } 950 #endif 951 952 QDF_STATUS 953 dfs_process_radar_ind(struct wlan_dfs *dfs, 954 struct radar_found_info *radar_found) 955 { 956 QDF_STATUS status; 957 958 /* Acquire a lock to avoid initiating mode switch till radar 959 * processing is completed. 960 */ 961 DFS_RADAR_MODE_SWITCH_LOCK(dfs); 962 963 if (utils_dfs_can_ignore_radar_event(dfs->dfs_pdev_obj)) { 964 DFS_RADAR_MODE_SWITCH_UNLOCK(dfs); 965 return QDF_STATUS_SUCCESS; 966 } 967 968 /* Before processing radar, check if HW mode switch is in progress. 969 * If in progress, defer the processing of radar event received till 970 * the mode switch is completed. 971 */ 972 if (dfs_is_hw_mode_switch_in_progress(dfs)) 973 status = dfs_radar_action_for_hw_mode_switch(dfs, radar_found); 974 else if (dfs_is_radarsource_agile(dfs, radar_found)) 975 status = dfs_process_radar_ind_on_agile_chan(dfs, radar_found); 976 else 977 status = dfs_process_radar_ind_on_home_chan(dfs, radar_found); 978 979 DFS_RADAR_MODE_SWITCH_UNLOCK(dfs); 980 981 return status; 982 } 983 984 QDF_STATUS 985 dfs_process_radar_ind_on_home_chan(struct wlan_dfs *dfs, 986 struct radar_found_info *radar_found) 987 { 988 bool wait_for_csa = false; 989 uint16_t freq_list[MAX_20MHZ_SUBCHANS]; 990 uint16_t nol_freq_list[MAX_20MHZ_SUBCHANS]; 991 uint8_t num_channels; 992 QDF_STATUS status = QDF_STATUS_E_FAILURE; 993 uint32_t freq_center; 994 uint32_t radarfound_freq; 995 struct dfs_channel *dfs_curchan; 996 997 dfs_curchan = dfs->dfs_curchan; 998 999 /* Check if the current channel is a non DFS channel 1000 * If the current channel is non-DFS and the radar is from Agile 1001 * Detector we need to process it since Agile Detector has a 1002 * different channel. 1003 */ 1004 if (!dfs_radar_found_event_basic_sanity(dfs, dfs_curchan)) 1005 goto exit; 1006 1007 dfs_compute_radar_found_cfreq(dfs, radar_found, &freq_center); 1008 radarfound_freq = freq_center + radar_found->freq_offset; 1009 1010 if (radar_found->segment_id == SEG_ID_SECONDARY) 1011 dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS, 1012 "Radar found on second segment.Radarfound Freq=%d MHz.Secondary Chan cfreq=%d MHz.", 1013 radarfound_freq, freq_center); 1014 else 1015 dfs_debug(NULL, WLAN_DEBUG_DFS_ALWAYS, 1016 "Radar found on channel=%d, freq=%d MHz. Primary beaconning chan:%d, freq=%d MHz.", 1017 utils_dfs_freq_to_chan(radarfound_freq), 1018 radarfound_freq, dfs_curchan->dfs_ch_ieee, 1019 dfs_curchan->dfs_ch_freq); 1020 1021 utils_dfs_deliver_event(dfs->dfs_pdev_obj, radarfound_freq, 1022 WLAN_EV_RADAR_DETECTED); 1023 1024 if (!dfs->dfs_use_nol) { 1025 if (!dfs->dfs_is_offload_enabled) { 1026 dfs_radar_disable(dfs); 1027 dfs_second_segment_radar_disable(dfs); 1028 dfs_flush_additional_pulses(dfs); 1029 } 1030 dfs_reset_bangradar(dfs); 1031 dfs_send_csa_to_current_chan(dfs); 1032 status = QDF_STATUS_SUCCESS; 1033 goto exit; 1034 } 1035 num_channels = dfs_find_radar_affected_channels(dfs, 1036 radar_found, 1037 freq_list, 1038 freq_center); 1039 1040 dfs_reset_bangradar(dfs); 1041 1042 status = dfs_radar_add_channel_list_to_nol_for_freq(dfs, 1043 freq_list, 1044 nol_freq_list, 1045 &num_channels); 1046 if (QDF_IS_STATUS_ERROR(status)) { 1047 dfs_err(dfs, WLAN_DEBUG_DFS, 1048 "radar event received on invalid channel"); 1049 goto exit; 1050 } 1051 1052 /* 1053 * If precac is running and the radar found in secondary 1054 * VHT80 mark the channel as radar and add to NOL list. 1055 * Otherwise random channel selection can choose this 1056 * channel. 1057 */ 1058 dfs_debug(dfs, WLAN_DEBUG_DFS, 1059 "found_on_second=%d is_pre=%d", 1060 dfs->is_radar_found_on_secondary_seg, 1061 dfs_is_precac_timer_running(dfs)); 1062 /* 1063 * Even if radar found on primary, we need to mark the channel as NOL 1064 * in preCAC list. The preCAC list also maintains the current CAC 1065 * channels as part of pre-cleared DFS. Hence call the API 1066 * to mark channels as NOL irrespective of preCAC being enabled or not. 1067 */ 1068 1069 dfs_debug(dfs, WLAN_DEBUG_DFS, 1070 "Radar found on dfs detector: %d", radar_found->detector_id); 1071 dfs_mark_precac_nol_for_freq(dfs, 1072 dfs->is_radar_found_on_secondary_seg, 1073 radar_found->detector_id, 1074 nol_freq_list, 1075 num_channels); 1076 1077 dfs_send_nol_ie_and_rcsa(dfs, 1078 radar_found, 1079 nol_freq_list, 1080 num_channels, 1081 &wait_for_csa); 1082 1083 if (!dfs->dfs_is_offload_enabled && 1084 dfs->is_radar_found_on_secondary_seg) { 1085 dfs_second_segment_radar_disable(dfs); 1086 dfs->is_radar_found_on_secondary_seg = 0; 1087 1088 if (dfs->is_radar_during_precac) { 1089 dfs->is_radar_during_precac = 0; 1090 goto exit; 1091 } 1092 } 1093 1094 /* 1095 * XXX TODO: the umac NOL code isn't used, but 1096 * WLAN_CHAN_DFS_RADAR still gets set. Since the umac 1097 * NOL code isn't used, that flag is never cleared. This 1098 * needs to be fixed. See EV 105776. 1099 */ 1100 if (wait_for_csa) 1101 goto exit; 1102 1103 /* 1104 * EV 129487 : We have detected radar in the channel, 1105 * stop processing PHY error data as this can cause 1106 * false detect in the new channel while channel 1107 * change is in progress. 1108 */ 1109 1110 if (!dfs->dfs_is_offload_enabled) { 1111 dfs_radar_disable(dfs); 1112 dfs_second_segment_radar_disable(dfs); 1113 /* 1114 * The radar queues were reset just after the filter match, but 1115 * the phyerror reception was not disabled. This might 1116 * cause the unwanted additional/accumulated pulses to be 1117 * detected as radar in the new channel. So, clear the radar 1118 * queues and the associated variables. 1119 */ 1120 dfs_flush_additional_pulses(dfs); 1121 } 1122 1123 dfs_mlme_mark_dfs(dfs->dfs_pdev_obj, 1124 dfs->dfs_curchan->dfs_ch_ieee, 1125 dfs->dfs_curchan->dfs_ch_freq, 1126 dfs->dfs_curchan->dfs_ch_mhz_freq_seg2, 1127 dfs->dfs_curchan->dfs_ch_flags); 1128 1129 exit: 1130 return status; 1131 } 1132 #endif 1133