1 /* 2 * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 /** 19 * DOC: wlan_dcs.c 20 * 21 * This file provide definitions for following: 22 * - (de)register to WMI events for psoc enable 23 * - send dcs wmi command 24 * - dcs algorithm handling 25 */ 26 27 #include <target_if_dcs.h> 28 #include "wlan_dcs.h" 29 #include <wlan_objmgr_psoc_obj_i.h> 30 #include "wlan_utility.h" 31 #ifdef WLAN_POLICY_MGR_ENABLE 32 #include "wlan_policy_mgr_api.h" 33 #endif 34 #include <wlan_reg_services_api.h> 35 36 struct dcs_pdev_priv_obj * 37 wlan_dcs_get_pdev_private_obj(struct wlan_objmgr_psoc *psoc, uint32_t pdev_id) 38 { 39 struct dcs_psoc_priv_obj *dcs_psoc_obj; 40 struct dcs_pdev_priv_obj *dcs_pdev_priv = NULL; 41 42 if (!psoc) { 43 dcs_err("psoc is null"); 44 goto end; 45 } 46 47 dcs_psoc_obj = wlan_objmgr_psoc_get_comp_private_obj( 48 psoc, 49 WLAN_UMAC_COMP_DCS); 50 if (!dcs_psoc_obj) { 51 dcs_err("dcs psoc object is null"); 52 goto end; 53 } 54 55 if (pdev_id >= WLAN_DCS_MAX_PDEVS) { 56 dcs_err("invalid pdev_id: %u", pdev_id); 57 goto end; 58 } 59 60 dcs_pdev_priv = &dcs_psoc_obj->dcs_pdev_priv[pdev_id]; 61 end: 62 63 return dcs_pdev_priv; 64 } 65 66 QDF_STATUS wlan_dcs_attach(struct wlan_objmgr_psoc *psoc) 67 { 68 struct wlan_target_if_dcs_tx_ops *dcs_tx_ops; 69 70 if (!psoc) { 71 dcs_err("psoc is null"); 72 return QDF_STATUS_E_NULL_VALUE; 73 } 74 75 dcs_tx_ops = target_if_dcs_get_tx_ops(psoc); 76 if (!dcs_tx_ops) { 77 dcs_err("tx_ops is null!"); 78 return QDF_STATUS_E_NULL_VALUE; 79 } 80 81 if (!dcs_tx_ops->dcs_attach) { 82 dcs_err("dcs_attach function is null!"); 83 return QDF_STATUS_E_NULL_VALUE; 84 } 85 86 return dcs_tx_ops->dcs_attach(psoc); 87 } 88 89 QDF_STATUS wlan_dcs_detach(struct wlan_objmgr_psoc *psoc) 90 { 91 struct wlan_target_if_dcs_tx_ops *dcs_tx_ops; 92 93 if (!psoc) { 94 dcs_err("psoc is null"); 95 return QDF_STATUS_E_NULL_VALUE; 96 } 97 98 dcs_tx_ops = target_if_dcs_get_tx_ops(psoc); 99 if (!dcs_tx_ops) { 100 dcs_err("tx_ops is null!"); 101 return QDF_STATUS_E_NULL_VALUE; 102 } 103 104 if (!dcs_tx_ops->dcs_detach) { 105 dcs_err("dcs_detach function is null!"); 106 return QDF_STATUS_E_NULL_VALUE; 107 } 108 109 return dcs_tx_ops->dcs_detach(psoc); 110 } 111 112 QDF_STATUS wlan_dcs_cmd_send(struct wlan_objmgr_psoc *psoc, 113 uint32_t pdev_id, 114 bool is_host_pdev_id) 115 { 116 struct wlan_target_if_dcs_tx_ops *dcs_tx_ops; 117 struct dcs_pdev_priv_obj *dcs_pdev_priv; 118 uint32_t dcs_enable; 119 120 if (!psoc) { 121 dcs_err("psoc is null"); 122 return QDF_STATUS_E_NULL_VALUE; 123 } 124 125 dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc, pdev_id); 126 if (!dcs_pdev_priv) { 127 dcs_err("dcs pdev private object is null"); 128 return QDF_STATUS_E_NULL_VALUE; 129 } 130 131 dcs_enable = dcs_pdev_priv->dcs_host_params.dcs_enable & 132 dcs_pdev_priv->dcs_host_params.dcs_enable_cfg; 133 dcs_tx_ops = target_if_dcs_get_tx_ops(psoc); 134 135 if (dcs_tx_ops && dcs_tx_ops->dcs_cmd_send) { 136 dcs_debug("dcs_enable: %u, pdev_id: %u", dcs_enable, pdev_id); 137 return dcs_tx_ops->dcs_cmd_send(psoc, 138 pdev_id, 139 is_host_pdev_id, 140 dcs_enable); 141 } 142 143 return QDF_STATUS_SUCCESS; 144 } 145 146 /** 147 * wlan_dcs_im_copy_stats() - dcs target interference mitigation statistics copy 148 * @prev_stats: previous statistics pointer 149 * @curr_stats: current statistics pointer 150 * 151 * Return: None 152 */ 153 static inline void 154 wlan_dcs_im_copy_stats(struct wlan_host_dcs_im_tgt_stats *prev_stats, 155 struct wlan_host_dcs_im_tgt_stats *curr_stats) 156 { 157 if (!prev_stats || !curr_stats) { 158 dcs_err("previous or current stats is null"); 159 return; 160 } 161 162 /* 163 * Right now no other actions are required beyond memcopy, 164 * if required the rest of the code would follow. 165 */ 166 qdf_mem_copy(prev_stats, curr_stats, 167 sizeof(struct wlan_host_dcs_im_tgt_stats)); 168 } 169 170 /** 171 * wlan_dcs_im_print_stats() - print current/previous dcs target im statistics 172 * @prev_stats: previous statistics pointer 173 * @curr_stats: current statistics pointer 174 * 175 * Return: None 176 */ 177 static void 178 wlan_dcs_im_print_stats(struct wlan_host_dcs_im_tgt_stats *prev_stats, 179 struct wlan_host_dcs_im_tgt_stats *curr_stats) 180 { 181 if (!prev_stats || !curr_stats) { 182 dcs_err("previous or current stats is null"); 183 return; 184 } 185 186 /* Debug, dump all received stats first */ 187 dcs_debug("tgt_curr/tsf: %u", curr_stats->reg_tsf32); 188 dcs_debug("tgt_curr/last_ack_rssi: %u", curr_stats->last_ack_rssi); 189 dcs_debug("tgt_curr/tx_waste_time: %u", curr_stats->tx_waste_time); 190 dcs_debug("tgt_curr/dcs_rx_time: %u", curr_stats->rx_time); 191 dcs_debug("tgt_curr/listen_time: %u", 192 curr_stats->mib_stats.listen_time); 193 dcs_debug("tgt_curr/tx_frame_cnt: %u", 194 curr_stats->mib_stats.reg_tx_frame_cnt); 195 dcs_debug("tgt_curr/rx_frame_cnt: %u", 196 curr_stats->mib_stats.reg_rx_frame_cnt); 197 dcs_debug("tgt_curr/rxclr_cnt: %u", 198 curr_stats->mib_stats.reg_rxclr_cnt); 199 dcs_debug("tgt_curr/reg_cycle_cnt: %u", 200 curr_stats->mib_stats.reg_cycle_cnt); 201 dcs_debug("tgt_curr/rxclr_ext_cnt: %u", 202 curr_stats->mib_stats.reg_rxclr_ext_cnt); 203 dcs_debug("tgt_curr/ofdm_phyerr_cnt: %u", 204 curr_stats->mib_stats.reg_ofdm_phyerr_cnt); 205 dcs_debug("tgt_curr/cck_phyerr_cnt: %u", 206 curr_stats->mib_stats.reg_cck_phyerr_cnt); 207 208 dcs_debug("tgt_prev/tsf: %u", prev_stats->reg_tsf32); 209 dcs_debug("tgt_prev/last_ack_rssi: %u", prev_stats->last_ack_rssi); 210 dcs_debug("tgt_prev/tx_waste_time: %u", prev_stats->tx_waste_time); 211 dcs_debug("tgt_prev/rx_time: %u", prev_stats->rx_time); 212 dcs_debug("tgt_prev/listen_time: %u", 213 prev_stats->mib_stats.listen_time); 214 dcs_debug("tgt_prev/tx_frame_cnt: %u", 215 prev_stats->mib_stats.reg_tx_frame_cnt); 216 dcs_debug("tgt_prev/rx_frame_cnt: %u", 217 prev_stats->mib_stats.reg_rx_frame_cnt); 218 dcs_debug("tgt_prev/rxclr_cnt: %u", 219 prev_stats->mib_stats.reg_rxclr_cnt); 220 dcs_debug("tgt_prev/reg_cycle_cnt: %u", 221 prev_stats->mib_stats.reg_cycle_cnt); 222 dcs_debug("tgt_prev/rxclr_ext_cnt: %u", 223 prev_stats->mib_stats.reg_rxclr_ext_cnt); 224 dcs_debug("tgt_prev/ofdm_phyerr_cnt: %u", 225 prev_stats->mib_stats.reg_ofdm_phyerr_cnt); 226 dcs_debug("tgt_prev/cck_phyerr_cnt: %u", 227 prev_stats->mib_stats.reg_cck_phyerr_cnt); 228 } 229 230 /** 231 * wlan_dcs_update_chan_util() - update chan utilization of dcs stats 232 * @p_dcs_im_stats: pointer to pdev_dcs_im_stats 233 * @rx_cu: rx channel utilization 234 * @tx_cu: tx channel utilization 235 * @obss_rx_cu: obss rx channel utilization 236 * @total_cu: total channel utilization 237 * @chan_nf: Channel noise floor (units are in dBm) 238 * 239 * Return: Void 240 */ 241 static void wlan_dcs_update_chan_util(struct pdev_dcs_im_stats *p_dcs_im_stats, 242 uint32_t rx_cu, uint32_t tx_cu, 243 uint32_t obss_rx_cu, 244 uint32_t total_cu, uint32_t chan_nf) 245 { 246 if (p_dcs_im_stats) { 247 p_dcs_im_stats->dcs_ch_util_im_stats.rx_cu = rx_cu; 248 p_dcs_im_stats->dcs_ch_util_im_stats.tx_cu = tx_cu; 249 p_dcs_im_stats->dcs_ch_util_im_stats.obss_rx_cu = obss_rx_cu; 250 p_dcs_im_stats->dcs_ch_util_im_stats.total_cu = total_cu; 251 p_dcs_im_stats->dcs_ch_util_im_stats.chan_nf = chan_nf; 252 } 253 } 254 255 /** 256 * wlan_dcs_wlan_interference_process() - dcs detection algorithm handling 257 * @curr_stats: current target im stats pointer 258 * @dcs_pdev_priv: dcs pdev priv pointer 259 * 260 * Return: true or false means start dcs callback handler or not 261 */ 262 static bool 263 wlan_dcs_wlan_interference_process( 264 struct wlan_host_dcs_im_tgt_stats *curr_stats, 265 struct dcs_pdev_priv_obj *dcs_pdev_priv) 266 { 267 struct wlan_host_dcs_im_tgt_stats *prev_stats; 268 struct pdev_dcs_params dcs_host_params; 269 struct pdev_dcs_im_stats *p_dcs_im_stats; 270 bool start_dcs_cbk_handler = false; 271 272 uint32_t reg_tsf_delta = 0; 273 uint32_t scaled_reg_tsf_delta; 274 uint32_t rxclr_delta = 0; 275 uint32_t rxclr_ext_delta = 0; 276 uint32_t cycle_count_delta = 0; 277 uint32_t scaled_cycle_count_delta; 278 uint32_t tx_frame_delta = 0; 279 uint32_t rx_frame_delta = 0; 280 uint32_t my_bss_rx_delta = 0; 281 uint32_t reg_total_cu = 0; 282 uint32_t reg_tx_cu = 0; 283 uint32_t reg_rx_cu = 0; 284 uint32_t obss_rx_cu = 0; 285 uint32_t reg_unused_cu = 0; 286 uint32_t rx_time_cu = 0; 287 uint32_t reg_ofdm_phyerr_delta = 0; 288 uint32_t reg_cck_phyerr_delta = 0; 289 uint32_t reg_ofdm_phyerr_cu = 0; 290 uint32_t ofdm_phy_err_rate = 0; 291 uint32_t cck_phy_err_rate = 0; 292 uint32_t max_phy_err_rate = 0; 293 uint32_t max_phy_err_count = 0; 294 uint32_t total_wasted_cu = 0; 295 uint32_t wasted_tx_cu = 0; 296 uint32_t tx_err = 0; 297 uint32_t too_many_phy_errors = 0; 298 299 if (!curr_stats) { 300 dcs_err("curr_stats is NULL"); 301 goto end; 302 } 303 304 if (!dcs_pdev_priv) { 305 dcs_err("dcs pdev private object is NULL"); 306 goto end; 307 } 308 309 dcs_host_params = dcs_pdev_priv->dcs_host_params; 310 p_dcs_im_stats = &dcs_pdev_priv->dcs_im_stats; 311 prev_stats = &dcs_pdev_priv->dcs_im_stats.prev_dcs_im_stats; 312 313 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) 314 wlan_dcs_im_print_stats(prev_stats, curr_stats); 315 316 /* 317 * Counters would have wrapped. Ideally we should be able to figure this 318 * out, but we never know how many times counters wrapped, just ignore. 319 */ 320 if ((curr_stats->mib_stats.listen_time <= 0) || 321 (curr_stats->reg_tsf32 <= prev_stats->reg_tsf32)) { 322 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) 323 dcs_debug("ignoring due to negative TSF value"); 324 goto copy_stats; 325 } 326 327 reg_tsf_delta = curr_stats->reg_tsf32 - prev_stats->reg_tsf32; 328 329 /* 330 * Do nothing if current stats are not seeming good, probably 331 * a reset happened on chip, force cleared 332 */ 333 if (prev_stats->mib_stats.reg_rxclr_cnt > 334 curr_stats->mib_stats.reg_rxclr_cnt) { 335 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) 336 dcs_debug("ignoring due to negative rxclr count"); 337 goto copy_stats; 338 } 339 340 rxclr_delta = curr_stats->mib_stats.reg_rxclr_cnt - 341 prev_stats->mib_stats.reg_rxclr_cnt; 342 rxclr_ext_delta = curr_stats->mib_stats.reg_rxclr_ext_cnt - 343 prev_stats->mib_stats.reg_rxclr_ext_cnt; 344 tx_frame_delta = curr_stats->mib_stats.reg_tx_frame_cnt - 345 prev_stats->mib_stats.reg_tx_frame_cnt; 346 347 rx_frame_delta = curr_stats->mib_stats.reg_rx_frame_cnt - 348 prev_stats->mib_stats.reg_rx_frame_cnt; 349 350 cycle_count_delta = curr_stats->mib_stats.reg_cycle_cnt - 351 prev_stats->mib_stats.reg_cycle_cnt; 352 353 my_bss_rx_delta = curr_stats->my_bss_rx_cycle_count - 354 prev_stats->my_bss_rx_cycle_count; 355 356 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) 357 dcs_debug("rxclr_delta: %u, rxclr_ext_delta: %u, tx_frame_delta: %u, rx_frame_delta: %u, cycle_count_delta: %u, my_bss_rx_delta: %u", 358 rxclr_delta, rxclr_ext_delta, tx_frame_delta, 359 rx_frame_delta, cycle_count_delta, my_bss_rx_delta); 360 361 /* Update user stats */ 362 wlan_dcs_pdev_obj_lock(dcs_pdev_priv); 363 if (dcs_pdev_priv->dcs_host_params.user_request_count) { 364 struct wlan_host_dcs_im_user_stats *p_user_stats = 365 &p_dcs_im_stats->user_dcs_im_stats; 366 367 p_user_stats->cycle_count += cycle_count_delta; 368 p_user_stats->rxclr_count += rxclr_delta; 369 p_user_stats->rx_frame_count += rx_frame_delta; 370 p_user_stats->my_bss_rx_cycle_count += my_bss_rx_delta; 371 if (0 == p_user_stats->max_rssi && 372 0 == p_user_stats->min_rssi) { 373 p_user_stats->max_rssi = curr_stats->last_ack_rssi; 374 p_user_stats->min_rssi = curr_stats->last_ack_rssi; 375 } else { 376 if (curr_stats->last_ack_rssi > p_user_stats->max_rssi) 377 p_user_stats->max_rssi = 378 curr_stats->last_ack_rssi; 379 if (curr_stats->last_ack_rssi < p_user_stats->min_rssi) 380 p_user_stats->min_rssi = 381 curr_stats->last_ack_rssi; 382 } 383 dcs_pdev_priv->dcs_host_params.user_request_count--; 384 if (0 == dcs_pdev_priv->dcs_host_params.user_request_count) 385 dcs_pdev_priv->dcs_host_params.notify_user = 1; 386 } 387 wlan_dcs_pdev_obj_unlock(dcs_pdev_priv); 388 389 /* 390 * Total channel utiliztaion is the amount of time RXCLR is 391 * counted. RXCLR is counted, when 'RX is NOT clear', please 392 * refer to mac documentation. It means either TX or RX is ON 393 * 394 * Why shift by 8 ? after multiplication it could overflow. At one 395 * second rate, normally neither cycle_count_delta nor the tsf_delta 396 * would be zero after shift by 8 bits. In corner case, host resets 397 * dcs stats, and at the same time tsf counters is wrapped. 398 * Then all the variable in prev_stats are 0, and the variable in 399 * curr_stats may be a small value, so add check for cycle_count_delta 400 * and the tsf_delta after shift by 8 bits. 401 */ 402 scaled_cycle_count_delta = cycle_count_delta >> 8; 403 scaled_reg_tsf_delta = reg_tsf_delta >> 8; 404 if (!scaled_cycle_count_delta || !scaled_reg_tsf_delta) { 405 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) 406 dcs_debug("cycle count or TSF NULL --Investigate--"); 407 goto copy_stats; 408 } 409 reg_total_cu = ((rxclr_delta >> 8) * 100) / scaled_cycle_count_delta; 410 reg_tx_cu = ((tx_frame_delta >> 8) * 100) / scaled_cycle_count_delta; 411 reg_rx_cu = ((rx_frame_delta >> 8) * 100) / scaled_cycle_count_delta; 412 rx_time_cu = ((curr_stats->rx_time >> 8) * 100) / scaled_reg_tsf_delta; 413 obss_rx_cu = (((rx_frame_delta - my_bss_rx_delta) >> 8) * 100) / 414 scaled_cycle_count_delta; 415 wlan_dcs_update_chan_util(p_dcs_im_stats, reg_rx_cu, reg_tx_cu, 416 obss_rx_cu, reg_total_cu, 417 curr_stats->chan_nf); 418 419 /* 420 * Amount of the time AP received cannot go higher than the receive 421 * cycle count delta. If at all it is, there should have been a 422 * computation error, ceil it to receive_cycle_count_diff 423 */ 424 if (rx_time_cu > reg_rx_cu) 425 rx_time_cu = reg_rx_cu; 426 427 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) 428 dcs_debug("reg_total_cu: %u, reg_tx_cu: %u, reg_rx_cu: %u, rx_time_cu: %u, obss_rx_cu: %u dcs_algorithm: %d", 429 reg_total_cu, reg_tx_cu, reg_rx_cu, 430 rx_time_cu, obss_rx_cu, 431 dcs_host_params.dcs_algorithm_process); 432 433 /* 434 * For below scenario, will ignore dcs event data and won't do 435 * interference detection algorithm calculation: 436 * 1: Current SAP channel isn't on 5G band 437 * 2: In the process of ACS 438 * 3: In the process of dcs disabling dcs_restart_delay time duration 439 */ 440 if (!dcs_host_params.dcs_algorithm_process) 441 goto copy_stats; 442 443 /* 444 * Unusable channel utilization is amount of time that we 445 * spent in backoff or waiting for other transmit/receive to 446 * complete. If there is interference it is more likely that 447 * we overshoot the limit. In case of multiple stations, we 448 * still see increased channel utilization. This assumption may 449 * not be true for the VOW scenario where either multicast or 450 * unicast-UDP is used ( mixed traffic would still cause high 451 * channel utilization). 452 */ 453 wasted_tx_cu = ((curr_stats->tx_waste_time >> 8) * 100) / 454 scaled_reg_tsf_delta; 455 456 /* 457 * Transmit channel utilization cannot go higher than the amount of time 458 * wasted, if so cap the wastage to transmit channel utillzation. This 459 * could happen to compution error. 460 */ 461 if (reg_tx_cu < wasted_tx_cu) 462 wasted_tx_cu = reg_tx_cu; 463 464 tx_err = (reg_tx_cu && wasted_tx_cu) ? 465 (wasted_tx_cu * 100) / reg_tx_cu : 0; 466 467 /* 468 * The below actually gives amount of time we are not using, or the 469 * interferer is active. 470 * rx_time_cu is what computed receive time *NOT* rx_cycle_count 471 * rx_cycle_count is our receive+interferer's transmit 472 * un-used is really total_cycle_counts - 473 * (our_rx_time(rx_time_cu) + our_receive_time) 474 */ 475 reg_unused_cu = (reg_total_cu >= (reg_tx_cu + rx_time_cu)) ? 476 (reg_total_cu - (reg_tx_cu + rx_time_cu)) : 0; 477 478 /* If any retransmissions are there, count them as wastage */ 479 total_wasted_cu = reg_unused_cu + wasted_tx_cu; 480 481 /* Check ofdm and cck errors */ 482 if (unlikely(curr_stats->mib_stats.reg_ofdm_phyerr_cnt < 483 prev_stats->mib_stats.reg_ofdm_phyerr_cnt)) 484 reg_ofdm_phyerr_delta = 485 curr_stats->mib_stats.reg_ofdm_phyerr_cnt; 486 else 487 reg_ofdm_phyerr_delta = 488 curr_stats->mib_stats.reg_ofdm_phyerr_cnt - 489 prev_stats->mib_stats.reg_ofdm_phyerr_cnt; 490 491 if (unlikely(curr_stats->mib_stats.reg_cck_phyerr_cnt < 492 prev_stats->mib_stats.reg_cck_phyerr_cnt)) 493 reg_cck_phyerr_delta = curr_stats->mib_stats.reg_cck_phyerr_cnt; 494 else 495 reg_cck_phyerr_delta = 496 curr_stats->mib_stats.reg_cck_phyerr_cnt - 497 prev_stats->mib_stats.reg_cck_phyerr_cnt; 498 499 /* 500 * Add the influence of ofdm phy errors to the wasted channel 501 * utillization, this computed through time wasted in errors 502 */ 503 reg_ofdm_phyerr_cu = reg_ofdm_phyerr_delta * 504 dcs_host_params.phy_err_penalty; 505 total_wasted_cu += 506 (reg_ofdm_phyerr_cu > 0) ? 507 (((reg_ofdm_phyerr_cu >> 8) * 100) / scaled_reg_tsf_delta) : 0; 508 509 ofdm_phy_err_rate = (curr_stats->mib_stats.reg_ofdm_phyerr_cnt * 1000) / 510 curr_stats->mib_stats.listen_time; 511 cck_phy_err_rate = (curr_stats->mib_stats.reg_cck_phyerr_cnt * 1000) / 512 curr_stats->mib_stats.listen_time; 513 514 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) { 515 dcs_debug("reg_unused_cu: %u, reg_ofdm_phyerr_delta: %u, reg_cck_phyerr_delta: %u, reg_ofdm_phyerr_cu: %u", 516 reg_unused_cu, reg_ofdm_phyerr_delta, 517 reg_cck_phyerr_delta, reg_ofdm_phyerr_cu); 518 dcs_debug("total_wasted_cu: %u, ofdm_phy_err_rate: %u, cck_phy_err_rate: %u", 519 total_wasted_cu, ofdm_phy_err_rate, cck_phy_err_rate); 520 dcs_debug("new_unused_cu: %u, reg_ofdm_phy_error_cu: %u", 521 reg_unused_cu, 522 (curr_stats->mib_stats.reg_ofdm_phyerr_cnt * 100) / 523 curr_stats->mib_stats.listen_time); 524 } 525 526 /* Check if the error rates are higher than the thresholds */ 527 max_phy_err_rate = QDF_MAX(ofdm_phy_err_rate, cck_phy_err_rate); 528 529 max_phy_err_count = QDF_MAX(curr_stats->mib_stats.reg_ofdm_phyerr_cnt, 530 curr_stats->mib_stats.reg_cck_phyerr_cnt); 531 532 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) 533 dcs_debug("max_phy_err_rate: %u, max_phy_err_count: %u", 534 max_phy_err_rate, max_phy_err_count); 535 536 if (((max_phy_err_rate >= dcs_host_params.phy_err_threshold) && 537 (max_phy_err_count > dcs_host_params.phy_err_threshold)) || 538 (curr_stats->phyerr_cnt > dcs_host_params.radar_err_threshold)) 539 too_many_phy_errors = 1; 540 541 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_CRITICAL)) { 542 dcs_debug("total_cu: %u, tx_cu: %u, rx_cu: %u, rx_time_cu: %u, unused cu: %u", 543 reg_total_cu, reg_tx_cu, 544 reg_rx_cu, rx_time_cu, reg_unused_cu); 545 dcs_debug("phyerr: %u, total_wasted_cu: %u, phyerror_cu: %u, wasted_cu: %u, reg_tx_cu: %u, reg_rx_cu: %u", 546 too_many_phy_errors, total_wasted_cu, 547 reg_ofdm_phyerr_cu, wasted_tx_cu, 548 reg_tx_cu, reg_rx_cu); 549 dcs_debug("tx_err: %u", tx_err); 550 } 551 552 if (reg_unused_cu >= dcs_host_params.coch_intfr_threshold) 553 /* Quickly reach to decision */ 554 p_dcs_im_stats->im_intfr_cnt += 2; 555 else if (too_many_phy_errors && 556 (((total_wasted_cu > 557 (dcs_host_params.coch_intfr_threshold + 10)) && 558 ((reg_tx_cu + reg_rx_cu) > dcs_host_params.user_max_cu)) || 559 ((reg_tx_cu > DCS_TX_MAX_CU) && 560 (tx_err >= dcs_host_params.tx_err_threshold)))) 561 p_dcs_im_stats->im_intfr_cnt++; 562 563 if (p_dcs_im_stats->im_intfr_cnt >= 564 dcs_host_params.intfr_detection_threshold) { 565 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_CRITICAL)) { 566 dcs_debug("interference threshold exceeded"); 567 dcs_debug("unused_cu: %u, too_any_phy_errors: %u, total_wasted_cu: %u, reg_tx_cu: %u, reg_rx_cu: %u", 568 reg_unused_cu, too_many_phy_errors, 569 total_wasted_cu, reg_tx_cu, reg_rx_cu); 570 } 571 572 p_dcs_im_stats->im_intfr_cnt = 0; 573 p_dcs_im_stats->im_samp_cnt = 0; 574 /* 575 * Once the interference is detected, change the channel, as on 576 * today this is common routine for wirelesslan and 577 * non-wirelesslan interference. Name as such kept the same 578 * because of the DA code, which is using the same function. 579 */ 580 start_dcs_cbk_handler = true; 581 } else if (0 == p_dcs_im_stats->im_intfr_cnt || 582 p_dcs_im_stats->im_samp_cnt >= 583 dcs_host_params.intfr_detection_window) { 584 p_dcs_im_stats->im_intfr_cnt = 0; 585 p_dcs_im_stats->im_samp_cnt = 0; 586 } 587 588 /* Count the current run too */ 589 p_dcs_im_stats->im_samp_cnt++; 590 591 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) 592 dcs_debug("intfr_count: %u, sample_count: %u", 593 p_dcs_im_stats->im_intfr_cnt, 594 p_dcs_im_stats->im_samp_cnt); 595 copy_stats: 596 /* Copy the stats for next cycle */ 597 wlan_dcs_im_copy_stats(prev_stats, curr_stats); 598 end: 599 return start_dcs_cbk_handler; 600 } 601 602 void wlan_dcs_disable_timer_fn(void *dcs_timer_args) 603 { 604 struct pdev_dcs_timer_args *dcs_timer_args_ctx; 605 struct wlan_objmgr_psoc *psoc; 606 uint32_t pdev_id; 607 struct dcs_psoc_priv_obj *dcs_psoc_priv; 608 struct dcs_pdev_priv_obj *dcs_pdev_priv; 609 610 if (!dcs_timer_args) { 611 dcs_err("dcs timer args is null"); 612 return; 613 } 614 615 dcs_timer_args_ctx = (struct pdev_dcs_timer_args *)dcs_timer_args; 616 psoc = dcs_timer_args_ctx->psoc; 617 pdev_id = dcs_timer_args_ctx->pdev_id; 618 619 dcs_psoc_priv = 620 wlan_objmgr_psoc_get_comp_private_obj(psoc, WLAN_UMAC_COMP_DCS); 621 if (!dcs_psoc_priv) { 622 dcs_err("dcs psoc private object is null"); 623 return; 624 } 625 626 dcs_pdev_priv = &dcs_psoc_priv->dcs_pdev_priv[pdev_id]; 627 dcs_pdev_priv->dcs_freq_ctrl_params.disable_delay_process = false; 628 629 dcs_info("dcs disable timeout, enable dcs detection again"); 630 wlan_dcs_set_algorithm_process(psoc, pdev_id, true); 631 } 632 633 /** 634 * wlan_dcs_frequency_control() - dcs frequency control handling 635 * @psoc: psoc pointer 636 * @dcs_pdev_priv: dcs pdev priv pointer 637 * @event: dcs stats event pointer 638 * 639 * Return: none 640 */ 641 static void wlan_dcs_frequency_control(struct wlan_objmgr_psoc *psoc, 642 struct dcs_pdev_priv_obj *dcs_pdev_priv, 643 struct wlan_host_dcs_event *event) 644 { 645 struct dcs_psoc_priv_obj *dcs_psoc_priv; 646 struct pdev_dcs_freq_ctrl_params *dcs_freq_ctrl_params; 647 uint8_t timestamp_pos; 648 unsigned long current_time; 649 uint8_t delta_pos; 650 unsigned long delta_time; 651 bool disable_dcs_sometime = false; 652 653 if (!psoc || !dcs_pdev_priv || !event) { 654 dcs_err("psoc or dcs_pdev_priv or event is null"); 655 return; 656 } 657 658 dcs_freq_ctrl_params = &dcs_pdev_priv->dcs_freq_ctrl_params; 659 if (dcs_freq_ctrl_params->disable_delay_process) { 660 dcs_err("In the process of dcs disable, shouldn't go to here"); 661 return; 662 } 663 664 current_time = qdf_get_system_timestamp(); 665 if (dcs_freq_ctrl_params->dcs_happened_count >= 666 dcs_freq_ctrl_params->disable_threshold_per_5mins) { 667 delta_pos = 668 dcs_freq_ctrl_params->dcs_happened_count - 669 dcs_freq_ctrl_params->disable_threshold_per_5mins; 670 delta_pos = delta_pos % MAX_DCS_TIME_RECORD; 671 672 delta_time = current_time - 673 dcs_freq_ctrl_params->timestamp[delta_pos]; 674 if (delta_time < DCS_FREQ_CONTROL_TIME) 675 disable_dcs_sometime = true; 676 } 677 678 if (!disable_dcs_sometime) { 679 timestamp_pos = dcs_freq_ctrl_params->dcs_happened_count % 680 MAX_DCS_TIME_RECORD; 681 dcs_freq_ctrl_params->timestamp[timestamp_pos] = current_time; 682 dcs_freq_ctrl_params->dcs_happened_count++; 683 } 684 685 /* 686 * Before start dcs callback handler or disable dcs for some time, 687 * need to ignore dcs event data and won't do interference detection 688 * algorithm calculation for disabling dcs detection firstly. 689 */ 690 wlan_dcs_set_algorithm_process(psoc, event->dcs_param.pdev_id, false); 691 692 if (disable_dcs_sometime) { 693 dcs_freq_ctrl_params->disable_delay_process = true; 694 dcs_pdev_priv->dcs_timer_args.psoc = psoc; 695 dcs_pdev_priv->dcs_timer_args.pdev_id = 696 event->dcs_param.pdev_id; 697 qdf_timer_start(&dcs_pdev_priv->dcs_disable_timer, 698 dcs_pdev_priv->dcs_freq_ctrl_params. 699 restart_delay * 60 * 1000); 700 dcs_info("start dcs disable timer"); 701 } else { 702 dcs_psoc_priv = wlan_objmgr_psoc_get_comp_private_obj( 703 psoc, 704 WLAN_UMAC_COMP_DCS); 705 if (!dcs_psoc_priv) { 706 dcs_err("dcs private psoc object is null"); 707 return; 708 } 709 710 dcs_info("start dcs callback handler"); 711 dcs_psoc_priv->dcs_cbk.cbk(psoc, event->dcs_param.pdev_id, 712 event->dcs_param.interference_type, 713 dcs_psoc_priv->dcs_cbk.arg); 714 } 715 } 716 717 QDF_STATUS 718 wlan_dcs_switch_chan(struct wlan_objmgr_vdev *vdev, qdf_freq_t tgt_freq, 719 enum phy_ch_width tgt_width) 720 { 721 struct wlan_objmgr_psoc *psoc; 722 struct dcs_psoc_priv_obj *dcs_psoc_priv; 723 dcs_switch_chan_cb switch_chan_cb; 724 725 psoc = wlan_vdev_get_psoc(vdev); 726 if (!psoc) 727 return QDF_STATUS_E_INVAL; 728 729 dcs_psoc_priv = wlan_objmgr_psoc_get_comp_private_obj(psoc, 730 WLAN_UMAC_COMP_DCS); 731 if (!dcs_psoc_priv) 732 return QDF_STATUS_E_INVAL; 733 734 switch_chan_cb = dcs_psoc_priv->switch_chan_cb; 735 if (!switch_chan_cb) 736 return QDF_STATUS_E_NOSUPPORT; 737 738 return switch_chan_cb(vdev, tgt_freq, tgt_width); 739 } 740 741 #ifdef WLAN_POLICY_MGR_ENABLE 742 /** 743 * wlan_dcs_get_pcl_for_sap() - get preferred channel list for SAP 744 * @vdev: vdev ptr 745 * @freq_list: Pointer to PCL 746 * @freq_list_sz: Max size of PCL 747 * 748 * Return: number of channels in PCL 749 */ 750 static uint32_t wlan_dcs_get_pcl_for_sap(struct wlan_objmgr_vdev *vdev, 751 qdf_freq_t *freq_list, 752 uint32_t freq_list_sz) 753 { 754 struct wlan_objmgr_psoc *psoc; 755 struct wlan_objmgr_pdev *pdev; 756 struct policy_mgr_pcl_list *pcl; 757 qdf_freq_t freq; 758 enum channel_state state; 759 QDF_STATUS status; 760 int i, j; 761 enum policy_mgr_con_mode mode; 762 763 psoc = wlan_vdev_get_psoc(vdev); 764 if (!psoc) 765 return 0; 766 767 pdev = wlan_vdev_get_pdev(vdev); 768 if (!pdev) 769 return 0; 770 771 pcl = qdf_mem_malloc(sizeof(*pcl)); 772 if (!pcl) 773 return 0; 774 775 mode = policy_mgr_qdf_opmode_to_pm_con_mode(psoc, QDF_SAP_MODE, 776 wlan_vdev_get_id(vdev)); 777 778 status = policy_mgr_get_pcl_for_vdev_id(psoc, mode, pcl->pcl_list, 779 &pcl->pcl_len, 780 pcl->weight_list, 781 QDF_ARRAY_SIZE(pcl->weight_list), 782 wlan_vdev_get_id(vdev)); 783 if (QDF_IS_STATUS_ERROR(status) || !pcl->pcl_len) { 784 qdf_mem_free(pcl); 785 return 0; 786 } 787 788 for (i = 0, j = 0; i < pcl->pcl_len && i < freq_list_sz; i++) { 789 freq = (qdf_freq_t)pcl->pcl_list[i]; 790 state = wlan_reg_get_channel_state_for_pwrmode( 791 pdev, 792 freq, 793 REG_CURRENT_PWR_MODE); 794 if (state != CHANNEL_STATE_ENABLE) 795 continue; 796 797 freq_list[j++] = freq; 798 } 799 800 qdf_mem_free(pcl); 801 return j; 802 } 803 #else 804 static uint32_t wlan_dcs_get_pcl_for_sap(struct wlan_objmgr_vdev *vdev, 805 qdf_freq_t *freq_list, 806 uint32_t freq_list_sz) 807 { 808 struct wlan_objmgr_pdev *pdev; 809 struct regulatory_channel *cur_chan_list; 810 qdf_freq_t freq; 811 enum channel_state state; 812 int i, j; 813 814 pdev = wlan_vdev_get_pdev(vdev); 815 if (!pdev) 816 return 0; 817 818 cur_chan_list = qdf_mem_malloc(NUM_CHANNELS * 819 sizeof(struct regulatory_channel)); 820 if (!cur_chan_list) 821 return 0; 822 823 if (wlan_reg_get_current_chan_list(pdev, cur_chan_list) != 824 QDF_STATUS_SUCCESS) { 825 qdf_mem_free(cur_chan_list); 826 return 0; 827 } 828 829 for (i = 0, j = 0; i < NUM_CHANNELS && i < freq_list_sz; i++) { 830 freq = cur_chan_list[i].center_freq; 831 state = wlan_reg_get_channel_state_for_pwrmode( 832 pdev, 833 freq, 834 REG_CURRENT_PWR_MODE); 835 if (state != CHANNEL_STATE_ENABLE) 836 continue; 837 838 freq_list[j++] = freq; 839 } 840 841 qdf_mem_free(cur_chan_list); 842 return j; 843 } 844 #endif 845 846 /** 847 * wlan_dcs_awgn_get_intf_for_seg() - get interference for specified segment 848 * @awgn_info: awgn info pointer 849 * @segment: segment index in channel band 850 * 851 * This function extracts the information from awgn event and check interference 852 * within the specified segment. 853 * 854 * Return: true if interference is found within the segment, false otherwise. 855 */ 856 static bool 857 wlan_dcs_awgn_get_intf_for_seg(struct wlan_host_dcs_awgn_info *awgn_info, 858 uint32_t segment) 859 { 860 uint32_t seg_mask; 861 862 switch (segment) { 863 case WLAN_DCS_SEG_PRI20: 864 seg_mask = WLAN_DCS_SEG_PRI20_MASK; 865 break; 866 case WLAN_DCS_SEG_SEC20: 867 seg_mask = WLAN_DCS_SEG_SEC20_MASK; 868 break; 869 case WLAN_DCS_SEG_SEC40: 870 seg_mask = WLAN_DCS_SEG_SEC40_MASK; 871 break; 872 case WLAN_DCS_SEG_SEC80: 873 seg_mask = WLAN_DCS_SEG_SEC80_MASK; 874 break; 875 case WLAN_DCS_SEG_SEC160: 876 seg_mask = WLAN_DCS_SEG_SEC160_MASK; 877 break; 878 default: 879 seg_mask = 0xFFFFFFFF; 880 break; 881 } 882 883 return (awgn_info->chan_bw_intf_bitmap & seg_mask); 884 } 885 886 /** 887 * wlan_dcs_get_max_seg_idx() - get max segment index for channel width 888 * @width: channel width 889 * 890 * Return: max segment index(enum wlan_dcs_chan_seg) for the channel width. 891 */ 892 static enum wlan_dcs_chan_seg wlan_dcs_get_max_seg_idx(enum phy_ch_width width) 893 { 894 switch (width) { 895 case CH_WIDTH_160MHZ: 896 case CH_WIDTH_80P80MHZ: 897 return WLAN_DCS_SEG_SEC80; 898 case CH_WIDTH_80MHZ: 899 return WLAN_DCS_SEG_SEC40; 900 case CH_WIDTH_40MHZ: 901 return WLAN_DCS_SEG_SEC20; 902 case CH_WIDTH_20MHZ: 903 return WLAN_DCS_SEG_PRI20; 904 default: 905 dcs_err("Invalid ch width %d", width); 906 return WLAN_DCS_SEG_INVALID; 907 } 908 } 909 910 /** 911 * wlan_dcs_get_chan_width_for_seg() - get channel width for specified segment 912 * @seg_idx: segment index 913 * 914 * Return: channel width for segment index 915 */ 916 static enum phy_ch_width 917 wlan_dcs_get_chan_width_for_seg(enum wlan_dcs_chan_seg seg_idx) 918 { 919 switch (seg_idx) { 920 case WLAN_DCS_SEG_SEC80: 921 return CH_WIDTH_160MHZ; 922 case WLAN_DCS_SEG_SEC40: 923 return CH_WIDTH_80MHZ; 924 case WLAN_DCS_SEG_SEC20: 925 return CH_WIDTH_40MHZ; 926 case WLAN_DCS_SEG_PRI20: 927 return CH_WIDTH_20MHZ; 928 default: 929 dcs_err("Invalid seg idx %d", seg_idx); 930 return CH_WIDTH_INVALID; 931 } 932 } 933 934 /** 935 * wlan_dcs_get_max_no_intf_bw() - get max no interference band width 936 * @awgn_info: pointer to awgn info 937 * @width: pointer to channel width 938 * 939 * This function tries to get max no interference band width according to 940 * awgn event. 941 * 942 * Return: true if valid no interference band width is found, false otherwise. 943 */ 944 static bool 945 wlan_dcs_get_max_no_intf_bw(struct wlan_host_dcs_awgn_info *awgn_info, 946 enum phy_ch_width *width) 947 { 948 enum wlan_dcs_chan_seg seg_idx, max_seg_idx; 949 950 max_seg_idx = wlan_dcs_get_max_seg_idx(awgn_info->channel_width); 951 if (max_seg_idx == WLAN_DCS_SEG_INVALID) 952 return false; 953 954 seg_idx = WLAN_DCS_SEG_PRI20; 955 while (seg_idx <= max_seg_idx) { 956 if (wlan_dcs_awgn_get_intf_for_seg(awgn_info, seg_idx)) { 957 dcs_debug("Intf found for seg idx %d", seg_idx); 958 break; 959 } 960 seg_idx++; 961 } 962 963 /* scroll back to the last no-intf idx */ 964 seg_idx--; 965 966 if (seg_idx == WLAN_DCS_SEG_INVALID) { 967 /* If pri20 contains interference, do full channel change */ 968 dcs_debug("Primary 20MHz Channel interference detected"); 969 return false; 970 } 971 972 *width = wlan_dcs_get_chan_width_for_seg(seg_idx); 973 if (*width == CH_WIDTH_160MHZ && 974 awgn_info->channel_width == CH_WIDTH_80P80MHZ) 975 *width = CH_WIDTH_80P80MHZ; 976 977 dcs_debug("Found the max no intf width %d", *width); 978 return (*width != CH_WIDTH_INVALID); 979 } 980 981 /** 982 * wlan_dcs_get_available_chan_for_bw() - get available channel for specified 983 * band width 984 * @pdev: pdev ptr 985 * @awgn_info: pointer to awgn info 986 * @bw: channel width 987 * @freq_list: List of preferred channels 988 * @freq_num: Number of channels in the PCL 989 * @random: request for random channel 990 * 991 * Return: the selected channel frequency, 0 if no available chan is found. 992 */ 993 static qdf_freq_t 994 wlan_dcs_get_available_chan_for_bw(struct wlan_objmgr_pdev *pdev, 995 struct wlan_host_dcs_awgn_info *awgn_info, 996 enum phy_ch_width bw, qdf_freq_t *freq_list, 997 uint32_t freq_num, bool random) 998 { 999 int i, j = 0; 1000 uint32_t random_chan_idx; 1001 qdf_freq_t freq, selected_freq = 0; 1002 const struct bonded_channel_freq *bonded_chan_ptr = NULL; 1003 enum channel_state state; 1004 uint16_t chan_cfreq; 1005 bool is_safe = true; 1006 1007 if (!freq_list || !freq_num) 1008 return selected_freq; 1009 1010 for (i = 0; i < freq_num; i++) { 1011 if (j && !random) { 1012 selected_freq = freq_list[0]; 1013 dcs_debug("get the first available freq %u for bw %u", 1014 selected_freq, bw); 1015 break; 1016 } 1017 1018 freq = freq_list[i]; 1019 if (!WLAN_REG_IS_SAME_BAND_FREQS(freq, awgn_info->center_freq)) 1020 continue; 1021 1022 /* 1023 * DFS channel may need CAC during restart, which costs time 1024 * and may cause failure. 1025 */ 1026 if (wlan_reg_is_dfs_for_freq(pdev, freq)) { 1027 dcs_debug("skip dfs freq %u", freq); 1028 continue; 1029 } 1030 1031 if (bonded_chan_ptr && 1032 freq >= bonded_chan_ptr->start_freq && 1033 freq <= bonded_chan_ptr->end_freq) { 1034 if (is_safe) { 1035 dcs_debug("add freq directly [%d] = %u", 1036 j, freq); 1037 freq_list[j++] = freq; 1038 } 1039 continue; 1040 } 1041 1042 state = wlan_reg_get_5g_bonded_channel_and_state_for_pwrmode( 1043 pdev, freq, bw, &bonded_chan_ptr, 1044 REG_CURRENT_PWR_MODE, 1045 NO_SCHANS_PUNC); 1046 if (state != CHANNEL_STATE_ENABLE) 1047 continue; 1048 1049 /* no bonding channel for 20MHz */ 1050 if (bw == CH_WIDTH_20MHZ) { 1051 if (WLAN_DCS_IS_FREQ_IN_WIDTH(awgn_info->center_freq, 1052 awgn_info->center_freq0, 1053 awgn_info->center_freq1, 1054 awgn_info->channel_width, 1055 freq)) 1056 continue; 1057 1058 dcs_debug("add freq[%d] = %u", j, freq); 1059 freq_list[j++] = freq; 1060 continue; 1061 } 1062 1063 is_safe = true; 1064 chan_cfreq = bonded_chan_ptr->start_freq; 1065 while (chan_cfreq <= bonded_chan_ptr->end_freq) { 1066 if (WLAN_DCS_IS_FREQ_IN_WIDTH(awgn_info->center_freq, 1067 awgn_info->center_freq0, 1068 awgn_info->center_freq1, 1069 awgn_info->channel_width, 1070 chan_cfreq)) { 1071 is_safe = false; 1072 break; 1073 } 1074 chan_cfreq = chan_cfreq + 20; 1075 } 1076 if (is_safe) { 1077 dcs_debug("add freq[%d] = %u", j, freq); 1078 freq_list[j++] = freq; 1079 } 1080 } 1081 1082 if (j && random) { 1083 qdf_get_random_bytes(&random_chan_idx, sizeof(random_chan_idx)); 1084 random_chan_idx = random_chan_idx % j; 1085 selected_freq = freq_list[random_chan_idx]; 1086 dcs_debug("get freq[%d] = %u for bw %u", 1087 random_chan_idx, selected_freq, bw); 1088 } 1089 1090 return selected_freq; 1091 } 1092 1093 /** 1094 * wlan_dcs_sap_select_chan() - get available channel for sap 1095 * @vdev: vdev ptr 1096 * @awgn_info: pointer to awgn info 1097 * @tgt_freq: frequency of the selected channel 1098 * @tgt_width: band width of the selected channel 1099 * @random: request for random channel 1100 * 1101 * This function tries to get no-interference chan with max possible bandwidth 1102 * from pcl for sap according to awgn info. 1103 * 1104 * Return: true if available channel is found, false otherwise. 1105 */ 1106 static bool 1107 wlan_dcs_sap_select_chan(struct wlan_objmgr_vdev *vdev, 1108 struct wlan_host_dcs_awgn_info *awgn_info, 1109 qdf_freq_t *tgt_freq, enum phy_ch_width *tgt_width, 1110 bool random) 1111 { 1112 int32_t tmp_width; 1113 qdf_freq_t tmp_freq = 0; 1114 struct wlan_objmgr_pdev *pdev; 1115 qdf_freq_t *freq_list; 1116 uint32_t freq_num; 1117 1118 freq_list = qdf_mem_malloc(sizeof(*freq_list) * NUM_CHANNELS); 1119 if (!freq_list) 1120 return false; 1121 1122 freq_num = wlan_dcs_get_pcl_for_sap(vdev, freq_list, NUM_CHANNELS); 1123 if (!freq_num) { 1124 qdf_mem_free(freq_list); 1125 return false; 1126 } 1127 1128 tmp_width = awgn_info->channel_width; 1129 pdev = wlan_vdev_get_pdev(vdev); 1130 if (!pdev) { 1131 qdf_mem_free(freq_list); 1132 return false; 1133 } 1134 1135 while (tmp_width >= CH_WIDTH_20MHZ) { 1136 tmp_freq = wlan_dcs_get_available_chan_for_bw(pdev, awgn_info, 1137 tmp_width, 1138 freq_list, 1139 freq_num, 1140 random); 1141 if (tmp_freq) 1142 break; 1143 tmp_width--; 1144 } 1145 1146 if (tmp_freq) { 1147 *tgt_width = tmp_width; 1148 *tgt_freq = tmp_freq; 1149 dcs_debug("new_width: %d new_freq %u", tmp_width, tmp_freq); 1150 1151 qdf_mem_free(freq_list); 1152 return true; 1153 } 1154 1155 qdf_mem_free(freq_list); 1156 return false; 1157 } 1158 1159 /** 1160 * wlan_dcs_is_awgnim_valid() - validate awgn info 1161 * @awgn_info: pointer to awgn info 1162 * 1163 * Return: true if valid, false otherwise. 1164 */ 1165 static inline bool 1166 wlan_dcs_is_awgnim_valid(struct wlan_host_dcs_awgn_info *awgn_info) 1167 { 1168 return (awgn_info && 1169 awgn_info->center_freq && awgn_info->chan_bw_intf_bitmap && 1170 awgn_info->channel_width != CH_WIDTH_INVALID && 1171 WLAN_REG_IS_6GHZ_CHAN_FREQ(awgn_info->center_freq)); 1172 } 1173 1174 /** 1175 * wlan_dcs_vdev_get_op_chan_info() - get operating channel info for vdev 1176 * @vdev: pointer to vdev object 1177 * @cfreq: Center frequency of primary channel 1178 * @cfreq0: Center frequency of segment 1 1179 * @cfreq1: Center frequency of segment 2 1180 * @ch_width: Channel width, enum phy_ch_width 1181 * 1182 * Return: QDF_STATUS 1183 */ 1184 static QDF_STATUS 1185 wlan_dcs_vdev_get_op_chan_info(struct wlan_objmgr_vdev *vdev, 1186 qdf_freq_t *cfreq, qdf_freq_t *cfreq0, 1187 qdf_freq_t *cfreq1, enum phy_ch_width *ch_width) 1188 { 1189 struct wlan_channel *chan; 1190 1191 if (!vdev) 1192 return QDF_STATUS_E_INVAL; 1193 1194 *cfreq = 0; 1195 *cfreq0 = 0; 1196 *cfreq1 = 0; 1197 *ch_width = 0; 1198 1199 if (wlan_vdev_mlme_is_active(vdev) != QDF_STATUS_SUCCESS) 1200 return QDF_STATUS_E_INVAL; 1201 1202 chan = wlan_vdev_get_active_channel(vdev); 1203 if (!chan) 1204 return QDF_STATUS_E_INVAL; 1205 1206 *cfreq = chan->ch_freq; 1207 *cfreq0 = chan->ch_cfreq1; 1208 *cfreq1 = chan->ch_cfreq2; 1209 *ch_width = chan->ch_width; 1210 1211 return QDF_STATUS_SUCCESS; 1212 } 1213 1214 /** 1215 * wlan_dcs_process_awgn_sta() - process AWGN event for STA 1216 * @pdev: pointer to pdev object 1217 * @object: vdev object 1218 * @arg: Arguments to the handler 1219 * 1220 * Return: void 1221 */ 1222 static void wlan_dcs_process_awgn_sta(struct wlan_objmgr_pdev *pdev, 1223 void *object, void *arg) 1224 { 1225 struct wlan_objmgr_vdev *vdev = object; 1226 struct wlan_host_dcs_awgn_info *awgn_info = arg; 1227 enum phy_ch_width ch_width; 1228 enum phy_ch_width tgt_width = CH_WIDTH_INVALID; 1229 qdf_freq_t op_freq, cfreq0, cfreq1; 1230 qdf_freq_t tgt_freq = 0; 1231 QDF_STATUS status; 1232 uint8_t vdev_id; 1233 bool found; 1234 1235 if (!vdev || !pdev) 1236 return; 1237 1238 if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE) 1239 return; 1240 1241 vdev_id = wlan_vdev_get_id(vdev); 1242 status = wlan_dcs_vdev_get_op_chan_info(vdev, &op_freq, &cfreq0, 1243 &cfreq1, &ch_width); 1244 if (QDF_IS_STATUS_ERROR(status)) 1245 return; 1246 1247 if (awgn_info->center_freq != op_freq) { 1248 dcs_debug("STA-%d: freq not match", vdev_id); 1249 return; 1250 } 1251 1252 found = wlan_dcs_get_max_no_intf_bw(awgn_info, &tgt_width); 1253 if (found) { 1254 if (ch_width <= tgt_width) { 1255 dcs_debug("STA-%d: freq and bw are unchanged", vdev_id); 1256 return; 1257 } 1258 1259 tgt_freq = op_freq; 1260 } 1261 1262 /* If no width is found, means to disconnect */ 1263 dcs_debug("STA-%d: target freq %u width %u", 1264 vdev_id, tgt_freq, tgt_width); 1265 wlan_dcs_switch_chan(vdev, tgt_freq, tgt_width); 1266 } 1267 1268 /** 1269 * wlan_dcs_process_awgn_sap() - process AWGN event for SAP 1270 * @pdev: pointer to pdev object 1271 * @object: vdev object 1272 * @arg: Arguments to the handler 1273 * 1274 * Return: void 1275 */ 1276 static void wlan_dcs_process_awgn_sap(struct wlan_objmgr_pdev *pdev, 1277 void *object, void *arg) 1278 { 1279 struct wlan_objmgr_vdev *vdev = object; 1280 struct wlan_host_dcs_awgn_info *awgn_info = arg; 1281 enum phy_ch_width ch_width; 1282 enum phy_ch_width tgt_width = CH_WIDTH_INVALID; 1283 qdf_freq_t op_freq, cfreq0, cfreq1; 1284 qdf_freq_t tgt_freq = 0; 1285 QDF_STATUS status; 1286 uint8_t vdev_id; 1287 bool found; 1288 1289 if (!vdev || !pdev) 1290 return; 1291 1292 if (wlan_vdev_mlme_get_opmode(vdev) != QDF_SAP_MODE) 1293 return; 1294 1295 vdev_id = wlan_vdev_get_id(vdev); 1296 status = wlan_dcs_vdev_get_op_chan_info(vdev, &op_freq, &cfreq0, &cfreq1, &ch_width); 1297 if (QDF_IS_STATUS_ERROR(status)) 1298 return; 1299 1300 if (awgn_info->center_freq != op_freq) { 1301 dcs_debug("SAP-%d: freq not match rpt:%u - op:%u", 1302 vdev_id, awgn_info->center_freq, op_freq); 1303 return; 1304 } 1305 1306 found = wlan_dcs_get_max_no_intf_bw(awgn_info, &tgt_width); 1307 if (found) { 1308 if (ch_width <= tgt_width) { 1309 dcs_debug("SAP-%d: both freq and bw are unchanged", 1310 vdev_id); 1311 return; 1312 } 1313 1314 tgt_freq = op_freq; 1315 } else { 1316 wlan_dcs_sap_select_chan(vdev, awgn_info, &tgt_freq, 1317 &tgt_width, true); 1318 } 1319 1320 /* If no chan is selected, means to stop sap */ 1321 dcs_debug("SAP-%d: target freq %u width %u", 1322 vdev_id, tgt_freq, tgt_width); 1323 wlan_dcs_switch_chan(vdev, tgt_freq, tgt_width); 1324 } 1325 1326 /** 1327 * wlan_dcs_awgn_process() - process awgn IM 1328 * @psoc: psoc ptr 1329 * @pdev_id: pdev id 1330 * @awgn_info: pointer to awgn info 1331 * 1332 * This function triggers channel change for all STAs and SAPs, according 1333 * to AWGN info. 1334 * 1335 * Return: None. 1336 */ 1337 static void 1338 wlan_dcs_awgn_process(struct wlan_objmgr_psoc *psoc, uint8_t pdev_id, 1339 struct wlan_host_dcs_awgn_info *awgn_info) 1340 { 1341 struct wlan_objmgr_pdev *pdev; 1342 1343 if (!wlan_dcs_is_awgnim_valid(awgn_info)) { 1344 dcs_err("Invalid awgnim event"); 1345 return; 1346 } 1347 1348 pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_DCS_ID); 1349 if (!pdev) { 1350 dcs_err("Invalid pdev id %d", pdev_id); 1351 return; 1352 } 1353 1354 dcs_debug("pdev id %u width %u freq %u freq0 %u fre1 %u bitmap 0x%x", 1355 pdev_id, awgn_info->channel_width, awgn_info->center_freq, 1356 awgn_info->center_freq0, awgn_info->center_freq1, 1357 awgn_info->chan_bw_intf_bitmap); 1358 1359 wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, 1360 wlan_dcs_process_awgn_sta, 1361 awgn_info, 0, WLAN_DCS_ID); 1362 1363 wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, 1364 wlan_dcs_process_awgn_sap, 1365 awgn_info, 0, WLAN_DCS_ID); 1366 1367 wlan_objmgr_pdev_release_ref(pdev, WLAN_DCS_ID); 1368 } 1369 1370 #ifdef CONFIG_AFC_SUPPORT 1371 /** 1372 * wlan_dcs_afc_sel_chan() - Select SAP new channel/bandwidth when AFC updated 1373 * @psoc: pointer to soc 1374 * @vdev_id: vdev id 1375 * @cur_freq: current channel frequency 1376 * @cur_bw: current channel bandwidth 1377 * @pref_bw: pointer to bandwidth of prefer to switch to when input, and target 1378 * bandwidth decided to switch to 1379 * 1380 * Return: target channel frequency to switch to 1381 */ 1382 static qdf_freq_t wlan_dcs_afc_sel_chan(struct wlan_objmgr_psoc *psoc, 1383 uint32_t vdev_id, 1384 qdf_freq_t cur_freq, 1385 enum phy_ch_width cur_bw, 1386 enum phy_ch_width *pref_bw) 1387 { 1388 struct dcs_psoc_priv_obj *dcs_psoc_priv; 1389 dcs_afc_select_chan_cb afc_sel_chan_cb; 1390 1391 if (!psoc) 1392 return 0; 1393 1394 dcs_psoc_priv = wlan_objmgr_psoc_get_comp_private_obj( 1395 psoc, 1396 WLAN_UMAC_COMP_DCS); 1397 if (!dcs_psoc_priv) 1398 return 0; 1399 1400 afc_sel_chan_cb = dcs_psoc_priv->afc_sel_chan_cbk.cbk; 1401 if (!afc_sel_chan_cb) 1402 return 0; 1403 1404 return afc_sel_chan_cb(dcs_psoc_priv->afc_sel_chan_cbk.arg, 1405 vdev_id, cur_freq, cur_bw, pref_bw); 1406 } 1407 1408 /** 1409 * wlan_dcs_afc_get_conn_info() - Iterate function to get connection channel 1410 * information of every vdev 1411 * @pdev: pointer to pdev 1412 * @object: pointer to iteration object 1413 * @arg: pointer to iteration argument 1414 * 1415 * Return: void 1416 */ 1417 static void 1418 wlan_dcs_afc_get_conn_info(struct wlan_objmgr_pdev *pdev, 1419 void *object, void *arg) 1420 { 1421 struct wlan_objmgr_vdev *vdev = object; 1422 struct wlan_dcs_conn_info *conn_info = arg; 1423 enum QDF_OPMODE op_mode; 1424 struct wlan_channel *chan; 1425 uint8_t vdev_id; 1426 1427 if (!vdev || !pdev || !conn_info) 1428 return; 1429 1430 if (conn_info->exit_condition) 1431 return; 1432 1433 if (wlan_vdev_mlme_is_active(vdev) != QDF_STATUS_SUCCESS) 1434 return; 1435 1436 vdev_id = wlan_vdev_get_id(vdev); 1437 op_mode = wlan_vdev_mlme_get_opmode(vdev); 1438 chan = wlan_vdev_get_active_channel(vdev); 1439 if (!chan) 1440 return; 1441 1442 switch (op_mode) { 1443 case QDF_STA_MODE: 1444 if (conn_info->sta_cnt >= WLAN_DCS_MAX_STA_NUM) { 1445 dcs_debug("too many STAs"); 1446 conn_info->exit_condition = true; 1447 break; 1448 } 1449 conn_info->sta[conn_info->sta_cnt].freq = chan->ch_freq; 1450 conn_info->sta[conn_info->sta_cnt].bw = chan->ch_width; 1451 conn_info->sta[conn_info->sta_cnt].vdev_id = vdev_id; 1452 conn_info->sta_cnt++; 1453 break; 1454 case QDF_SAP_MODE: 1455 if (WLAN_REG_IS_5GHZ_CH_FREQ(chan->ch_freq)) { 1456 if (conn_info->sap_5ghz_cnt >= WLAN_DCS_MAX_SAP_NUM) { 1457 dcs_debug("too many 5 GHz SAPs"); 1458 conn_info->exit_condition = true; 1459 } 1460 conn_info->sap_5ghz[conn_info->sap_5ghz_cnt].freq = 1461 chan->ch_freq; 1462 conn_info->sap_5ghz[conn_info->sap_5ghz_cnt].bw = 1463 chan->ch_width; 1464 conn_info->sap_5ghz[conn_info->sap_5ghz_cnt].vdev_id = 1465 vdev_id; 1466 conn_info->sap_5ghz_cnt++; 1467 } else if (WLAN_REG_IS_6GHZ_CHAN_FREQ(chan->ch_freq)) { 1468 if (conn_info->sap_6ghz_cnt >= WLAN_DCS_MAX_SAP_NUM) { 1469 dcs_debug("too many 6 GHz SAPs"); 1470 conn_info->exit_condition = true; 1471 } 1472 conn_info->sap_6ghz[conn_info->sap_6ghz_cnt].freq = 1473 chan->ch_freq; 1474 conn_info->sap_6ghz[conn_info->sap_6ghz_cnt].bw = 1475 chan->ch_width; 1476 conn_info->sap_6ghz[conn_info->sap_6ghz_cnt].vdev_id = 1477 vdev_id; 1478 conn_info->sap_6ghz_cnt++; 1479 } 1480 break; 1481 default: 1482 dcs_debug("not support op mode %d", op_mode); 1483 conn_info->exit_condition = true; 1484 break; 1485 } 1486 } 1487 1488 /** 1489 * wlan_dcs_afc_reduce_bw() - Get target bandwidth with fixed channel frequency 1490 * @pdev: pointer to pdev 1491 * @freq: channel frequency which is fixed because SCC with STA 1492 * @input_bw: SAP current channel bandwidth 1493 * 1494 * This function check every sub 20 MHz channel state which update by AFC, and 1495 * reduce channel bandwidth if sub channel is disable. 1496 * 1497 * Return: Reduced channel bandwidth 1498 */ 1499 static enum phy_ch_width wlan_dcs_afc_reduce_bw(struct wlan_objmgr_pdev *pdev, 1500 qdf_freq_t freq, 1501 enum phy_ch_width input_bw) 1502 { 1503 const struct bonded_channel_freq *bonded_chan_ptr = NULL; 1504 enum channel_state state; 1505 qdf_freq_t start_freq; 1506 bool find; 1507 1508 if (input_bw <= CH_WIDTH_20MHZ) 1509 return input_bw; 1510 1511 while (input_bw > CH_WIDTH_20MHZ) { 1512 state = wlan_reg_get_5g_bonded_channel_and_state_for_pwrmode( 1513 pdev, freq, input_bw, &bonded_chan_ptr, 1514 REG_CURRENT_PWR_MODE, NO_SCHANS_PUNC); 1515 if (state != CHANNEL_STATE_ENABLE) { 1516 input_bw = wlan_reg_get_next_lower_bandwidth(input_bw); 1517 continue; 1518 } 1519 find = false; 1520 start_freq = bonded_chan_ptr->start_freq; 1521 while (start_freq <= bonded_chan_ptr->end_freq) { 1522 if (wlan_reg_is_disable_in_secondary_list_for_freq( 1523 pdev, start_freq)) { 1524 find = true; 1525 break; 1526 } 1527 start_freq += 20; 1528 } 1529 if (find) 1530 input_bw = wlan_reg_get_next_lower_bandwidth(input_bw); 1531 else 1532 return input_bw; 1533 } 1534 return input_bw; 1535 } 1536 1537 /** 1538 * wlan_sap_update_tpc_on_channel() - Update vdev channel TPC parameters and 1539 * send TPC command 1540 * @pdev: pointer to pdev 1541 * @vdev_id: vdev id 1542 * @freq: SAP 6 GHz channel frequency 1543 * @bw: SAP 6 GHz channel bandwidth 1544 * 1545 * Return: void 1546 */ 1547 static void 1548 wlan_sap_update_tpc_on_channel(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id, 1549 qdf_freq_t freq, enum phy_ch_width bw) 1550 { 1551 struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); 1552 struct wlan_lmac_if_reg_tx_ops *tx_ops; 1553 struct vdev_mlme_obj *mlme_obj; 1554 struct wlan_objmgr_vdev *vdev; 1555 struct reg_tpc_power_info *tpc; 1556 bool is_psd; 1557 uint32_t i; 1558 uint16_t tx_power; 1559 int16_t psd_eirp; 1560 enum reg_6g_ap_type power_type; 1561 1562 if (!wlan_reg_is_ext_tpc_supported(psoc)) 1563 return; 1564 1565 if (wlan_reg_decide_6ghz_power_within_bw_for_freq( 1566 pdev, freq, bw, &is_psd, &tx_power, &psd_eirp, &power_type, 1567 REG_CURRENT_PWR_MODE, NO_SCHANS_PUNC) != 1568 QDF_STATUS_SUCCESS) 1569 return; 1570 1571 vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_DCS_ID); 1572 if (!vdev) 1573 return; 1574 1575 tx_ops = wlan_reg_get_tx_ops(psoc); 1576 1577 mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev); 1578 if (!mlme_obj) { 1579 dcs_err("vdev mlme obj is NULL"); 1580 goto release_vdev; 1581 } 1582 1583 tpc = &mlme_obj->reg_tpc_obj; 1584 if (tpc->is_psd_power != is_psd) { 1585 dcs_debug("psd flag changed"); 1586 goto release_vdev; 1587 } 1588 tpc->eirp_power = tx_power; 1589 tpc->power_type_6g = power_type; 1590 for (i = 0; i < tpc->num_pwr_levels; i++) { 1591 if (is_psd) 1592 tpc->chan_power_info[i].tx_power = (uint8_t)psd_eirp; 1593 else 1594 tpc->chan_power_info[i].tx_power = (uint8_t)tx_power; 1595 } 1596 1597 dcs_debug("6 GHz pwr type %d, is psd %d, pwr %d, psd %d, num pwr %d", 1598 power_type, is_psd, tx_power, psd_eirp, tpc->num_pwr_levels); 1599 1600 if (tx_ops->set_tpc_power) 1601 tx_ops->set_tpc_power(psoc, vdev_id, tpc); 1602 1603 release_vdev: 1604 wlan_objmgr_vdev_release_ref(vdev, WLAN_DCS_ID); 1605 } 1606 1607 /** 1608 * wlan_dcs_afc_sap_dcs_with_sta() - SAP channel switch when coexist with STA 1609 * @pdev: pointer to pdev handle 1610 * @conn_info: pointer to connection context of AFC DCS 1611 * 1612 * This function update TPC or restart SAP if doing SCC on 6 GHz with STA 1613 * 1614 * Return: void 1615 */ 1616 static void 1617 wlan_dcs_afc_sap_dcs_with_sta(struct wlan_objmgr_pdev *pdev, 1618 struct wlan_dcs_conn_info *conn_info) 1619 { 1620 uint32_t i; 1621 qdf_freq_t target_freq = conn_info->sta[0].freq; 1622 enum phy_ch_width target_bw = CH_WIDTH_20MHZ; 1623 struct wlan_objmgr_vdev *vdev; 1624 1625 if (!WLAN_REG_IS_6GHZ_CHAN_FREQ(conn_info->sta[0].freq)) 1626 return; 1627 1628 for (i = 0; i < conn_info->sap_6ghz_cnt; i++) { 1629 if (conn_info->sap_6ghz[i].freq == 1630 conn_info->sta[0].freq) { 1631 /* 1632 * sta operate under control of ap, if stop sap, 1633 * cannot start by itself, so just update tpc as sta, 1634 * if tx power is minimum of SCC tpc commands, no 1635 * need to update sap tpc command. 1636 * assume sta will move to safe channel by ap and 1637 * sap can move channel accordingly. 1638 */ 1639 if (wlan_reg_is_disable_in_secondary_list_for_freq( 1640 pdev, conn_info->sta[0].freq)) 1641 continue; 1642 1643 target_bw = wlan_dcs_afc_reduce_bw( 1644 pdev, 1645 conn_info->sap_6ghz[i].freq, 1646 conn_info->sap_6ghz[i].bw); 1647 1648 if (target_bw == conn_info->sap_6ghz[i].bw) { 1649 wlan_sap_update_tpc_on_channel( 1650 pdev, 1651 conn_info->sap_6ghz[i].vdev_id, 1652 conn_info->sap_6ghz[i].freq, 1653 target_bw); 1654 continue; 1655 } 1656 1657 vdev = wlan_objmgr_get_vdev_by_id_from_pdev( 1658 pdev, 1659 conn_info->sap_6ghz[i].vdev_id, 1660 WLAN_DCS_ID); 1661 if (!vdev) 1662 continue; 1663 1664 /* tpc update once csa complete */ 1665 wlan_dcs_switch_chan(vdev, target_freq, target_bw); 1666 wlan_objmgr_vdev_release_ref(vdev, WLAN_DCS_ID); 1667 } 1668 } 1669 } 1670 1671 #ifdef WLAN_POLICY_MGR_ENABLE 1672 /** 1673 * wlan_dcs_afc_6ghz_capable() - API to check SAP configure is able to operate 1674 * on 6 GHz 1675 * @psoc: pointer to SOC 1676 * @vdev_id: vdev id 1677 * 1678 * Return: Return true if SAP is able to operate on 6 GHz 1679 */ 1680 static inline bool 1681 wlan_dcs_afc_6ghz_capable(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) 1682 { 1683 return policy_mgr_get_ap_6ghz_capable(psoc, vdev_id, NULL); 1684 } 1685 #else 1686 static inline bool 1687 wlan_dcs_afc_6ghz_capable(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) 1688 { 1689 return false; 1690 } 1691 #endif 1692 1693 /** 1694 * wlan_dcs_afc_5ghz6ghz_sap_dcs() - SAP on 5 GHz or 6 GHz channel to do 1695 * channel switch. 1696 * @pdev: pointer to pdev handle 1697 * @conn_info: pointer to connection context for AFC DCS 1698 * 1699 * This function is trigger by AFC event and 6 GHz channels' state has been 1700 * updated, restart SAP to SP channel if possible, gain better performance. 1701 * 1702 * Return: void 1703 */ 1704 static void 1705 wlan_dcs_afc_5ghz6ghz_sap_dcs(struct wlan_objmgr_pdev *pdev, 1706 struct wlan_dcs_conn_info *conn_info) 1707 { 1708 uint32_t i; 1709 struct wlan_objmgr_vdev *vdev; 1710 uint8_t max_bw_vdev_id; 1711 qdf_freq_t max_bw_freq, target_freq; 1712 enum phy_ch_width max_bw = CH_WIDTH_20MHZ; 1713 enum phy_ch_width pref_bw; 1714 1715 if (conn_info->sap_5ghz_cnt) { 1716 max_bw = conn_info->sap_5ghz[0].bw; 1717 max_bw_vdev_id = conn_info->sap_5ghz[0].vdev_id; 1718 max_bw_freq = conn_info->sap_5ghz[0].freq; 1719 for (i = 1; i < conn_info->sap_5ghz_cnt; i++) { 1720 if (conn_info->sap_5ghz[i].bw > max_bw) { 1721 max_bw = conn_info->sap_5ghz[i].bw; 1722 max_bw_vdev_id = conn_info->sap_5ghz[i].vdev_id; 1723 max_bw_freq = conn_info->sap_5ghz[i].freq; 1724 } 1725 } 1726 } else if (conn_info->sap_6ghz_cnt) { 1727 max_bw = conn_info->sap_6ghz[0].bw; 1728 max_bw_vdev_id = conn_info->sap_6ghz[0].vdev_id; 1729 max_bw_freq = conn_info->sap_6ghz[0].freq; 1730 for (i = 1; i < conn_info->sap_6ghz_cnt; i++) { 1731 if (conn_info->sap_6ghz[i].bw > max_bw) { 1732 max_bw = conn_info->sap_6ghz[i].bw; 1733 max_bw_vdev_id = conn_info->sap_6ghz[i].vdev_id; 1734 max_bw_freq = conn_info->sap_6ghz[i].freq; 1735 } 1736 } 1737 } else { 1738 return; 1739 } 1740 1741 /* 1742 * After several AFC event update, if maximum bandwidth shrink to 1743 * 20 MHz, set prefer bandwidth to pre-defined value like 80 MHz, 1744 * so it can expand bandwidth and gain better performance. 1745 */ 1746 if (max_bw == CH_WIDTH_20MHZ) 1747 pref_bw = WLAN_DCS_AFC_PREFER_BW; 1748 else 1749 pref_bw = max_bw; 1750 1751 target_freq = wlan_dcs_afc_sel_chan( 1752 wlan_pdev_get_psoc(pdev), 1753 max_bw_vdev_id, 1754 max_bw_freq, max_bw, &pref_bw); 1755 1756 if (!target_freq) 1757 return; 1758 1759 if (WLAN_REG_IS_6GHZ_CHAN_FREQ(target_freq) && 1760 conn_info->sap_5ghz_cnt) { 1761 for (i = 0; i < conn_info->sap_5ghz_cnt; i++) { 1762 if (!wlan_dcs_afc_6ghz_capable( 1763 wlan_pdev_get_psoc(pdev), 1764 conn_info->sap_5ghz[i].vdev_id)) { 1765 dcs_debug("vdev %d has no 6 GHz capability", 1766 conn_info->sap_5ghz[i].vdev_id); 1767 return; 1768 } 1769 } 1770 } 1771 1772 if (conn_info->sap_5ghz_cnt) { 1773 for (i = 0; i < conn_info->sap_5ghz_cnt; i++) { 1774 if (target_freq == conn_info->sap_5ghz[i].freq && 1775 pref_bw == conn_info->sap_5ghz[i].bw) 1776 continue; 1777 vdev = wlan_objmgr_get_vdev_by_id_from_pdev( 1778 pdev, 1779 conn_info->sap_5ghz[i].vdev_id, 1780 WLAN_DCS_ID); 1781 if (!vdev) 1782 continue; 1783 1784 wlan_dcs_switch_chan(vdev, target_freq, pref_bw); 1785 wlan_objmgr_vdev_release_ref(vdev, WLAN_DCS_ID); 1786 } 1787 } else if (conn_info->sap_6ghz_cnt) { 1788 for (i = 0; i < conn_info->sap_6ghz_cnt; i++) { 1789 if (target_freq == conn_info->sap_6ghz[i].freq && 1790 pref_bw == conn_info->sap_6ghz[i].bw) 1791 continue; 1792 vdev = wlan_objmgr_get_vdev_by_id_from_pdev( 1793 pdev, 1794 conn_info->sap_6ghz[i].vdev_id, 1795 WLAN_DCS_ID); 1796 if (!vdev) 1797 continue; 1798 1799 wlan_dcs_switch_chan(vdev, target_freq, pref_bw); 1800 wlan_objmgr_vdev_release_ref(vdev, WLAN_DCS_ID); 1801 } 1802 } 1803 } 1804 1805 /** 1806 * wlan_dcs_afc_process() - Dynamic SAP channel switch after AFC update 1807 * @psoc: psoc handle 1808 * @pdev_id: pdev id 1809 * 1810 * Return: void 1811 */ 1812 static void 1813 wlan_dcs_afc_process(struct wlan_objmgr_psoc *psoc, uint8_t pdev_id) 1814 { 1815 struct wlan_objmgr_pdev *pdev; 1816 struct wlan_dcs_conn_info conn_info = {0}; 1817 1818 pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_DCS_ID); 1819 if (!pdev) { 1820 dcs_err("Invalid pdev id %d", pdev_id); 1821 return; 1822 } 1823 1824 wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, 1825 wlan_dcs_afc_get_conn_info, 1826 &conn_info, 0, WLAN_DCS_ID); 1827 if (conn_info.exit_condition) 1828 goto pdev_release; 1829 1830 if ((conn_info.sap_5ghz_cnt && conn_info.sap_6ghz_cnt) || 1831 (!conn_info.sap_5ghz_cnt && !conn_info.sap_6ghz_cnt)) { 1832 dcs_debug("NA for %d 5 GHz SAP, %d 6 GHz SAP", 1833 conn_info.sap_5ghz_cnt, conn_info.sap_6ghz_cnt); 1834 goto pdev_release; 1835 } 1836 1837 if (conn_info.sta_cnt && 1838 !WLAN_REG_IS_24GHZ_CH_FREQ(conn_info.sta[0].freq)) 1839 wlan_dcs_afc_sap_dcs_with_sta(pdev, &conn_info); 1840 else 1841 wlan_dcs_afc_5ghz6ghz_sap_dcs(pdev, &conn_info); 1842 1843 pdev_release: 1844 wlan_objmgr_pdev_release_ref(pdev, WLAN_DCS_ID); 1845 } 1846 #else 1847 static inline void 1848 wlan_dcs_afc_process(struct wlan_objmgr_psoc *psoc, uint8_t pdev_id) {} 1849 #endif 1850 1851 QDF_STATUS 1852 wlan_dcs_process(struct wlan_objmgr_psoc *psoc, 1853 struct wlan_host_dcs_event *event) 1854 { 1855 struct dcs_pdev_priv_obj *dcs_pdev_priv; 1856 bool start_dcs_cbk_handler = false; 1857 1858 if (!psoc || !event) { 1859 dcs_err("psoc or event is NULL"); 1860 return QDF_STATUS_E_INVAL; 1861 } 1862 1863 dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc, 1864 event->dcs_param.pdev_id); 1865 if (!dcs_pdev_priv) { 1866 dcs_err("dcs pdev private object is null"); 1867 return QDF_STATUS_E_INVAL; 1868 } 1869 1870 if (unlikely(dcs_pdev_priv->dcs_host_params.dcs_debug 1871 >= DCS_DEBUG_VERBOSE)) 1872 dcs_debug("dcs_enable: %u, interference_type: %u, pdev_id: %u", 1873 dcs_pdev_priv->dcs_host_params.dcs_enable, 1874 event->dcs_param.interference_type, 1875 event->dcs_param.pdev_id); 1876 1877 switch (event->dcs_param.interference_type) { 1878 case WLAN_HOST_DCS_CWIM: 1879 break; 1880 case WLAN_HOST_DCS_WLANIM: 1881 if (!dcs_pdev_priv->dcs_host_params.dcs_enable) 1882 break; 1883 1884 if (dcs_pdev_priv->dcs_host_params.dcs_enable & 1885 WLAN_HOST_DCS_WLANIM) 1886 start_dcs_cbk_handler = 1887 wlan_dcs_wlan_interference_process( 1888 &event->wlan_stat, 1889 dcs_pdev_priv); 1890 if (dcs_pdev_priv->user_cb && 1891 dcs_pdev_priv->dcs_host_params.notify_user) { 1892 dcs_pdev_priv->dcs_host_params.notify_user = 0; 1893 dcs_pdev_priv->user_cb(dcs_pdev_priv->requestor_vdev_id, 1894 &dcs_pdev_priv->dcs_im_stats.user_dcs_im_stats, 1895 0); 1896 } 1897 if (start_dcs_cbk_handler) 1898 wlan_dcs_frequency_control(psoc, 1899 dcs_pdev_priv, 1900 event); 1901 break; 1902 case WLAN_HOST_DCS_AWGNIM: 1903 /* Skip frequency control for AWGNIM */ 1904 wlan_dcs_awgn_process(psoc, event->dcs_param.pdev_id, 1905 &event->awgn_info); 1906 break; 1907 case WLAN_HOST_DCS_AFC: 1908 wlan_dcs_afc_process(psoc, event->dcs_param.pdev_id); 1909 break; 1910 default: 1911 dcs_err("unidentified interference type reported"); 1912 break; 1913 } 1914 1915 return QDF_STATUS_SUCCESS; 1916 } 1917 1918 void wlan_dcs_clear(struct wlan_objmgr_psoc *psoc, uint32_t pdev_id) 1919 { 1920 struct dcs_pdev_priv_obj *dcs_pdev_priv; 1921 1922 if (!psoc) { 1923 dcs_err("psoc is null"); 1924 return; 1925 } 1926 1927 dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc, pdev_id); 1928 if (!dcs_pdev_priv) { 1929 dcs_err("dcs pdev private object is null"); 1930 return; 1931 } 1932 1933 qdf_timer_stop(&dcs_pdev_priv->dcs_disable_timer); 1934 qdf_mem_set(&dcs_pdev_priv->dcs_im_stats, 1935 sizeof(dcs_pdev_priv->dcs_im_stats), 0); 1936 qdf_mem_set(dcs_pdev_priv->dcs_freq_ctrl_params.timestamp, 1937 MAX_DCS_TIME_RECORD * sizeof(unsigned long), 0); 1938 dcs_pdev_priv->dcs_freq_ctrl_params.dcs_happened_count = 0; 1939 dcs_pdev_priv->dcs_freq_ctrl_params.disable_delay_process = false; 1940 wlan_dcs_set_algorithm_process(psoc, pdev_id, false); 1941 } 1942 1943 void wlan_dcs_set_algorithm_process(struct wlan_objmgr_psoc *psoc, 1944 uint32_t pdev_id, 1945 bool dcs_algorithm_process) 1946 { 1947 struct dcs_pdev_priv_obj *dcs_pdev_priv; 1948 1949 dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc, pdev_id); 1950 if (!dcs_pdev_priv) { 1951 dcs_err("dcs pdev private object is null"); 1952 return; 1953 } 1954 1955 if (dcs_pdev_priv->dcs_host_params.force_disable_algorithm) { 1956 dcs_debug("dcs algorithm is disabled forcely"); 1957 dcs_pdev_priv->dcs_host_params.dcs_algorithm_process = false; 1958 return; 1959 } 1960 1961 dcs_pdev_priv->dcs_host_params.dcs_algorithm_process = 1962 dcs_algorithm_process; 1963 } 1964