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