1 /* 2 * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting 4 * All rights reserved. 5 * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 /** 29 * DOC: This file has the functions related to DFS CAC. 30 */ 31 32 #include "../dfs_channel.h" 33 #include "../dfs_zero_cac.h" 34 #include <wlan_objmgr_vdev_obj.h> 35 #include "wlan_dfs_utils_api.h" 36 #include "wlan_dfs_mlme_api.h" 37 #include "../dfs_internal.h" 38 #include "../dfs_process_radar_found_ind.h" 39 40 #define IS_CHANNEL_WEATHER_RADAR(freq) ((freq >= 5600) && (freq <= 5650)) 41 #define ADJACENT_WEATHER_RADAR_CHANNEL 5580 42 #define CH100_START_FREQ 5490 43 #define CH100 100 44 45 /* 46 * dfs_cac_valid_timeout() - Timeout function for dfs_cac_valid_timer 47 * cac_valid bit will be reset in this function. 48 * 49 * NB: not using kernel-doc format since the kernel-doc script doesn't 50 * handle the os_timer_func() macro 51 */ 52 static os_timer_func(dfs_cac_valid_timeout) 53 { 54 struct wlan_dfs *dfs = NULL; 55 56 OS_GET_TIMER_ARG(dfs, struct wlan_dfs *); 57 dfs->dfs_cac_valid = 0; 58 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, ": Timed out!!"); 59 } 60 61 /** 62 * dfs_clear_cac_started_chan() - Clear dfs cac started channel. 63 * @dfs: Pointer to wlan_dfs structure. 64 */ 65 void dfs_clear_cac_started_chan(struct wlan_dfs *dfs) 66 { 67 qdf_mem_zero(&dfs->dfs_cac_started_chan, 68 sizeof(dfs->dfs_cac_started_chan)); 69 } 70 71 static void dfs_clear_nol_history_for_curchan(struct wlan_dfs *dfs) 72 { 73 struct dfs_channel *chan = dfs->dfs_curchan; 74 uint16_t sub_channels[MAX_20MHZ_SUBCHANS]; 75 uint8_t num_subchs; 76 77 num_subchs = dfs_get_bonding_channel_without_seg_info_for_freq( 78 chan, sub_channels); 79 80 if (dfs->dfs_is_stadfs_enabled) 81 if (dfs_mlme_is_opmode_sta(dfs->dfs_pdev_obj)) 82 utils_dfs_reg_update_nol_history_chan_for_freq( 83 dfs->dfs_pdev_obj, sub_channels, 84 num_subchs, DFS_NOL_HISTORY_RESET); 85 } 86 87 void dfs_process_cac_completion(struct wlan_dfs *dfs) 88 { 89 enum phy_ch_width ch_width = CH_WIDTH_INVALID; 90 uint16_t primary_chan_freq = 0, sec_chan_freq = 0; 91 struct dfs_channel *dfs_curchan; 92 93 dfs->dfs_cac_timer_running = 0; 94 dfs_curchan = dfs->dfs_curchan; 95 96 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "cac expired, chan %d cur time %d", 97 dfs->dfs_curchan->dfs_ch_freq, 98 (qdf_system_ticks_to_msecs(qdf_system_ticks()) / 1000)); 99 100 /* 101 * When radar is detected during a CAC we are woken up prematurely to 102 * switch to a new channel. Check the channel to decide how to act. 103 */ 104 if (WLAN_IS_CHAN_RADAR(dfs, dfs->dfs_curchan)) { 105 dfs_mlme_mark_dfs(dfs->dfs_pdev_obj, 106 dfs_curchan->dfs_ch_ieee, 107 dfs_curchan->dfs_ch_freq, 108 dfs_curchan->dfs_ch_mhz_freq_seg2, 109 dfs_curchan->dfs_ch_flags, 110 0); 111 dfs_debug(dfs, WLAN_DEBUG_DFS, 112 "CAC timer on chan %u (%u MHz) stopped due to radar", 113 dfs_curchan->dfs_ch_ieee, 114 dfs_curchan->dfs_ch_freq); 115 } else { 116 dfs_debug(dfs, WLAN_DEBUG_DFS, 117 "CAC timer on channel %u (%u MHz) expired;" 118 "no radar detected", 119 dfs_curchan->dfs_ch_ieee, 120 dfs_curchan->dfs_ch_freq); 121 122 /* On CAC completion, set the bit 'cac_valid'. 123 * CAC will not be re-done if this bit is reset. 124 * The flag will be reset when dfs_cac_valid_timer 125 * timesout. 126 */ 127 if (dfs->dfs_cac_valid_time) { 128 dfs->dfs_cac_valid = 1; 129 qdf_timer_mod(&dfs->dfs_cac_valid_timer, 130 dfs->dfs_cac_valid_time * 1000); 131 } 132 133 dfs_find_curchwidth_and_center_chan_for_freq(dfs, 134 &ch_width, 135 &primary_chan_freq, 136 &sec_chan_freq); 137 138 /* ETSI allows the driver to cache the CAC ( Once CAC done, 139 * it can be used in future). 140 * Therefore mark the current channel CAC done. 141 */ 142 if (utils_get_dfsdomain(dfs->dfs_pdev_obj) == DFS_ETSI_DOMAIN) 143 dfs_mark_precac_done_for_freq(dfs, 144 primary_chan_freq, 145 sec_chan_freq, 146 ch_width); 147 } 148 149 dfs_clear_cac_started_chan(dfs); 150 151 /* Clear NOL history for current channel on successful CAC completion */ 152 dfs_clear_nol_history_for_curchan(dfs); 153 /* Iterate over the nodes, processing the CAC completion event. */ 154 dfs_mlme_proc_cac(dfs->dfs_pdev_obj, 0); 155 156 /* Send a CAC timeout, VAP up event to user space */ 157 dfs_mlme_deliver_event_up_after_cac(dfs->dfs_pdev_obj); 158 159 if (dfs->dfs_defer_precac_channel_change == 1) { 160 dfs_mlme_channel_change_by_precac(dfs->dfs_pdev_obj); 161 dfs->dfs_defer_precac_channel_change = 0; 162 } 163 } 164 165 /** 166 * dfs_cac_timeout() - DFS cactimeout function. 167 * @arg: Container of dfs object. 168 * 169 * Sets dfs_cac_timer_running to 0 and dfs_cac_valid_timer. 170 */ 171 #ifdef CONFIG_CHAN_FREQ_API 172 static enum qdf_hrtimer_restart_status 173 dfs_cac_timeout(qdf_hrtimer_data_t *arg) 174 { 175 struct wlan_dfs *dfs; 176 177 dfs = container_of(arg, struct wlan_dfs, dfs_cac_timer); 178 179 if (dfs_is_hw_mode_switch_in_progress(dfs)) 180 dfs->dfs_defer_params.is_cac_completed = true; 181 else 182 dfs_process_cac_completion(dfs); 183 184 return QDF_HRTIMER_NORESTART; 185 } 186 #endif 187 188 #ifdef QCA_SUPPORT_DFS_CAC 189 void dfs_cac_timer_attach(struct wlan_dfs *dfs) 190 { 191 dfs->dfs_cac_timeout_override = -1; 192 dfs->wlan_dfs_cac_time = WLAN_DFS_WAIT_MS; 193 qdf_hrtimer_init(&dfs->dfs_cac_timer, 194 dfs_cac_timeout, 195 QDF_CLOCK_MONOTONIC, 196 QDF_HRTIMER_MODE_REL, 197 QDF_CONTEXT_TASKLET); 198 qdf_timer_init(NULL, 199 &(dfs->dfs_cac_valid_timer), 200 dfs_cac_valid_timeout, 201 (void *)(dfs), 202 QDF_TIMER_TYPE_WAKE_APPS); 203 } 204 205 void dfs_cac_timer_reset(struct wlan_dfs *dfs) 206 { 207 qdf_hrtimer_cancel(&dfs->dfs_cac_timer); 208 dfs_get_override_cac_timeout(dfs, 209 &(dfs->dfs_cac_timeout_override)); 210 dfs_clear_cac_started_chan(dfs); 211 } 212 213 void dfs_cac_timer_detach(struct wlan_dfs *dfs) 214 { 215 qdf_hrtimer_kill(&dfs->dfs_cac_timer); 216 qdf_timer_free(&dfs->dfs_cac_valid_timer); 217 dfs->dfs_cac_valid = 0; 218 } 219 220 int dfs_is_ap_cac_timer_running(struct wlan_dfs *dfs) 221 { 222 return dfs->dfs_cac_timer_running; 223 } 224 225 #ifdef CONFIG_CHAN_FREQ_API 226 void dfs_start_cac_timer(struct wlan_dfs *dfs) 227 { 228 int cac_timeout = 0; 229 struct dfs_channel *chan = dfs->dfs_curchan; 230 231 cac_timeout = 232 dfs_mlme_get_cac_timeout_for_freq(dfs->dfs_pdev_obj, 233 chan->dfs_ch_freq, 234 chan->dfs_ch_mhz_freq_seg2, 235 chan->dfs_ch_flags); 236 237 dfs->dfs_cac_started_chan = *chan; 238 239 dfs_deliver_cac_state_events(dfs); 240 dfs_debug(dfs, WLAN_DEBUG_DFS, 241 "chan = %d cfreq2 = %d timeout = %d sec, curr_time = %d sec", 242 chan->dfs_ch_ieee, chan->dfs_ch_vhtop_ch_freq_seg2, 243 cac_timeout, 244 qdf_system_ticks_to_msecs(qdf_system_ticks()) / 1000); 245 246 qdf_hrtimer_start(&dfs->dfs_cac_timer, 247 qdf_time_ms_to_ktime(cac_timeout * 1000), 248 QDF_HRTIMER_MODE_REL); 249 dfs->dfs_cac_aborted = 0; 250 } 251 #endif 252 253 void dfs_cancel_cac_timer(struct wlan_dfs *dfs) 254 { 255 qdf_hrtimer_cancel(&dfs->dfs_cac_timer); 256 dfs_clear_cac_started_chan(dfs); 257 } 258 259 void dfs_send_dfs_events_for_chan(struct wlan_dfs *dfs, 260 struct dfs_channel *chan, 261 enum WLAN_DFS_EVENTS event) 262 { 263 uint8_t nchannels, i; 264 qdf_freq_t freq_list[MAX_20MHZ_SUBCHANS]; 265 266 nchannels = 267 dfs_get_bonding_channel_without_seg_info_for_freq(chan, 268 freq_list); 269 for (i = 0; i < nchannels; i++) 270 utils_dfs_deliver_event(dfs->dfs_pdev_obj, 271 freq_list[i], 272 event); 273 } 274 275 void dfs_cac_stop(struct wlan_dfs *dfs) 276 { 277 uint32_t phyerr; 278 struct dfs_channel *chan; 279 280 chan = &dfs->dfs_cac_started_chan; 281 dfs_get_debug_info(dfs, (void *)&phyerr); 282 dfs_debug(dfs, WLAN_DEBUG_DFS, 283 "Stopping CAC Timer %d procphyerr 0x%08x", 284 dfs->dfs_curchan->dfs_ch_freq, phyerr); 285 qdf_hrtimer_cancel(&dfs->dfs_cac_timer); 286 287 dfs_send_dfs_events_for_chan(dfs, chan, WLAN_EV_CAC_RESET); 288 289 if (dfs->dfs_cac_timer_running) 290 dfs->dfs_cac_aborted = 1; 291 dfs_clear_cac_started_chan(dfs); 292 dfs->dfs_cac_timer_running = 0; 293 } 294 295 void dfs_stacac_stop(struct wlan_dfs *dfs) 296 { 297 uint32_t phyerr; 298 299 dfs_get_debug_info(dfs, (void *)&phyerr); 300 dfs_debug(dfs, WLAN_DEBUG_DFS, 301 "Stopping STA CAC Timer %d procphyerr 0x%08x", 302 dfs->dfs_curchan->dfs_ch_freq, phyerr); 303 dfs_clear_cac_started_chan(dfs); 304 } 305 306 int dfs_override_cac_timeout(struct wlan_dfs *dfs, int cac_timeout) 307 { 308 if (!dfs) 309 return -EIO; 310 311 dfs->dfs_cac_timeout_override = cac_timeout; 312 dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "CAC timeout is now %s %d", 313 (cac_timeout == -1) ? "default" : "overridden", 314 cac_timeout); 315 316 return 0; 317 } 318 319 int dfs_get_override_cac_timeout(struct wlan_dfs *dfs, int *cac_timeout) 320 { 321 if (!dfs) 322 return -EIO; 323 324 (*cac_timeout) = dfs->dfs_cac_timeout_override; 325 326 return 0; 327 } 328 329 #ifdef CONFIG_CHAN_FREQ_API 330 void dfs_cac_valid_reset_for_freq(struct wlan_dfs *dfs, 331 uint16_t prevchan_freq, 332 uint32_t prevchan_flags) 333 { 334 if (dfs->dfs_cac_valid_time) { 335 if ((prevchan_freq != dfs->dfs_curchan->dfs_ch_freq) || 336 (prevchan_flags != dfs->dfs_curchan->dfs_ch_flags)) { 337 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, 338 "Cancelling timer & clearing cac_valid"); 339 qdf_timer_stop(&dfs->dfs_cac_valid_timer); 340 dfs->dfs_cac_valid = 0; 341 } 342 } 343 } 344 #endif 345 #endif 346 347 #ifdef CONFIG_CHAN_FREQ_API 348 bool 349 dfs_is_subset_channel_for_freq(uint16_t *old_subchans_freq, 350 uint8_t old_n_chans, 351 uint16_t *new_subchans_freq, 352 uint8_t new_n_chans) 353 { 354 bool is_found; 355 int i, j; 356 357 if (!new_n_chans) 358 return true; 359 360 if (new_n_chans > old_n_chans) 361 return false; 362 363 for (i = 0; i < new_n_chans; i++) { 364 is_found = false; 365 for (j = 0; j < old_n_chans; j++) { 366 if (new_subchans_freq[i] == old_subchans_freq[j]) { 367 is_found = true; 368 break; 369 } 370 } 371 372 /* If new_subchans[i] is not found in old_subchans, then, 373 * new_chan is not subset of old_chan. 374 */ 375 if (!is_found) 376 break; 377 } 378 379 return is_found; 380 } 381 #endif 382 383 #ifdef CONFIG_CHAN_FREQ_API 384 uint8_t 385 dfs_find_dfs_sub_channels_for_freq(struct wlan_dfs *dfs, 386 struct dfs_channel *chan, 387 uint16_t *subchan_arr) 388 { 389 if (WLAN_IS_CHAN_MODE_160(chan) || WLAN_IS_CHAN_MODE_80_80(chan)) { 390 if (WLAN_IS_CHAN_DFS(chan) && WLAN_IS_CHAN_DFS_CFREQ2(chan)) 391 return dfs_get_bonding_channel_without_seg_info_for_freq 392 (chan, subchan_arr); 393 if (WLAN_IS_CHAN_DFS(chan)) 394 return dfs_get_bonding_channels_for_freq(dfs, 395 chan, 396 SEG_ID_PRIMARY, 397 DETECTOR_ID_0, 398 subchan_arr); 399 if (WLAN_IS_CHAN_DFS_CFREQ2(chan)) 400 return dfs_get_bonding_channels_for_freq 401 (dfs, chan, SEG_ID_SECONDARY, 402 DETECTOR_ID_0, subchan_arr); 403 /* All channels in 160/80_80 BW are non DFS, return 0 404 * as number of subchannels 405 */ 406 return 0; 407 } else if (WLAN_IS_CHAN_DFS(chan)) { 408 return dfs_get_bonding_channel_without_seg_info_for_freq 409 (chan, subchan_arr); 410 } 411 /* All channels are non DFS, return 0 as number of subchannels*/ 412 return 0; 413 } 414 #endif 415 416 #ifdef CONFIG_CHAN_FREQ_API 417 bool 418 dfs_is_new_chan_subset_of_old_chan(struct wlan_dfs *dfs, 419 struct dfs_channel *new_chan, 420 struct dfs_channel *old_chan) 421 { 422 uint16_t new_subchans[MAX_20MHZ_SUBCHANS]; 423 uint16_t old_subchans[MAX_20MHZ_SUBCHANS]; 424 uint8_t n_new_subchans = 0; 425 uint8_t n_old_subchans = 0; 426 427 /* Given channel is the old channel. i.e. The channel which 428 * should have the new channel as subset. 429 */ 430 n_old_subchans = dfs_find_dfs_sub_channels_for_freq(dfs, old_chan, 431 old_subchans); 432 /* cur_chan is the new channel to be check if subset of old channel */ 433 n_new_subchans = dfs_find_dfs_sub_channels_for_freq(dfs, new_chan, 434 new_subchans); 435 436 return dfs_is_subset_channel_for_freq(old_subchans, 437 n_old_subchans, 438 new_subchans, 439 n_new_subchans); 440 } 441 #endif 442 443 #ifdef QCA_SUPPORT_DFS_CAC 444 bool dfs_is_cac_required(struct wlan_dfs *dfs, 445 struct dfs_channel *cur_chan, 446 struct dfs_channel *prev_chan, 447 bool *continue_current_cac, 448 bool is_vap_restart) 449 { 450 struct dfs_channel *cac_started_chan = &dfs->dfs_cac_started_chan; 451 452 if (!WLAN_IS_PRIMARY_OR_SECONDARY_CHAN_DFS(cur_chan)) { 453 dfs_debug(dfs, WLAN_DEBUG_DFS, "Skip CAC on non-DFS channel"); 454 return false; 455 } 456 457 if (dfs->dfs_ignore_dfs || dfs->dfs_cac_valid || dfs->dfs_ignore_cac) { 458 dfs_debug(dfs, WLAN_DEBUG_DFS, 459 "Skip CAC, ignore_dfs = %d cac_valid = %d ignore_cac = %d", 460 dfs->dfs_ignore_dfs, dfs->dfs_cac_valid, 461 dfs->dfs_ignore_cac); 462 return false; 463 } 464 465 /* In case of RCAC, check if CAC is completed only on the RCAC channel 466 * and do not check the CAC info on current operating channel. 467 */ 468 if (dfs_is_agile_rcac_enabled(dfs) && 469 dfs_is_rcac_cac_done(dfs, cur_chan, prev_chan)) 470 return false; 471 472 /* If the channel has completed PRE-CAC then CAC can be skipped here. */ 473 if (dfs_is_precac_done(dfs, cur_chan)) { 474 dfs_debug(dfs, WLAN_DEBUG_DFS, 475 "PRE-CAC already done on this channel %d", 476 cur_chan->dfs_ch_ieee); 477 return false; 478 } 479 480 if (dfs_is_ap_cac_timer_running(dfs)) { 481 /* Check if we should continue the existing CAC or 482 * cancel the existing CAC. 483 * For example: - if an existing VAP(0) is already in 484 * DFS wait state (which means the radio(wifi) is 485 * running the CAC) and it is in channel A and another 486 * VAP(1) comes up in the same channel then instead of 487 * cancelling the CAC we can let the CAC continue. 488 */ 489 if (dfs_is_new_chan_subset_of_old_chan(dfs, 490 cur_chan, 491 cac_started_chan)) { 492 if (continue_current_cac) 493 *continue_current_cac = true; 494 } else { 495 /* New CAC is needed, cancel the running CAC 496 * timer. 497 * 1) When AP is in DFS_WAIT state and it is in 498 * channel A and user restarts the AP vap in 499 * channel B, then cancel the running CAC in 500 * channel A and start new CAC in channel B. 501 * 502 * 2) When AP detects the RADAR during CAC in 503 * channel A, it cancels the running CAC and 504 * tries to find channel B with the reduced 505 * bandwidth with of channel A. 506 * In this case, since the CAC is aborted by 507 * the RADAR, AP should start the CAC again. 508 */ 509 dfs_cancel_cac_timer(dfs); 510 } 511 } else { /* CAC timer is not running. */ 512 /* If channel change happens via VAP DOWN/UP on subset channels, 513 * (eg: from 52 HT80 to 64 HT80) CAC done information 514 * (of 52 HT80) based on subset logic 515 * (as 52 and 64 HT80 are subsets of each other) 516 * is not expected to be preserved as VAP has come up 517 * from DOWN state. Hence do not skip CAC on 64 HT80. 518 * is_vap_restart flag is used as an identifier to indicate if 519 * vap has come up from a DOWN state or UP state (vap restart). 520 */ 521 if (!is_vap_restart) { 522 dfs_debug(dfs, WLAN_DEBUG_DFS, "CAC is needed"); 523 return true; 524 } 525 if (dfs_is_new_chan_subset_of_old_chan(dfs, 526 cur_chan, 527 prev_chan)) { 528 /* AP bandwidth reduce case: 529 * When AP detects the RADAR in in-service monitoring 530 * mode in channel A, it cancels the running CAC and 531 * tries to find the channel B with the reduced 532 * bandwidth of channel A. 533 * If the new channel B is subset of the channel A 534 * then AP skips the CAC. 535 */ 536 if (!dfs->dfs_cac_aborted) { 537 dfs_debug(dfs, WLAN_DEBUG_DFS, "Skip CAC"); 538 return false; 539 } 540 } 541 } 542 543 return true; 544 } 545 #endif 546