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