1 /* 2 * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2023 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 408 * @center_freq: Center frequency of the channel width. 409 * @ch_width: Channel width. 410 * @freq_list: output array of sub-channel frequencies. 411 * 412 * Calculate bonding channel frequencies from the channel width's 413 * center frequency and channel width. It is assumed that the caller 414 * has allocated sufficient memory for @freq_list so that it can hold 415 * all the output subchannels. 416 * 417 * Return: void 418 */ 419 static void 420 dfs_calc_bonding_freqs(qdf_freq_t center_freq, 421 uint16_t ch_width, 422 uint16_t *freq_list) 423 { 424 #define CHAN_SPACING_MHZ_5G 20 425 #define SUB20CHAN_BW_MHZ_5G 20 426 uint8_t nchans = ch_width / CHAN_SPACING_MHZ_5G; 427 qdf_freq_t first_subchan_cfreq = center_freq - (ch_width / 2) + 428 (SUB20CHAN_BW_MHZ_5G / 2); 429 uint8_t i; 430 431 for (i = 0; i < nchans; ++i) 432 freq_list[i] = first_subchan_cfreq + (i * CHAN_SPACING_MHZ_5G); 433 } 434 435 /** 436 * dfs_get_20mhz_bonding_channels() - Get bonding frequency list of 20MHz 437 * channel. 438 * @center_freq: Center frequency of the 20MHz channel. 439 * @freq_list: Pointer to frequency list. 440 * 441 * Return: void 442 */ 443 static 444 void dfs_get_20mhz_bonding_channels(uint16_t center_freq, uint16_t *freq_list) 445 { 446 uint16_t chwidth = BW_20; 447 448 dfs_calc_bonding_freqs(center_freq, chwidth, freq_list); 449 } 450 451 /** 452 * dfs_get_40mhz_bonding_channels() - Get bonding frequency list of 40MHz 453 * channel. 454 * @center_freq: Center frequency of the 40MHz channel. 455 * @freq_list: Pointer to frequency list. 456 * 457 * Return: void 458 */ 459 static 460 void dfs_get_40mhz_bonding_channels(uint16_t center_freq, uint16_t *freq_list) 461 { 462 uint16_t chwidth = BW_40; 463 464 dfs_calc_bonding_freqs(center_freq, chwidth, freq_list); 465 } 466 467 /** 468 * dfs_get_80mhz_bonding_channels() - Get bonding frequency list of 80MHz 469 * channel. 470 * @center_freq: Center frequency of the 80MHz channel. 471 * @freq_list: Pointer to frequency list. 472 * 473 * Return: void 474 */ 475 static 476 void dfs_get_80mhz_bonding_channels(uint16_t center_freq, uint16_t *freq_list) 477 { 478 uint16_t chwidth = BW_80; 479 480 dfs_calc_bonding_freqs(center_freq, chwidth, freq_list); 481 } 482 483 /** 484 * dfs_get_160mhz_bonding_channels() - Get bonding frequency list of 160MHz 485 * channel. 486 * @center_freq: Center frequency of the 160MHz channel. 487 * @freq_list: Pointer to frequency list. 488 * 489 * Return: void 490 */ 491 static 492 void dfs_get_160mhz_bonding_channels(uint16_t center_freq, uint16_t *freq_list) 493 { 494 uint16_t chwidth = BW_160; 495 496 dfs_calc_bonding_freqs(center_freq, chwidth, freq_list); 497 } 498 499 /** 500 * dfs_get_320mhz_bonding_channels() - Get bonding frequency list of 320 MHz 501 * channel. 502 * @center_freq: Center frequency of the 320 MHz channel. 503 * @freq_list: Pointer to frequency list. 504 * @nchannels: Number of channels in @freq_list 505 * 506 * Return: void 507 */ 508 #ifdef WLAN_FEATURE_11BE 509 static 510 void dfs_get_320mhz_bonding_channels(uint16_t center_freq, uint16_t *freq_list, 511 uint8_t *nchannels) 512 { 513 uint16_t chwidth = 320; 514 515 /* 516 * In 5 GHz band, the 320 MHz channel is always 80 MHz punctured 517 * to the right. Therefore, it is actually a 240 MHz channel and 518 * has twelve 20 MHz subchannels. 519 */ 520 *nchannels = NUM_CHANNELS_240MHZ; 521 dfs_calc_bonding_freqs(center_freq, chwidth, freq_list); 522 } 523 #else 524 static 525 void dfs_get_320mhz_bonding_channels(uint16_t center_freq, uint16_t *freq_list, 526 uint8_t *nchannels) 527 { 528 *nchannels = 0; 529 dfs_debug(NULL, WLAN_DEBUG_DFS_ALWAYS, 530 "320MHz chan width for non 11be"); 531 } 532 #endif 533 534 /** 535 * dfs_get_bonding_channel_without_seg_info_for_freq() - Get bonding frequency 536 * list. 537 * @chan: Pointer to dfs_channel. 538 * @freq_list: Pointer to frequency list. 539 */ 540 #ifdef CONFIG_CHAN_FREQ_API 541 uint8_t 542 dfs_get_bonding_channel_without_seg_info_for_freq(struct dfs_channel *chan, 543 uint16_t *freq_list) 544 { 545 uint16_t center_freq; 546 uint8_t nchannels = 0; 547 548 center_freq = chan->dfs_ch_mhz_freq_seg1; 549 550 if (WLAN_IS_CHAN_MODE_20(chan)) { 551 nchannels = 1; 552 dfs_get_20mhz_bonding_channels(center_freq, 553 freq_list); 554 } else if (WLAN_IS_CHAN_MODE_40(chan)) { 555 nchannels = 2; 556 dfs_get_40mhz_bonding_channels(center_freq, 557 freq_list); 558 } else if (WLAN_IS_CHAN_MODE_80(chan)) { 559 nchannels = 4; 560 dfs_get_80mhz_bonding_channels(center_freq, 561 freq_list); 562 } else if (WLAN_IS_CHAN_MODE_80_80(chan)) { 563 nchannels = 8; 564 dfs_get_80mhz_bonding_channels(center_freq, 565 freq_list); 566 center_freq = chan->dfs_ch_mhz_freq_seg2; 567 dfs_get_80mhz_bonding_channels(center_freq, 568 freq_list + 4); 569 } else if (WLAN_IS_CHAN_MODE_160(chan)) { 570 nchannels = 8; 571 center_freq = chan->dfs_ch_mhz_freq_seg2; 572 dfs_get_160mhz_bonding_channels(center_freq, freq_list); 573 } else if (WLAN_IS_CHAN_MODE_320(chan)) { 574 center_freq = chan->dfs_ch_mhz_freq_seg2; 575 dfs_get_320mhz_bonding_channels(center_freq, freq_list, 576 &nchannels); 577 } 578 579 return nchannels; 580 } 581 #endif 582 583 #ifdef CONFIG_CHAN_FREQ_API 584 /** 585 * dfs_get_agile_subchans_for_curchan_160() - Get bonding frequency list of 586 * agile channels when current operating channel is 160MHz. 587 * 588 * @dfs: Pointer to DFS structure. 589 * @center_freq: Center frequency of the channel. 590 * @segment_id: Segment ID of interest. 0 for primary segment and 1 for 591 * secondary segment. 592 * @freq_list: Pointer to frequency list. 593 * @nchannels: Number of subchannel. 594 */ 595 static void 596 dfs_get_agile_subchans_for_curchan_160(struct wlan_dfs *dfs, 597 uint16_t center_freq, 598 uint32_t segment_id, 599 uint16_t *freq_list, 600 uint8_t *nchannels) 601 { 602 if (dfs->dfs_precac_chwidth == CH_WIDTH_80MHZ) { 603 /* 604 * The current operating channel is 160MHz and 605 * the agile channel is 80MHz. This can happen 606 * in HK only. 607 */ 608 *nchannels = 4; 609 dfs_get_80mhz_bonding_channels(center_freq, 610 freq_list); 611 } else if (dfs->dfs_precac_chwidth == CH_WIDTH_160MHZ) 612 /* 613 * The current operating channel is 160MHz and 614 * the agile channel is 160MHz. 615 * Pine ADFS specific. 616 */ 617 dfs_get_160mhz_bonding_channels(center_freq, 618 freq_list); 619 else if (dfs->dfs_precac_chwidth == CH_WIDTH_80P80MHZ) { 620 /* 621 * The current operating channel is 160MHz and the agile channel 622 * is 165MHz(restricted 80P80MHZ). Pine ADFS specific. 623 * If the segment id is primary segment 0, shift the center 624 * frequency 5730MHz to the center of left 80MHz segment 5690MHz 625 * and add the subchannels of the left 80MHz segment. 626 * If the segment id is secondary segment 1, shift the center 627 * frequency 5730MHz to the center of right 80MHz segment 628 * 5775MHz and add the subchannels of the right 80MHz segment. 629 */ 630 *nchannels = 4; 631 center_freq = (segment_id) ? 632 (center_freq + DFS_165MHZ_SECOND_SEG_OFFSET_RIGHT) : 633 (center_freq - DFS_165MHZ_SECOND_SEG_OFFSET_LEFT); 634 dfs_get_80mhz_bonding_channels(center_freq, 635 freq_list); 636 } 637 } 638 639 /** 640 * dfs_get_bonding_channels_for_freq() - Get bonding channel frequency. 641 * @dfs: Pointer to wlan_dfs. 642 * @curchan: Pointer to dfs_channel. 643 * @segment_id: Segment ID. 644 * @detector_id: Detector ID. 645 * @freq_list: Pointer to frequency list. 646 */ 647 uint8_t dfs_get_bonding_channels_for_freq(struct wlan_dfs *dfs, 648 struct dfs_channel *curchan, 649 uint32_t segment_id, 650 uint8_t detector_id, 651 uint16_t *freq_list) 652 { 653 uint16_t center_freq; 654 uint8_t nchannels = 0; 655 656 /* 657 * For radar in agile detector, use the center of the channel 658 * configured to the agile detector. 659 * For radar on a 160MHz home channel, use the center of 160MHz. 660 * For radar on all other bandwidths, use the center of the segment 661 * affected. 662 */ 663 if (detector_id == dfs_get_agile_detector_id(dfs)) 664 center_freq = dfs->dfs_agile_precac_freq_mhz; 665 else if (WLAN_IS_CHAN_MODE_160(curchan) || 666 WLAN_IS_CHAN_MODE_320(curchan)) 667 center_freq = curchan->dfs_ch_mhz_freq_seg2; 668 else if (!segment_id) 669 center_freq = curchan->dfs_ch_mhz_freq_seg1; 670 else 671 center_freq = curchan->dfs_ch_mhz_freq_seg2; 672 673 if (WLAN_IS_CHAN_MODE_20(curchan)) { 674 nchannels = 1; 675 dfs_get_20mhz_bonding_channels(center_freq, freq_list); 676 } else if (WLAN_IS_CHAN_MODE_40(curchan)) { 677 nchannels = 2; 678 dfs_get_40mhz_bonding_channels(center_freq, freq_list); 679 } else if (WLAN_IS_CHAN_MODE_80(curchan)) { 680 nchannels = 4; 681 dfs_get_80mhz_bonding_channels(center_freq, freq_list); 682 } else if (WLAN_IS_CHAN_MODE_160(curchan)) { 683 nchannels = 8; 684 if (detector_id == dfs_get_agile_detector_id(dfs)) 685 dfs_get_agile_subchans_for_curchan_160(dfs, 686 center_freq, 687 segment_id, 688 freq_list, 689 &nchannels); 690 else 691 dfs_get_160mhz_bonding_channels(center_freq, freq_list); 692 } else if (WLAN_IS_CHAN_MODE_320(curchan)) { 693 dfs_get_320mhz_bonding_channels(center_freq, freq_list, 694 &nchannels); 695 } else if (WLAN_IS_CHAN_MODE_80_80(curchan)) { 696 /* 697 * If the current channel's bandwidth is 80P80MHz, 698 * the corresponding agile Detector's bandwidth will be 160MHz 699 * in case of Pine ADFS. 700 */ 701 if (detector_id == dfs_get_agile_detector_id(dfs)) { 702 if (dfs->dfs_precac_chwidth == CH_WIDTH_160MHZ) { 703 nchannels = 8; 704 dfs_get_160mhz_bonding_channels(center_freq, 705 freq_list); 706 } else if (dfs->dfs_precac_chwidth == CH_WIDTH_80MHZ) { 707 nchannels = 4; 708 dfs_get_80mhz_bonding_channels(center_freq, 709 freq_list); 710 } else { 711 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, 712 "Incorrect precac width %u", 713 dfs->dfs_precac_chwidth); 714 } 715 } else { 716 /* 717 * If the radar is getting detected in 80P80MHz home 718 * channel, only the 80MHz segment that is infected with 719 * radar is of interest. The other 80MHz segment is 720 * ignored. The center frequency of the radar infected 721 * segment is dfs_ch_mhz_freq_seg1 if primary and 722 * dfs_ch_mhz_freq_seg2 in case of secondary. 723 */ 724 nchannels = 4; 725 dfs_get_80mhz_bonding_channels(center_freq, freq_list); 726 } 727 } 728 729 return nchannels; 730 } 731 #endif 732 733 void dfs_reset_bangradar(struct wlan_dfs *dfs) 734 { 735 dfs->dfs_bangradar_type = DFS_NO_BANGRADAR; 736 } 737 738 /** 739 * dfs_radar_found_event_basic_sanity() - Check if radar event is received on a 740 * DFS channel. 741 * @dfs: Pointer to wlan_dfs structure. 742 * @chan: Current channel. 743 * 744 * Return: If a radar event found on NON-DFS channel return false. Otherwise, 745 * return true. 746 */ 747 static 748 bool dfs_radar_found_event_basic_sanity(struct wlan_dfs *dfs, 749 struct dfs_channel *chan) 750 { 751 if (!chan) { 752 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, 753 "dfs->dfs_curchan is NULL"); 754 return false; 755 } 756 757 if (!(WLAN_IS_PRIMARY_OR_SECONDARY_CHAN_DFS(chan))) { 758 dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS, 759 "radar event on non-DFS chan"); 760 return false; 761 } 762 763 return true; 764 } 765 766 void dfs_send_csa_to_current_chan(struct wlan_dfs *dfs) 767 { 768 dfs->wlan_dfstest = 1; 769 dfs->wlan_dfstest_ieeechan = dfs->dfs_curchan->dfs_ch_ieee; 770 dfs->wlan_dfstesttime = 1; /* 1ms */ 771 qdf_timer_sync_cancel(&dfs->wlan_dfstesttimer); 772 qdf_timer_start(&dfs->wlan_dfstesttimer, dfs->wlan_dfstesttime); 773 } 774 775 int dfs_second_segment_radar_disable(struct wlan_dfs *dfs) 776 { 777 dfs->dfs_proc_phyerr &= ~DFS_SECOND_SEGMENT_RADAR_EN; 778 779 return 0; 780 } 781 782 #ifdef WLAN_DFS_FULL_OFFLOAD 783 void dfs_inc_num_radar(struct wlan_dfs *dfs) 784 { 785 dfs->wlan_dfs_stats.num_radar_detects++; 786 } 787 #endif /* WLAN_DFS_FULL_OFFLOAD */ 788 789 #if defined(WLAN_DFS_TRUE_160MHZ_SUPPORT) && defined(WLAN_DFS_FULL_OFFLOAD) 790 void dfs_translate_radar_params(struct wlan_dfs *dfs, 791 struct radar_found_info *radar_found) 792 { 793 struct dfs_channel *curchan = dfs->dfs_curchan; 794 bool is_primary_ch_right_of_center = false; 795 796 if (!dfs_is_true_160mhz_supported(dfs)) 797 return; 798 799 if (radar_found->detector_id == dfs_get_agile_detector_id(dfs)) { 800 dfs_translate_radar_params_for_agile_chan(dfs, radar_found); 801 return; 802 } 803 804 /* Is the primary channel ( or primary 80 segment) to the right 805 * of the center of 160/165Mhz channel. 806 */ 807 if (curchan->dfs_ch_freq > curchan->dfs_ch_mhz_freq_seg2) 808 is_primary_ch_right_of_center = true; 809 810 if (WLAN_IS_CHAN_MODE_160(curchan)) { 811 if (radar_found->freq_offset > 0) { 812 /* Offset positive: Equivalent to Upper IEEE 813 * 80Mhz chans Synthesizer. 814 */ 815 if (!is_primary_ch_right_of_center) 816 radar_found->segment_id = SEG_ID_SECONDARY; 817 radar_found->freq_offset -= 818 DFS_160MHZ_SECOND_SEG_OFFSET; 819 } else { 820 /* Offset negative: Equivalent to Lower IEEE 821 * 80Mhz chans Synthesizer. 822 */ 823 if (is_primary_ch_right_of_center) 824 radar_found->segment_id = SEG_ID_SECONDARY; 825 radar_found->freq_offset += 826 DFS_160MHZ_SECOND_SEG_OFFSET; 827 } 828 } else if (WLAN_IS_CHAN_MODE_165(dfs, curchan)) { 829 /* If offset is greater than 40MHz, radar is found on the 830 * secondary segment. 831 */ 832 if (abs(radar_found->freq_offset) > 40) { 833 radar_found->segment_id = SEG_ID_SECONDARY; 834 /* Update the freq. offset with respect to the 835 * secondary segment center freq. 836 */ 837 if (is_primary_ch_right_of_center) 838 radar_found->freq_offset += 839 DFS_80P80MHZ_SECOND_SEG_OFFSET; 840 else 841 radar_found->freq_offset -= 842 DFS_80P80MHZ_SECOND_SEG_OFFSET; 843 } 844 } 845 } 846 #endif /* WLAN_DFS_TRUE_160MHZ_SUPPORT */ 847 848 /** 849 * dfs_radar_action_for_hw_mode_switch()- Radar cannot be processed when HW 850 * switch is in progress. So save the radar found parameters for 851 * future processing. 852 * @dfs: Pointer to wlan_dfs structure. 853 * @radar_found: Pointer to radar found structure. 854 * 855 * Return: QDF_STATUS 856 */ 857 static QDF_STATUS 858 dfs_radar_action_for_hw_mode_switch(struct wlan_dfs *dfs, 859 struct radar_found_info *radar_found) 860 { 861 struct radar_found_info *radar_params = NULL; 862 863 radar_params = qdf_mem_malloc(sizeof(*radar_params)); 864 if (!radar_params) 865 return QDF_STATUS_E_NOMEM; 866 867 /* If CAC timer is running, cancel it here rather than 868 * after processing to avoid handling unnecessary CAC timeouts. 869 */ 870 if (dfs->dfs_cac_timer_running) 871 dfs_cac_stop(dfs); 872 873 /* If CAC timer is to be handled after mode switch and then 874 * we receive radar, no point in handling CAC completion. 875 */ 876 if (dfs->dfs_defer_params.is_cac_completed) 877 dfs->dfs_defer_params.is_cac_completed = false; 878 qdf_mem_copy(radar_params, radar_found, sizeof(*radar_params)); 879 dfs->dfs_defer_params.radar_params = radar_params; 880 dfs->dfs_defer_params.is_radar_detected = true; 881 882 return QDF_STATUS_SUCCESS; 883 } 884 885 #ifdef CONFIG_CHAN_FREQ_API 886 uint8_t 887 dfs_find_radar_affected_channels(struct wlan_dfs *dfs, 888 struct radar_found_info *radar_found, 889 uint16_t *freq_list, 890 uint32_t freq_center) 891 { 892 uint8_t num_channels; 893 894 if (dfs->dfs_bangradar_type == DFS_BANGRADAR_FOR_ALL_SUBCHANS) 895 num_channels = 896 dfs_get_bonding_channel_without_seg_info_for_freq 897 (dfs->dfs_curchan, freq_list); 898 /* BW reduction is dependent on subchannel marking */ 899 else if ((dfs->dfs_use_nol_subchannel_marking) && 900 (!(dfs->dfs_bangradar_type) || 901 (dfs->dfs_bangradar_type == 902 DFS_BANGRADAR_FOR_SPECIFIC_SUBCHANS))) 903 num_channels = 904 dfs_find_radar_affected_subchans_for_freq(dfs, 905 radar_found, 906 freq_list, 907 freq_center); 908 else 909 num_channels = dfs_get_bonding_channels_for_freq 910 (dfs, 911 dfs->dfs_curchan, 912 radar_found->segment_id, 913 radar_found->detector_id, 914 freq_list); 915 916 return num_channels; 917 } 918 919 #if defined(QCA_SUPPORT_AGILE_DFS) || defined(ATH_SUPPORT_ZERO_CAC_DFS) || \ 920 defined(QCA_SUPPORT_ADFS_RCAC) 921 /** 922 * dfs_is_radarsource_agile() - Indicates whether the radar event is received 923 * on the agile channel. 924 * @dfs: Pointer to wlan_dfs structure. 925 * @radar_found: Pointer to radar_found_info structure. 926 * 927 * Return: QDF_STATUS 928 */ 929 static 930 bool dfs_is_radarsource_agile(struct wlan_dfs *dfs, 931 struct radar_found_info *radar_found) 932 { 933 bool is_radar_from_agile_dfs = 934 ((dfs_is_agile_precac_enabled(dfs) && 935 dfs_is_precac_timer_running(dfs)) || 936 dfs_is_agile_rcac_enabled(dfs)) && 937 (radar_found->detector_id == dfs_get_agile_detector_id(dfs)); 938 939 dfs_debug(dfs, WLAN_DEBUG_DFS_AGILE, 940 "radar on PreCAC segment: ADFS:%d", 941 is_radar_from_agile_dfs); 942 943 return is_radar_from_agile_dfs; 944 } 945 #else 946 static 947 bool dfs_is_radarsource_agile(struct wlan_dfs *dfs, 948 struct radar_found_info *radar_found) 949 { 950 return false; 951 } 952 #endif 953 954 #ifdef QCA_DFS_BW_PUNCTURE 955 uint16_t dfs_generate_radar_bitmap(struct wlan_dfs *dfs, 956 uint16_t *radar_freq_list, 957 uint8_t num_radar_channels) 958 { 959 uint8_t n_cur_channels; 960 uint16_t dfs_radar_bitmap = 0x0; 961 uint16_t bits = 0x1; 962 uint8_t i, j; 963 uint16_t cur_freq_list[MAX_20MHZ_SUBCHANS] = {0}; 964 965 n_cur_channels = 966 dfs_get_bonding_channel_without_seg_info_for_freq(dfs->dfs_curchan, 967 cur_freq_list); 968 969 for (i = 0; i < n_cur_channels; i++) { 970 for (j = 0; j < num_radar_channels; j++) { 971 if (cur_freq_list[i] == radar_freq_list[j]) { 972 dfs_radar_bitmap |= bits; 973 break; 974 } 975 } 976 bits <<= 1; 977 } 978 979 return dfs_radar_bitmap; 980 } 981 #endif 982 983 QDF_STATUS 984 dfs_process_radar_ind(struct wlan_dfs *dfs, 985 struct radar_found_info *radar_found) 986 { 987 QDF_STATUS status; 988 989 /* Acquire a lock to avoid initiating mode switch till radar 990 * processing is completed. 991 */ 992 DFS_RADAR_MODE_SWITCH_LOCK(dfs); 993 994 if (utils_dfs_can_ignore_radar_event(dfs->dfs_pdev_obj)) { 995 DFS_RADAR_MODE_SWITCH_UNLOCK(dfs); 996 return QDF_STATUS_SUCCESS; 997 } 998 999 /* Before processing radar, check if HW mode switch is in progress. 1000 * If in progress, defer the processing of radar event received till 1001 * the mode switch is completed. 1002 */ 1003 if (dfs_is_hw_mode_switch_in_progress(dfs)) 1004 status = dfs_radar_action_for_hw_mode_switch(dfs, radar_found); 1005 else if (dfs_is_radarsource_agile(dfs, radar_found)) 1006 status = dfs_process_radar_ind_on_agile_chan(dfs, radar_found); 1007 else 1008 status = dfs_process_radar_ind_on_home_chan(dfs, radar_found); 1009 1010 DFS_RADAR_MODE_SWITCH_UNLOCK(dfs); 1011 1012 return status; 1013 } 1014 1015 #if defined(QCA_DFS_BW_PUNCTURE) && defined(WLAN_FEATURE_11BE) 1016 /** 1017 * dfs_is_ignore_radar_for_punctured_chans() - Store the radar bitmap and check 1018 * if radar is found in already 1019 * punctured channel and ignore the 1020 * radar. 1021 * @dfs: Wlan_dfs structure 1022 * @dfs_radar_bitmap: Variable to store radar bitmap. 1023 * @freq_list: output array of sub-channel frequencies. 1024 * @num_channels: Number of sub-channels in target DFS channel. 1025 * 1026 * Return: If radar is found on punctured channel then return true. 1027 * Else return false. 1028 */ 1029 static 1030 bool dfs_is_ignore_radar_for_punctured_chans(struct wlan_dfs *dfs, 1031 uint16_t *dfs_radar_bitmap, 1032 uint16_t *freq_list, 1033 uint8_t num_channels) 1034 { 1035 uint16_t dfs_punc_pattern = dfs->dfs_curchan->dfs_ch_punc_pattern; 1036 1037 *dfs_radar_bitmap = dfs_generate_radar_bitmap(dfs, 1038 freq_list, 1039 num_channels); 1040 *dfs_radar_bitmap |= dfs_punc_pattern; 1041 1042 if (*dfs_radar_bitmap == dfs_punc_pattern) { 1043 dfs_err(dfs, WLAN_DEBUG_DFS, 1044 "radar event received on invalid channel"); 1045 return true; 1046 } 1047 1048 return false; 1049 } 1050 #else 1051 static 1052 bool dfs_is_ignore_radar_for_punctured_chans(struct wlan_dfs *dfs, 1053 uint16_t *dfs_radar_bitmap, 1054 uint16_t *freq_list, 1055 uint8_t num_channels) 1056 { 1057 return false; 1058 } 1059 #endif /* QCA_DFS_BW_PUNCTURE */ 1060 1061 QDF_STATUS 1062 dfs_process_radar_ind_on_home_chan(struct wlan_dfs *dfs, 1063 struct radar_found_info *radar_found) 1064 { 1065 bool wait_for_csa = false; 1066 uint16_t freq_list[MAX_20MHZ_SUBCHANS]; 1067 uint16_t nol_freq_list[MAX_20MHZ_SUBCHANS]; 1068 uint8_t num_channels; 1069 QDF_STATUS status = QDF_STATUS_E_FAILURE; 1070 uint32_t freq_center; 1071 uint32_t radarfound_freq; 1072 struct dfs_channel *dfs_curchan; 1073 uint16_t dfs_radar_bitmap = 0; 1074 1075 dfs_curchan = dfs->dfs_curchan; 1076 1077 /* Check if the current channel is a non DFS channel 1078 * If the current channel is non-DFS and the radar is from Agile 1079 * Detector we need to process it since Agile Detector has a 1080 * different channel. 1081 */ 1082 if (!dfs_radar_found_event_basic_sanity(dfs, dfs_curchan)) 1083 goto exit; 1084 1085 dfs_compute_radar_found_cfreq(dfs, radar_found, &freq_center); 1086 radarfound_freq = freq_center + radar_found->freq_offset; 1087 1088 if (radar_found->segment_id == SEG_ID_SECONDARY) 1089 dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS, 1090 "Radar found on second segment.Radarfound Freq=%d MHz.Secondary Chan cfreq=%d MHz.", 1091 radarfound_freq, freq_center); 1092 else 1093 dfs_debug(NULL, WLAN_DEBUG_DFS_ALWAYS, 1094 "Radar found on channel=%d, freq=%d MHz. Primary beaconning chan:%d, freq=%d MHz.", 1095 utils_dfs_freq_to_chan(radarfound_freq), 1096 radarfound_freq, dfs_curchan->dfs_ch_ieee, 1097 dfs_curchan->dfs_ch_freq); 1098 1099 num_channels = dfs_find_radar_affected_channels(dfs, 1100 radar_found, 1101 freq_list, 1102 freq_center); 1103 1104 if (dfs->dfs_use_puncture && 1105 dfs_is_ignore_radar_for_punctured_chans(dfs, 1106 &dfs_radar_bitmap, 1107 freq_list, 1108 num_channels)) 1109 goto exit; 1110 1111 if (!dfs->dfs_use_nol) { 1112 if (!dfs->dfs_is_offload_enabled) 1113 dfs_disable_radar_and_flush_pulses(dfs); 1114 dfs_reset_bangradar(dfs); 1115 dfs_send_csa_to_current_chan(dfs); 1116 status = QDF_STATUS_SUCCESS; 1117 goto exit; 1118 } 1119 1120 dfs_reset_bangradar(dfs); 1121 1122 status = dfs_radar_add_channel_list_to_nol_for_freq(dfs, 1123 freq_list, 1124 nol_freq_list, 1125 &num_channels); 1126 if (QDF_IS_STATUS_ERROR(status)) { 1127 dfs_err(dfs, WLAN_DEBUG_DFS, 1128 "radar event received on invalid channel"); 1129 goto exit; 1130 } 1131 1132 /* 1133 * If precac is running and the radar found in secondary 1134 * VHT80 mark the channel as radar and add to NOL list. 1135 * Otherwise random channel selection can choose this 1136 * channel. 1137 */ 1138 dfs_debug(dfs, WLAN_DEBUG_DFS, 1139 "found_on_second=%d is_pre=%d", 1140 dfs->is_radar_found_on_secondary_seg, 1141 dfs_is_precac_timer_running(dfs)); 1142 /* 1143 * Even if radar found on primary, we need to mark the channel as NOL 1144 * in preCAC list. The preCAC list also maintains the current CAC 1145 * channels as part of pre-cleared DFS. Hence call the API 1146 * to mark channels as NOL irrespective of preCAC being enabled or not. 1147 */ 1148 1149 dfs_debug(dfs, WLAN_DEBUG_DFS, 1150 "Radar found on dfs detector: %d", radar_found->detector_id); 1151 dfs_mark_precac_nol_for_freq(dfs, 1152 dfs->is_radar_found_on_secondary_seg, 1153 radar_found->detector_id, 1154 nol_freq_list, 1155 num_channels); 1156 1157 dfs_send_nol_ie_and_rcsa(dfs, 1158 radar_found, 1159 nol_freq_list, 1160 num_channels, 1161 &wait_for_csa); 1162 1163 if (!dfs->dfs_is_offload_enabled && 1164 dfs->is_radar_found_on_secondary_seg) { 1165 dfs_second_segment_radar_disable(dfs); 1166 dfs->is_radar_found_on_secondary_seg = 0; 1167 1168 if (dfs->is_radar_during_precac) { 1169 dfs->is_radar_during_precac = 0; 1170 goto exit; 1171 } 1172 } 1173 1174 /* 1175 * XXX TODO: the umac NOL code isn't used, but 1176 * WLAN_CHAN_DFS_RADAR still gets set. Since the umac 1177 * NOL code isn't used, that flag is never cleared. This 1178 * needs to be fixed. See EV 105776. 1179 */ 1180 if (wait_for_csa) 1181 goto exit; 1182 1183 /* 1184 * EV 129487 : We have detected radar in the channel, 1185 * stop processing PHY error data as this can cause 1186 * false detect in the new channel while channel 1187 * change is in progress. 1188 */ 1189 1190 if (!dfs->dfs_is_offload_enabled) { 1191 /* 1192 * The radar queues were reset just after the filter match, but 1193 * the phyerror reception was not disabled. This might 1194 * cause the unwanted additional/accumulated pulses to be 1195 * detected as radar in the new channel. So, clear the radar 1196 * queues and the associated variables. 1197 */ 1198 dfs_disable_radar_and_flush_pulses(dfs); 1199 } 1200 1201 dfs_mlme_mark_dfs(dfs->dfs_pdev_obj, 1202 dfs->dfs_curchan->dfs_ch_ieee, 1203 dfs->dfs_curchan->dfs_ch_freq, 1204 dfs->dfs_curchan->dfs_ch_mhz_freq_seg2, 1205 dfs->dfs_curchan->dfs_ch_flags, 1206 dfs_radar_bitmap); 1207 1208 exit: 1209 if (QDF_IS_STATUS_SUCCESS(status)) 1210 utils_dfs_deliver_event(dfs->dfs_pdev_obj, radarfound_freq, 1211 WLAN_EV_RADAR_DETECTED); 1212 1213 return status; 1214 } 1215 #endif 1216