1 /* 2 * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022 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 35 struct dcs_pdev_priv_obj * 36 wlan_dcs_get_pdev_private_obj(struct wlan_objmgr_psoc *psoc, uint32_t pdev_id) 37 { 38 struct dcs_psoc_priv_obj *dcs_psoc_obj; 39 struct dcs_pdev_priv_obj *dcs_pdev_priv = NULL; 40 41 if (!psoc) { 42 dcs_err("psoc is null"); 43 goto end; 44 } 45 46 dcs_psoc_obj = wlan_objmgr_psoc_get_comp_private_obj( 47 psoc, 48 WLAN_UMAC_COMP_DCS); 49 if (!dcs_psoc_obj) { 50 dcs_err("dcs psoc object is null"); 51 goto end; 52 } 53 54 if (pdev_id >= WLAN_DCS_MAX_PDEVS) { 55 dcs_err("invalid pdev_id: %u", pdev_id); 56 goto end; 57 } 58 59 dcs_pdev_priv = &dcs_psoc_obj->dcs_pdev_priv[pdev_id]; 60 end: 61 62 return dcs_pdev_priv; 63 } 64 65 QDF_STATUS wlan_dcs_attach(struct wlan_objmgr_psoc *psoc) 66 { 67 struct wlan_target_if_dcs_tx_ops *dcs_tx_ops; 68 69 if (!psoc) { 70 dcs_err("psoc is null"); 71 return QDF_STATUS_E_NULL_VALUE; 72 } 73 74 dcs_tx_ops = target_if_dcs_get_tx_ops(psoc); 75 if (!dcs_tx_ops) { 76 dcs_err("tx_ops is null!"); 77 return QDF_STATUS_E_NULL_VALUE; 78 } 79 80 if (!dcs_tx_ops->dcs_attach) { 81 dcs_err("dcs_attach function is null!"); 82 return QDF_STATUS_E_NULL_VALUE; 83 } 84 85 return dcs_tx_ops->dcs_attach(psoc); 86 } 87 88 QDF_STATUS wlan_dcs_detach(struct wlan_objmgr_psoc *psoc) 89 { 90 struct wlan_target_if_dcs_tx_ops *dcs_tx_ops; 91 92 if (!psoc) { 93 dcs_err("psoc is null"); 94 return QDF_STATUS_E_NULL_VALUE; 95 } 96 97 dcs_tx_ops = target_if_dcs_get_tx_ops(psoc); 98 if (!dcs_tx_ops) { 99 dcs_err("tx_ops is null!"); 100 return QDF_STATUS_E_NULL_VALUE; 101 } 102 103 if (!dcs_tx_ops->dcs_detach) { 104 dcs_err("dcs_detach function is null!"); 105 return QDF_STATUS_E_NULL_VALUE; 106 } 107 108 return dcs_tx_ops->dcs_detach(psoc); 109 } 110 111 QDF_STATUS wlan_dcs_cmd_send(struct wlan_objmgr_psoc *psoc, 112 uint32_t pdev_id, 113 bool is_host_pdev_id) 114 { 115 struct wlan_target_if_dcs_tx_ops *dcs_tx_ops; 116 struct dcs_pdev_priv_obj *dcs_pdev_priv; 117 uint32_t dcs_enable; 118 119 if (!psoc) { 120 dcs_err("psoc is null"); 121 return QDF_STATUS_E_NULL_VALUE; 122 } 123 124 dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc, pdev_id); 125 if (!dcs_pdev_priv) { 126 dcs_err("dcs pdev private object is null"); 127 return QDF_STATUS_E_NULL_VALUE; 128 } 129 130 dcs_enable = dcs_pdev_priv->dcs_host_params.dcs_enable & 131 dcs_pdev_priv->dcs_host_params.dcs_enable_cfg; 132 dcs_tx_ops = target_if_dcs_get_tx_ops(psoc); 133 134 if (dcs_tx_ops && dcs_tx_ops->dcs_cmd_send) { 135 dcs_debug("dcs_enable: %u, pdev_id: %u", dcs_enable, pdev_id); 136 return dcs_tx_ops->dcs_cmd_send(psoc, 137 pdev_id, 138 is_host_pdev_id, 139 dcs_enable); 140 } 141 142 return QDF_STATUS_SUCCESS; 143 } 144 145 /** 146 * wlan_dcs_im_copy_stats() - dcs target interference mitigation statistics copy 147 * @prev_stats: previous statistics pointer 148 * @curr_stats: current statistics pointer 149 * 150 * Return: None 151 */ 152 static inline void 153 wlan_dcs_im_copy_stats(struct wlan_host_dcs_im_tgt_stats *prev_stats, 154 struct wlan_host_dcs_im_tgt_stats *curr_stats) 155 { 156 if (!prev_stats || !curr_stats) { 157 dcs_err("previous or current stats is null"); 158 return; 159 } 160 161 /* 162 * Right now no other actions are required beyond memcopy, 163 * if required the rest of the code would follow. 164 */ 165 qdf_mem_copy(prev_stats, curr_stats, 166 sizeof(struct wlan_host_dcs_im_tgt_stats)); 167 } 168 169 /** 170 * wlan_dcs_im_print_stats() - print current/previous dcs target im statistics 171 * @prev_stats: previous statistics pointer 172 * @curr_stats: current statistics pointer 173 * 174 * Return: None 175 */ 176 static void 177 wlan_dcs_im_print_stats(struct wlan_host_dcs_im_tgt_stats *prev_stats, 178 struct wlan_host_dcs_im_tgt_stats *curr_stats) 179 { 180 if (!prev_stats || !curr_stats) { 181 dcs_err("previous or current stats is null"); 182 return; 183 } 184 185 /* Debug, dump all received stats first */ 186 dcs_debug("tgt_curr/tsf: %u", curr_stats->reg_tsf32); 187 dcs_debug("tgt_curr/last_ack_rssi: %u", curr_stats->last_ack_rssi); 188 dcs_debug("tgt_curr/tx_waste_time: %u", curr_stats->tx_waste_time); 189 dcs_debug("tgt_curr/dcs_rx_time: %u", curr_stats->rx_time); 190 dcs_debug("tgt_curr/listen_time: %u", 191 curr_stats->mib_stats.listen_time); 192 dcs_debug("tgt_curr/tx_frame_cnt: %u", 193 curr_stats->mib_stats.reg_tx_frame_cnt); 194 dcs_debug("tgt_curr/rx_frame_cnt: %u", 195 curr_stats->mib_stats.reg_rx_frame_cnt); 196 dcs_debug("tgt_curr/rxclr_cnt: %u", 197 curr_stats->mib_stats.reg_rxclr_cnt); 198 dcs_debug("tgt_curr/reg_cycle_cnt: %u", 199 curr_stats->mib_stats.reg_cycle_cnt); 200 dcs_debug("tgt_curr/rxclr_ext_cnt: %u", 201 curr_stats->mib_stats.reg_rxclr_ext_cnt); 202 dcs_debug("tgt_curr/ofdm_phyerr_cnt: %u", 203 curr_stats->mib_stats.reg_ofdm_phyerr_cnt); 204 dcs_debug("tgt_curr/cck_phyerr_cnt: %u", 205 curr_stats->mib_stats.reg_cck_phyerr_cnt); 206 207 dcs_debug("tgt_prev/tsf: %u", prev_stats->reg_tsf32); 208 dcs_debug("tgt_prev/last_ack_rssi: %u", prev_stats->last_ack_rssi); 209 dcs_debug("tgt_prev/tx_waste_time: %u", prev_stats->tx_waste_time); 210 dcs_debug("tgt_prev/rx_time: %u", prev_stats->rx_time); 211 dcs_debug("tgt_prev/listen_time: %u", 212 prev_stats->mib_stats.listen_time); 213 dcs_debug("tgt_prev/tx_frame_cnt: %u", 214 prev_stats->mib_stats.reg_tx_frame_cnt); 215 dcs_debug("tgt_prev/rx_frame_cnt: %u", 216 prev_stats->mib_stats.reg_rx_frame_cnt); 217 dcs_debug("tgt_prev/rxclr_cnt: %u", 218 prev_stats->mib_stats.reg_rxclr_cnt); 219 dcs_debug("tgt_prev/reg_cycle_cnt: %u", 220 prev_stats->mib_stats.reg_cycle_cnt); 221 dcs_debug("tgt_prev/rxclr_ext_cnt: %u", 222 prev_stats->mib_stats.reg_rxclr_ext_cnt); 223 dcs_debug("tgt_prev/ofdm_phyerr_cnt: %u", 224 prev_stats->mib_stats.reg_ofdm_phyerr_cnt); 225 dcs_debug("tgt_prev/cck_phyerr_cnt: %u", 226 prev_stats->mib_stats.reg_cck_phyerr_cnt); 227 } 228 229 /** 230 * wlan_dcs_update_chan_util() - update chan utilization of dcs stats 231 * @p_dcs_im_stats: pointer to pdev_dcs_im_stats 232 * @rx_cu: rx channel utilization 233 * @tx_cu: tx channel utilization 234 * @obss_rx_cu: obss rx channel utilization 235 * @total_cu: total channel utilization 236 * @chan_nf: Channel noise floor (units are in dBm) 237 * 238 * Return: Void 239 */ 240 static void wlan_dcs_update_chan_util(struct pdev_dcs_im_stats *p_dcs_im_stats, 241 uint32_t rx_cu, uint32_t tx_cu, 242 uint32_t obss_rx_cu, 243 uint32_t total_cu, uint32_t chan_nf) 244 { 245 if (p_dcs_im_stats) { 246 p_dcs_im_stats->dcs_ch_util_im_stats.rx_cu = rx_cu; 247 p_dcs_im_stats->dcs_ch_util_im_stats.tx_cu = tx_cu; 248 p_dcs_im_stats->dcs_ch_util_im_stats.obss_rx_cu = obss_rx_cu; 249 p_dcs_im_stats->dcs_ch_util_im_stats.total_cu = total_cu; 250 p_dcs_im_stats->dcs_ch_util_im_stats.chan_nf = chan_nf; 251 } 252 } 253 254 /** 255 * wlan_dcs_wlan_interference_process() - dcs detection algorithm handling 256 * @curr_stats: current target im stats pointer 257 * @dcs_pdev_priv: dcs pdev priv pointer 258 * 259 * Return: true or false means start dcs callback handler or not 260 */ 261 static bool 262 wlan_dcs_wlan_interference_process( 263 struct wlan_host_dcs_im_tgt_stats *curr_stats, 264 struct dcs_pdev_priv_obj *dcs_pdev_priv) 265 { 266 struct wlan_host_dcs_im_tgt_stats *prev_stats; 267 struct pdev_dcs_params dcs_host_params; 268 struct pdev_dcs_im_stats *p_dcs_im_stats; 269 bool start_dcs_cbk_handler = false; 270 271 uint32_t reg_tsf_delta = 0; 272 uint32_t scaled_reg_tsf_delta; 273 uint32_t rxclr_delta = 0; 274 uint32_t rxclr_ext_delta = 0; 275 uint32_t cycle_count_delta = 0; 276 uint32_t scaled_cycle_count_delta; 277 uint32_t tx_frame_delta = 0; 278 uint32_t rx_frame_delta = 0; 279 uint32_t my_bss_rx_delta = 0; 280 uint32_t reg_total_cu = 0; 281 uint32_t reg_tx_cu = 0; 282 uint32_t reg_rx_cu = 0; 283 uint32_t obss_rx_cu = 0; 284 uint32_t reg_unused_cu = 0; 285 uint32_t rx_time_cu = 0; 286 uint32_t reg_ofdm_phyerr_delta = 0; 287 uint32_t reg_cck_phyerr_delta = 0; 288 uint32_t reg_ofdm_phyerr_cu = 0; 289 uint32_t ofdm_phy_err_rate = 0; 290 uint32_t cck_phy_err_rate = 0; 291 uint32_t max_phy_err_rate = 0; 292 uint32_t max_phy_err_count = 0; 293 uint32_t total_wasted_cu = 0; 294 uint32_t wasted_tx_cu = 0; 295 uint32_t tx_err = 0; 296 uint32_t too_many_phy_errors = 0; 297 298 if (!curr_stats) { 299 dcs_err("curr_stats is NULL"); 300 goto end; 301 } 302 303 if (!dcs_pdev_priv) { 304 dcs_err("dcs pdev private object is NULL"); 305 goto end; 306 } 307 308 dcs_host_params = dcs_pdev_priv->dcs_host_params; 309 p_dcs_im_stats = &dcs_pdev_priv->dcs_im_stats; 310 prev_stats = &dcs_pdev_priv->dcs_im_stats.prev_dcs_im_stats; 311 312 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) 313 wlan_dcs_im_print_stats(prev_stats, curr_stats); 314 315 /* 316 * Counters would have wrapped. Ideally we should be able to figure this 317 * out, but we never know how many times counters wrapped, just ignore. 318 */ 319 if ((curr_stats->mib_stats.listen_time <= 0) || 320 (curr_stats->reg_tsf32 <= prev_stats->reg_tsf32)) { 321 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) 322 dcs_debug("ignoring due to negative TSF value"); 323 goto copy_stats; 324 } 325 326 reg_tsf_delta = curr_stats->reg_tsf32 - prev_stats->reg_tsf32; 327 328 /* 329 * Do nothing if current stats are not seeming good, probably 330 * a reset happened on chip, force cleared 331 */ 332 if (prev_stats->mib_stats.reg_rxclr_cnt > 333 curr_stats->mib_stats.reg_rxclr_cnt) { 334 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) 335 dcs_debug("ignoring due to negative rxclr count"); 336 goto copy_stats; 337 } 338 339 rxclr_delta = curr_stats->mib_stats.reg_rxclr_cnt - 340 prev_stats->mib_stats.reg_rxclr_cnt; 341 rxclr_ext_delta = curr_stats->mib_stats.reg_rxclr_ext_cnt - 342 prev_stats->mib_stats.reg_rxclr_ext_cnt; 343 tx_frame_delta = curr_stats->mib_stats.reg_tx_frame_cnt - 344 prev_stats->mib_stats.reg_tx_frame_cnt; 345 346 rx_frame_delta = curr_stats->mib_stats.reg_rx_frame_cnt - 347 prev_stats->mib_stats.reg_rx_frame_cnt; 348 349 cycle_count_delta = curr_stats->mib_stats.reg_cycle_cnt - 350 prev_stats->mib_stats.reg_cycle_cnt; 351 352 my_bss_rx_delta = curr_stats->my_bss_rx_cycle_count - 353 prev_stats->my_bss_rx_cycle_count; 354 355 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) 356 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", 357 rxclr_delta, rxclr_ext_delta, tx_frame_delta, 358 rx_frame_delta, cycle_count_delta, my_bss_rx_delta); 359 360 /* Update user stats */ 361 wlan_dcs_pdev_obj_lock(dcs_pdev_priv); 362 if (dcs_pdev_priv->dcs_host_params.user_request_count) { 363 struct wlan_host_dcs_im_user_stats *p_user_stats = 364 &p_dcs_im_stats->user_dcs_im_stats; 365 366 p_user_stats->cycle_count += cycle_count_delta; 367 p_user_stats->rxclr_count += rxclr_delta; 368 p_user_stats->rx_frame_count += rx_frame_delta; 369 p_user_stats->my_bss_rx_cycle_count += my_bss_rx_delta; 370 if (0 == p_user_stats->max_rssi && 371 0 == p_user_stats->min_rssi) { 372 p_user_stats->max_rssi = curr_stats->last_ack_rssi; 373 p_user_stats->min_rssi = curr_stats->last_ack_rssi; 374 } else { 375 if (curr_stats->last_ack_rssi > p_user_stats->max_rssi) 376 p_user_stats->max_rssi = 377 curr_stats->last_ack_rssi; 378 if (curr_stats->last_ack_rssi < p_user_stats->min_rssi) 379 p_user_stats->min_rssi = 380 curr_stats->last_ack_rssi; 381 } 382 dcs_pdev_priv->dcs_host_params.user_request_count--; 383 if (0 == dcs_pdev_priv->dcs_host_params.user_request_count) 384 dcs_pdev_priv->dcs_host_params.notify_user = 1; 385 } 386 wlan_dcs_pdev_obj_unlock(dcs_pdev_priv); 387 388 /* 389 * Total channel utiliztaion is the amount of time RXCLR is 390 * counted. RXCLR is counted, when 'RX is NOT clear', please 391 * refer to mac documentation. It means either TX or RX is ON 392 * 393 * Why shift by 8 ? after multiplication it could overflow. At one 394 * second rate, normally neither cycle_count_delta nor the tsf_delta 395 * would be zero after shift by 8 bits. In corner case, host resets 396 * dcs stats, and at the same time tsf counters is wrapped. 397 * Then all the variable in prev_stats are 0, and the variable in 398 * curr_stats may be a small value, so add check for cycle_count_delta 399 * and the tsf_delta after shift by 8 bits. 400 */ 401 scaled_cycle_count_delta = cycle_count_delta >> 8; 402 scaled_reg_tsf_delta = reg_tsf_delta >> 8; 403 if (!scaled_cycle_count_delta || !scaled_reg_tsf_delta) { 404 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) 405 dcs_debug("cycle count or TSF NULL --Investigate--"); 406 goto copy_stats; 407 } 408 reg_total_cu = ((rxclr_delta >> 8) * 100) / scaled_cycle_count_delta; 409 reg_tx_cu = ((tx_frame_delta >> 8) * 100) / scaled_cycle_count_delta; 410 reg_rx_cu = ((rx_frame_delta >> 8) * 100) / scaled_cycle_count_delta; 411 rx_time_cu = ((curr_stats->rx_time >> 8) * 100) / scaled_reg_tsf_delta; 412 obss_rx_cu = (((rx_frame_delta - my_bss_rx_delta) >> 8) * 100) / 413 scaled_cycle_count_delta; 414 wlan_dcs_update_chan_util(p_dcs_im_stats, reg_rx_cu, reg_tx_cu, 415 obss_rx_cu, reg_total_cu, 416 curr_stats->chan_nf); 417 418 /* 419 * Amount of the time AP received cannot go higher than the receive 420 * cycle count delta. If at all it is, there should have been a 421 * computation error, ceil it to receive_cycle_count_diff 422 */ 423 if (rx_time_cu > reg_rx_cu) 424 rx_time_cu = reg_rx_cu; 425 426 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) 427 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", 428 reg_total_cu, reg_tx_cu, reg_rx_cu, 429 rx_time_cu, obss_rx_cu, 430 dcs_host_params.dcs_algorithm_process); 431 432 /* 433 * For below scenario, will ignore dcs event data and won't do 434 * interference detection algorithm calculation: 435 * 1: Current SAP channel isn't on 5G band 436 * 2: In the process of ACS 437 * 3: In the process of dcs disabling dcs_restart_delay time duration 438 */ 439 if (!dcs_host_params.dcs_algorithm_process) 440 goto copy_stats; 441 442 /* 443 * Unusable channel utilization is amount of time that we 444 * spent in backoff or waiting for other transmit/receive to 445 * complete. If there is interference it is more likely that 446 * we overshoot the limit. In case of multiple stations, we 447 * still see increased channel utilization. This assumption may 448 * not be true for the VOW scenario where either multicast or 449 * unicast-UDP is used ( mixed traffic would still cause high 450 * channel utilization). 451 */ 452 wasted_tx_cu = ((curr_stats->tx_waste_time >> 8) * 100) / 453 scaled_reg_tsf_delta; 454 455 /* 456 * Transmit channel utilization cannot go higher than the amount of time 457 * wasted, if so cap the wastage to transmit channel utillzation. This 458 * could happen to compution error. 459 */ 460 if (reg_tx_cu < wasted_tx_cu) 461 wasted_tx_cu = reg_tx_cu; 462 463 tx_err = (reg_tx_cu && wasted_tx_cu) ? 464 (wasted_tx_cu * 100) / reg_tx_cu : 0; 465 466 /* 467 * The below actually gives amount of time we are not using, or the 468 * interferer is active. 469 * rx_time_cu is what computed receive time *NOT* rx_cycle_count 470 * rx_cycle_count is our receive+interferer's transmit 471 * un-used is really total_cycle_counts - 472 * (our_rx_time(rx_time_cu) + our_receive_time) 473 */ 474 reg_unused_cu = (reg_total_cu >= (reg_tx_cu + rx_time_cu)) ? 475 (reg_total_cu - (reg_tx_cu + rx_time_cu)) : 0; 476 477 /* If any retransmissions are there, count them as wastage */ 478 total_wasted_cu = reg_unused_cu + wasted_tx_cu; 479 480 /* Check ofdm and cck errors */ 481 if (unlikely(curr_stats->mib_stats.reg_ofdm_phyerr_cnt < 482 prev_stats->mib_stats.reg_ofdm_phyerr_cnt)) 483 reg_ofdm_phyerr_delta = 484 curr_stats->mib_stats.reg_ofdm_phyerr_cnt; 485 else 486 reg_ofdm_phyerr_delta = 487 curr_stats->mib_stats.reg_ofdm_phyerr_cnt - 488 prev_stats->mib_stats.reg_ofdm_phyerr_cnt; 489 490 if (unlikely(curr_stats->mib_stats.reg_cck_phyerr_cnt < 491 prev_stats->mib_stats.reg_cck_phyerr_cnt)) 492 reg_cck_phyerr_delta = curr_stats->mib_stats.reg_cck_phyerr_cnt; 493 else 494 reg_cck_phyerr_delta = 495 curr_stats->mib_stats.reg_cck_phyerr_cnt - 496 prev_stats->mib_stats.reg_cck_phyerr_cnt; 497 498 /* 499 * Add the influence of ofdm phy errors to the wasted channel 500 * utillization, this computed through time wasted in errors 501 */ 502 reg_ofdm_phyerr_cu = reg_ofdm_phyerr_delta * 503 dcs_host_params.phy_err_penalty; 504 total_wasted_cu += 505 (reg_ofdm_phyerr_cu > 0) ? 506 (((reg_ofdm_phyerr_cu >> 8) * 100) / scaled_reg_tsf_delta) : 0; 507 508 ofdm_phy_err_rate = (curr_stats->mib_stats.reg_ofdm_phyerr_cnt * 1000) / 509 curr_stats->mib_stats.listen_time; 510 cck_phy_err_rate = (curr_stats->mib_stats.reg_cck_phyerr_cnt * 1000) / 511 curr_stats->mib_stats.listen_time; 512 513 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) { 514 dcs_debug("reg_unused_cu: %u, reg_ofdm_phyerr_delta: %u, reg_cck_phyerr_delta: %u, reg_ofdm_phyerr_cu: %u", 515 reg_unused_cu, reg_ofdm_phyerr_delta, 516 reg_cck_phyerr_delta, reg_ofdm_phyerr_cu); 517 dcs_debug("total_wasted_cu: %u, ofdm_phy_err_rate: %u, cck_phy_err_rate: %u", 518 total_wasted_cu, ofdm_phy_err_rate, cck_phy_err_rate); 519 dcs_debug("new_unused_cu: %u, reg_ofdm_phy_error_cu: %u", 520 reg_unused_cu, 521 (curr_stats->mib_stats.reg_ofdm_phyerr_cnt * 100) / 522 curr_stats->mib_stats.listen_time); 523 } 524 525 /* Check if the error rates are higher than the thresholds */ 526 max_phy_err_rate = QDF_MAX(ofdm_phy_err_rate, cck_phy_err_rate); 527 528 max_phy_err_count = QDF_MAX(curr_stats->mib_stats.reg_ofdm_phyerr_cnt, 529 curr_stats->mib_stats.reg_cck_phyerr_cnt); 530 531 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) 532 dcs_debug("max_phy_err_rate: %u, max_phy_err_count: %u", 533 max_phy_err_rate, max_phy_err_count); 534 535 if (((max_phy_err_rate >= dcs_host_params.phy_err_threshold) && 536 (max_phy_err_count > dcs_host_params.phy_err_threshold)) || 537 (curr_stats->phyerr_cnt > dcs_host_params.radar_err_threshold)) 538 too_many_phy_errors = 1; 539 540 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_CRITICAL)) { 541 dcs_debug("total_cu: %u, tx_cu: %u, rx_cu: %u, rx_time_cu: %u, unused cu: %u", 542 reg_total_cu, reg_tx_cu, 543 reg_rx_cu, rx_time_cu, reg_unused_cu); 544 dcs_debug("phyerr: %u, total_wasted_cu: %u, phyerror_cu: %u, wasted_cu: %u, reg_tx_cu: %u, reg_rx_cu: %u", 545 too_many_phy_errors, total_wasted_cu, 546 reg_ofdm_phyerr_cu, wasted_tx_cu, 547 reg_tx_cu, reg_rx_cu); 548 dcs_debug("tx_err: %u", tx_err); 549 } 550 551 if (reg_unused_cu >= dcs_host_params.coch_intfr_threshold) 552 /* Quickly reach to decision */ 553 p_dcs_im_stats->im_intfr_cnt += 2; 554 else if (too_many_phy_errors && 555 (((total_wasted_cu > 556 (dcs_host_params.coch_intfr_threshold + 10)) && 557 ((reg_tx_cu + reg_rx_cu) > dcs_host_params.user_max_cu)) || 558 ((reg_tx_cu > DCS_TX_MAX_CU) && 559 (tx_err >= dcs_host_params.tx_err_threshold)))) 560 p_dcs_im_stats->im_intfr_cnt++; 561 562 if (p_dcs_im_stats->im_intfr_cnt >= 563 dcs_host_params.intfr_detection_threshold) { 564 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_CRITICAL)) { 565 dcs_debug("interference threshold exceeded"); 566 dcs_debug("unused_cu: %u, too_any_phy_errors: %u, total_wasted_cu: %u, reg_tx_cu: %u, reg_rx_cu: %u", 567 reg_unused_cu, too_many_phy_errors, 568 total_wasted_cu, reg_tx_cu, reg_rx_cu); 569 } 570 571 p_dcs_im_stats->im_intfr_cnt = 0; 572 p_dcs_im_stats->im_samp_cnt = 0; 573 /* 574 * Once the interference is detected, change the channel, as on 575 * today this is common routine for wirelesslan and 576 * non-wirelesslan interference. Name as such kept the same 577 * because of the DA code, which is using the same function. 578 */ 579 start_dcs_cbk_handler = true; 580 } else if (0 == p_dcs_im_stats->im_intfr_cnt || 581 p_dcs_im_stats->im_samp_cnt >= 582 dcs_host_params.intfr_detection_window) { 583 p_dcs_im_stats->im_intfr_cnt = 0; 584 p_dcs_im_stats->im_samp_cnt = 0; 585 } 586 587 /* Count the current run too */ 588 p_dcs_im_stats->im_samp_cnt++; 589 590 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) 591 dcs_debug("intfr_count: %u, sample_count: %u", 592 p_dcs_im_stats->im_intfr_cnt, 593 p_dcs_im_stats->im_samp_cnt); 594 copy_stats: 595 /* Copy the stats for next cycle */ 596 wlan_dcs_im_copy_stats(prev_stats, curr_stats); 597 end: 598 return start_dcs_cbk_handler; 599 } 600 601 void wlan_dcs_disable_timer_fn(void *dcs_timer_args) 602 { 603 struct pdev_dcs_timer_args *dcs_timer_args_ctx; 604 struct wlan_objmgr_psoc *psoc; 605 uint32_t pdev_id; 606 struct dcs_psoc_priv_obj *dcs_psoc_priv; 607 struct dcs_pdev_priv_obj *dcs_pdev_priv; 608 609 if (!dcs_timer_args) { 610 dcs_err("dcs timer args is null"); 611 return; 612 } 613 614 dcs_timer_args_ctx = (struct pdev_dcs_timer_args *)dcs_timer_args; 615 psoc = dcs_timer_args_ctx->psoc; 616 pdev_id = dcs_timer_args_ctx->pdev_id; 617 618 dcs_psoc_priv = 619 wlan_objmgr_psoc_get_comp_private_obj(psoc, WLAN_UMAC_COMP_DCS); 620 if (!dcs_psoc_priv) { 621 dcs_err("dcs psoc private object is null"); 622 return; 623 } 624 625 dcs_pdev_priv = &dcs_psoc_priv->dcs_pdev_priv[pdev_id]; 626 dcs_pdev_priv->dcs_freq_ctrl_params.disable_delay_process = false; 627 628 dcs_info("dcs disable timeout, enable dcs detection again"); 629 wlan_dcs_set_algorithm_process(psoc, pdev_id, true); 630 } 631 632 /** 633 * wlan_dcs_frequency_control() - dcs frequency control handling 634 * @psoc: psoc pointer 635 * @dcs_pdev_priv: dcs pdev priv pointer 636 * @event: dcs stats event pointer 637 * 638 * Return: none 639 */ 640 static void wlan_dcs_frequency_control(struct wlan_objmgr_psoc *psoc, 641 struct dcs_pdev_priv_obj *dcs_pdev_priv, 642 struct wlan_host_dcs_event *event) 643 { 644 struct dcs_psoc_priv_obj *dcs_psoc_priv; 645 struct pdev_dcs_freq_ctrl_params *dcs_freq_ctrl_params; 646 uint8_t timestamp_pos; 647 unsigned long current_time; 648 uint8_t delta_pos; 649 unsigned long delta_time; 650 bool disable_dcs_sometime = false; 651 652 if (!psoc || !dcs_pdev_priv || !event) { 653 dcs_err("psoc or dcs_pdev_priv or event is null"); 654 return; 655 } 656 657 dcs_freq_ctrl_params = &dcs_pdev_priv->dcs_freq_ctrl_params; 658 if (dcs_freq_ctrl_params->disable_delay_process) { 659 dcs_err("In the process of dcs disable, shouldn't go to here"); 660 return; 661 } 662 663 current_time = qdf_get_system_timestamp(); 664 if (dcs_freq_ctrl_params->dcs_happened_count >= 665 dcs_freq_ctrl_params->disable_threshold_per_5mins) { 666 delta_pos = 667 dcs_freq_ctrl_params->dcs_happened_count - 668 dcs_freq_ctrl_params->disable_threshold_per_5mins; 669 delta_pos = delta_pos % MAX_DCS_TIME_RECORD; 670 671 delta_time = current_time - 672 dcs_freq_ctrl_params->timestamp[delta_pos]; 673 if (delta_time < DCS_FREQ_CONTROL_TIME) 674 disable_dcs_sometime = true; 675 } 676 677 if (!disable_dcs_sometime) { 678 timestamp_pos = dcs_freq_ctrl_params->dcs_happened_count % 679 MAX_DCS_TIME_RECORD; 680 dcs_freq_ctrl_params->timestamp[timestamp_pos] = current_time; 681 dcs_freq_ctrl_params->dcs_happened_count++; 682 } 683 684 /* 685 * Before start dcs callback handler or disable dcs for some time, 686 * need to ignore dcs event data and won't do interference detection 687 * algorithm calculation for disabling dcs detection firstly. 688 */ 689 wlan_dcs_set_algorithm_process(psoc, event->dcs_param.pdev_id, false); 690 691 if (disable_dcs_sometime) { 692 dcs_freq_ctrl_params->disable_delay_process = true; 693 dcs_pdev_priv->dcs_timer_args.psoc = psoc; 694 dcs_pdev_priv->dcs_timer_args.pdev_id = 695 event->dcs_param.pdev_id; 696 qdf_timer_start(&dcs_pdev_priv->dcs_disable_timer, 697 dcs_pdev_priv->dcs_freq_ctrl_params. 698 restart_delay * 60 * 1000); 699 dcs_info("start dcs disable timer"); 700 } else { 701 dcs_psoc_priv = wlan_objmgr_psoc_get_comp_private_obj( 702 psoc, 703 WLAN_UMAC_COMP_DCS); 704 if (!dcs_psoc_priv) { 705 dcs_err("dcs private psoc object is null"); 706 return; 707 } 708 709 dcs_info("start dcs callback handler"); 710 dcs_psoc_priv->dcs_cbk.cbk(psoc, event->dcs_param.pdev_id, 711 event->dcs_param.interference_type, 712 dcs_psoc_priv->dcs_cbk.arg); 713 } 714 } 715 716 /** 717 * wlan_dcs_switch_chan() - switch channel for vdev 718 * @vdev: vdev ptr 719 * @tgt_freq: target frequency 720 * @tgt_width: target channel width 721 * 722 * Return: QDF_STATUS 723 */ 724 static QDF_STATUS 725 wlan_dcs_switch_chan(struct wlan_objmgr_vdev *vdev, qdf_freq_t tgt_freq, 726 enum phy_ch_width tgt_width) 727 { 728 struct wlan_objmgr_psoc *psoc; 729 struct dcs_psoc_priv_obj *dcs_psoc_priv; 730 dcs_switch_chan_cb switch_chan_cb; 731 732 psoc = wlan_vdev_get_psoc(vdev); 733 if (!psoc) 734 return QDF_STATUS_E_INVAL; 735 736 dcs_psoc_priv = wlan_objmgr_psoc_get_comp_private_obj(psoc, 737 WLAN_UMAC_COMP_DCS); 738 if (!dcs_psoc_priv) 739 return QDF_STATUS_E_INVAL; 740 741 switch_chan_cb = dcs_psoc_priv->switch_chan_cb; 742 if (!switch_chan_cb) 743 return QDF_STATUS_E_NOSUPPORT; 744 745 return switch_chan_cb(vdev, tgt_freq, tgt_width); 746 } 747 748 #ifdef WLAN_POLICY_MGR_ENABLE 749 /** 750 * wlan_dcs_get_pcl_for_sap() - get preferred channel list for SAP 751 * @vdev: vdev ptr 752 * @freq_list: Pointer to PCL 753 * @freq_list_sz: Max size of PCL 754 * 755 * Return: number of channels in PCL 756 */ 757 static uint32_t wlan_dcs_get_pcl_for_sap(struct wlan_objmgr_vdev *vdev, 758 qdf_freq_t *freq_list, 759 uint32_t freq_list_sz) 760 { 761 struct wlan_objmgr_psoc *psoc; 762 struct wlan_objmgr_pdev *pdev; 763 struct policy_mgr_pcl_list *pcl; 764 qdf_freq_t freq; 765 enum channel_state state; 766 QDF_STATUS status; 767 int i, j; 768 769 psoc = wlan_vdev_get_psoc(vdev); 770 if (!psoc) 771 return 0; 772 773 pdev = wlan_vdev_get_pdev(vdev); 774 if (!pdev) 775 return 0; 776 777 pcl = qdf_mem_malloc(sizeof(*pcl)); 778 if (!pcl) 779 return 0; 780 781 status = policy_mgr_get_pcl_for_vdev_id(psoc, 782 PM_SAP_MODE, 783 pcl->pcl_list, &pcl->pcl_len, 784 pcl->weight_list, 785 QDF_ARRAY_SIZE(pcl->weight_list), 786 wlan_vdev_get_id(vdev)); 787 if (QDF_IS_STATUS_ERROR(status) || !pcl->pcl_len) { 788 qdf_mem_free(pcl); 789 return 0; 790 } 791 792 for (i = 0, j = 0; i < pcl->pcl_len && i < freq_list_sz; i++) { 793 freq = (qdf_freq_t)pcl->pcl_list[i]; 794 state = wlan_reg_get_channel_state_for_pwrmode( 795 pdev, 796 freq, 797 REG_CURRENT_PWR_MODE); 798 if (state != CHANNEL_STATE_ENABLE) 799 continue; 800 801 freq_list[j++] = freq; 802 } 803 804 qdf_mem_free(pcl); 805 return j; 806 } 807 #else 808 static uint32_t wlan_dcs_get_pcl_for_sap(struct wlan_objmgr_vdev *vdev, 809 qdf_freq_t *freq_list, 810 uint32_t freq_list_sz) 811 { 812 struct wlan_objmgr_pdev *pdev; 813 struct regulatory_channel *cur_chan_list; 814 qdf_freq_t freq; 815 enum channel_state state; 816 int i, j; 817 818 pdev = wlan_vdev_get_pdev(vdev); 819 if (!pdev) 820 return 0; 821 822 cur_chan_list = qdf_mem_malloc(NUM_CHANNELS * 823 sizeof(struct regulatory_channel)); 824 if (!cur_chan_list) 825 return 0; 826 827 if (wlan_reg_get_current_chan_list(pdev, cur_chan_list) != 828 QDF_STATUS_SUCCESS) { 829 qdf_mem_free(cur_chan_list); 830 return 0; 831 } 832 833 for (i = 0, j = 0; i < NUM_CHANNELS && i < freq_list_sz; i++) { 834 freq = cur_chan_list[i].center_freq; 835 state = wlan_reg_get_channel_state_for_pwrmode( 836 pdev, 837 freq, 838 REG_CURRENT_PWR_MODE); 839 if (state != CHANNEL_STATE_ENABLE) 840 continue; 841 842 freq_list[j++] = freq; 843 } 844 845 qdf_mem_free(cur_chan_list); 846 return j; 847 } 848 #endif 849 850 /** 851 * wlan_dcs_awgn_get_intf_for_seg() - get interference for specified segment 852 * @awgn_info: awgn info pointer 853 * @segment: segment index in channel band 854 * 855 * This function extracts the information from awgn event and check interference 856 * within the specified segment. 857 * 858 * Return: true if interference is found within the segment, false otherwise. 859 */ 860 static bool 861 wlan_dcs_awgn_get_intf_for_seg(struct wlan_host_dcs_awgn_info *awgn_info, 862 uint32_t segment) 863 { 864 uint32_t seg_mask; 865 866 switch (segment) { 867 case WLAN_DCS_SEG_PRI20: 868 seg_mask = WLAN_DCS_SEG_PRI20_MASK; 869 break; 870 case WLAN_DCS_SEG_SEC20: 871 seg_mask = WLAN_DCS_SEG_SEC20_MASK; 872 break; 873 case WLAN_DCS_SEG_SEC40: 874 seg_mask = WLAN_DCS_SEG_SEC40_MASK; 875 break; 876 case WLAN_DCS_SEG_SEC80: 877 seg_mask = WLAN_DCS_SEG_SEC80_MASK; 878 break; 879 case WLAN_DCS_SEG_SEC160: 880 seg_mask = WLAN_DCS_SEG_SEC160_MASK; 881 break; 882 default: 883 seg_mask = 0xFFFFFFFF; 884 break; 885 } 886 887 return (awgn_info->chan_bw_intf_bitmap & seg_mask); 888 } 889 890 /** 891 * wlan_dcs_get_max_seg_idx() - get max segment index for channel width 892 * @width: channel width 893 * 894 * Return: max segment index(enum wlan_dcs_chan_seg) for the channel width. 895 */ 896 static enum wlan_dcs_chan_seg wlan_dcs_get_max_seg_idx(enum phy_ch_width width) 897 { 898 switch (width) { 899 case CH_WIDTH_160MHZ: 900 case CH_WIDTH_80P80MHZ: 901 return WLAN_DCS_SEG_SEC80; 902 case CH_WIDTH_80MHZ: 903 return WLAN_DCS_SEG_SEC40; 904 case CH_WIDTH_40MHZ: 905 return WLAN_DCS_SEG_SEC20; 906 case CH_WIDTH_20MHZ: 907 return WLAN_DCS_SEG_PRI20; 908 default: 909 dcs_err("Invalid ch width %d", width); 910 return WLAN_DCS_SEG_INVALID; 911 } 912 } 913 914 /** 915 * wlan_dcs_get_chan_width_for_seg() - get channel width for specified segment 916 * @seg_idx: segment index 917 * 918 * Return: channel width for segment index 919 */ 920 static enum phy_ch_width 921 wlan_dcs_get_chan_width_for_seg(enum wlan_dcs_chan_seg seg_idx) 922 { 923 switch (seg_idx) { 924 case WLAN_DCS_SEG_SEC80: 925 return CH_WIDTH_160MHZ; 926 case WLAN_DCS_SEG_SEC40: 927 return CH_WIDTH_80MHZ; 928 case WLAN_DCS_SEG_SEC20: 929 return CH_WIDTH_40MHZ; 930 case WLAN_DCS_SEG_PRI20: 931 return CH_WIDTH_20MHZ; 932 default: 933 dcs_err("Invalid seg idx %d", seg_idx); 934 return CH_WIDTH_INVALID; 935 } 936 } 937 938 /** 939 * wlan_dcs_get_max_no_intf_bw() - get max no interference band width 940 * @awgn_info: pointer to awgn info 941 * @width: pointer to channel width 942 * 943 * This function tries to get max no interference band width according to 944 * awgn event. 945 * 946 * Return: true if valid no interference band width is found, false otherwise. 947 */ 948 static bool 949 wlan_dcs_get_max_no_intf_bw(struct wlan_host_dcs_awgn_info *awgn_info, 950 enum phy_ch_width *width) 951 { 952 enum wlan_dcs_chan_seg seg_idx, max_seg_idx; 953 954 max_seg_idx = wlan_dcs_get_max_seg_idx(awgn_info->channel_width); 955 if (max_seg_idx == WLAN_DCS_SEG_INVALID) 956 return false; 957 958 seg_idx = WLAN_DCS_SEG_PRI20; 959 while (seg_idx <= max_seg_idx) { 960 if (wlan_dcs_awgn_get_intf_for_seg(awgn_info, seg_idx)) { 961 dcs_debug("Intf found for seg idx %d", seg_idx); 962 break; 963 } 964 seg_idx++; 965 } 966 967 /* scroll back to the last no-intf idx */ 968 seg_idx--; 969 970 if (seg_idx == WLAN_DCS_SEG_INVALID) { 971 /* If pri20 contains interference, do full channel change */ 972 dcs_debug("Primary 20MHz Channel interference detected"); 973 return false; 974 } 975 976 *width = wlan_dcs_get_chan_width_for_seg(seg_idx); 977 if (*width == CH_WIDTH_160MHZ && 978 awgn_info->channel_width == CH_WIDTH_80P80MHZ) 979 *width = CH_WIDTH_80P80MHZ; 980 981 dcs_debug("Found the max no intf width %d", *width); 982 return (*width != CH_WIDTH_INVALID); 983 } 984 985 /** 986 * wlan_dcs_get_available_chan_for_bw() - get available channel for specified 987 * band width 988 * @pdev: pdev ptr 989 * @awgn_info: pointer to awgn info 990 * @bw: channel width 991 * @freq_list: List of preferred channels 992 * @freq_num: Number of channels in the PCL 993 * @random: request for random channel 994 * 995 * Return: the selected channel frequency, 0 if no available chan is found. 996 */ 997 static qdf_freq_t 998 wlan_dcs_get_available_chan_for_bw(struct wlan_objmgr_pdev *pdev, 999 struct wlan_host_dcs_awgn_info *awgn_info, 1000 enum phy_ch_width bw, qdf_freq_t *freq_list, 1001 uint32_t freq_num, bool random) 1002 { 1003 int i, j = 0; 1004 uint32_t random_chan_idx; 1005 qdf_freq_t freq, selected_freq = 0; 1006 const struct bonded_channel_freq *bonded_chan_ptr = NULL; 1007 enum channel_state state; 1008 uint16_t chan_cfreq; 1009 bool is_safe = true; 1010 1011 if (!freq_list || !freq_num) 1012 return selected_freq; 1013 1014 for (i = 0; i < freq_num; i++) { 1015 if (j && !random) { 1016 selected_freq = freq_list[0]; 1017 dcs_debug("get the first available freq %u for bw %u", 1018 selected_freq, bw); 1019 break; 1020 } 1021 1022 freq = freq_list[i]; 1023 if (!WLAN_REG_IS_SAME_BAND_FREQS(freq, awgn_info->center_freq)) 1024 continue; 1025 1026 /** 1027 * DFS channel may need CAC during restart, which costs time 1028 * and may cause failure. 1029 */ 1030 if (wlan_reg_is_dfs_for_freq(pdev, freq)) { 1031 dcs_debug("skip dfs freq %u", freq); 1032 continue; 1033 } 1034 1035 if (bonded_chan_ptr && 1036 freq >= bonded_chan_ptr->start_freq && 1037 freq <= bonded_chan_ptr->end_freq) { 1038 if (is_safe) { 1039 dcs_debug("add freq directly [%d] = %u", 1040 j, freq); 1041 freq_list[j++] = freq; 1042 } 1043 continue; 1044 } 1045 1046 state = wlan_reg_get_5g_bonded_channel_and_state_for_pwrmode( 1047 pdev, freq, bw, &bonded_chan_ptr, 1048 REG_CURRENT_PWR_MODE, 1049 NO_SCHANS_PUNC); 1050 if (state != CHANNEL_STATE_ENABLE) 1051 continue; 1052 1053 /* no bonding channel for 20MHz */ 1054 if (bw == CH_WIDTH_20MHZ) { 1055 if (WLAN_DCS_IS_FREQ_IN_WIDTH(awgn_info->center_freq, 1056 awgn_info->center_freq0, 1057 awgn_info->center_freq1, 1058 awgn_info->channel_width, 1059 freq)) 1060 continue; 1061 1062 dcs_debug("add freq[%d] = %u", j, freq); 1063 freq_list[j++] = freq; 1064 continue; 1065 } 1066 1067 is_safe = true; 1068 chan_cfreq = bonded_chan_ptr->start_freq; 1069 while (chan_cfreq <= bonded_chan_ptr->end_freq) { 1070 if (WLAN_DCS_IS_FREQ_IN_WIDTH(awgn_info->center_freq, 1071 awgn_info->center_freq0, 1072 awgn_info->center_freq1, 1073 awgn_info->channel_width, 1074 chan_cfreq)) { 1075 is_safe = false; 1076 break; 1077 } 1078 chan_cfreq = chan_cfreq + 20; 1079 } 1080 if (is_safe) { 1081 dcs_debug("add freq[%d] = %u", j, freq); 1082 freq_list[j++] = freq; 1083 } 1084 } 1085 1086 if (j && random) { 1087 qdf_get_random_bytes(&random_chan_idx, sizeof(random_chan_idx)); 1088 random_chan_idx = random_chan_idx % j; 1089 selected_freq = freq_list[random_chan_idx]; 1090 dcs_debug("get freq[%d] = %u for bw %u", 1091 random_chan_idx, selected_freq, bw); 1092 } 1093 1094 return selected_freq; 1095 } 1096 1097 /** 1098 * wlan_dcs_sap_get_available_chan() - get available channel for sap 1099 * @vdev: vdev ptr 1100 * @awgn_info: pointer to awgn info 1101 * @tgt_freq: frequency of the selected channel 1102 * @tgt_width: band width of the selected channel 1103 * @random: request for random channel 1104 * 1105 * This function tries to get no-interference chan with max possible bandwidth 1106 * from pcl for sap according to awgn info. 1107 * 1108 * Return: true if available channel is found, false otherwise. 1109 */ 1110 static bool 1111 wlan_dcs_sap_select_chan(struct wlan_objmgr_vdev *vdev, 1112 struct wlan_host_dcs_awgn_info *awgn_info, 1113 qdf_freq_t *tgt_freq, enum phy_ch_width *tgt_width, 1114 bool random) 1115 { 1116 int32_t tmp_width; 1117 qdf_freq_t tmp_freq = 0; 1118 struct wlan_objmgr_pdev *pdev; 1119 qdf_freq_t *freq_list; 1120 uint32_t freq_num; 1121 1122 freq_list = qdf_mem_malloc(sizeof(*freq_list) * NUM_CHANNELS); 1123 if (!freq_list) 1124 return false; 1125 1126 freq_num = wlan_dcs_get_pcl_for_sap(vdev, freq_list, NUM_CHANNELS); 1127 if (!freq_num) { 1128 qdf_mem_free(freq_list); 1129 return false; 1130 } 1131 1132 tmp_width = awgn_info->channel_width; 1133 pdev = wlan_vdev_get_pdev(vdev); 1134 if (!pdev) { 1135 qdf_mem_free(freq_list); 1136 return false; 1137 } 1138 1139 while (tmp_width >= CH_WIDTH_20MHZ) { 1140 tmp_freq = wlan_dcs_get_available_chan_for_bw(pdev, awgn_info, 1141 tmp_width, 1142 freq_list, 1143 freq_num, 1144 random); 1145 if (tmp_freq) 1146 break; 1147 tmp_width--; 1148 } 1149 1150 if (tmp_freq) { 1151 *tgt_width = tmp_width; 1152 *tgt_freq = tmp_freq; 1153 dcs_debug("new_width: %d new_freq %u", tmp_width, tmp_freq); 1154 1155 qdf_mem_free(freq_list); 1156 return true; 1157 } 1158 1159 qdf_mem_free(freq_list); 1160 return false; 1161 } 1162 1163 /** 1164 * wlan_dcs_is_awgnim_valid() - validate awgn info 1165 * @awgn_info: pointer to awgn info 1166 * 1167 * Return: true if valid, false otherwise. 1168 */ 1169 static inline bool 1170 wlan_dcs_is_awgnim_valid(struct wlan_host_dcs_awgn_info *awgn_info) 1171 { 1172 return (awgn_info && 1173 awgn_info->center_freq && awgn_info->chan_bw_intf_bitmap && 1174 awgn_info->channel_width != CH_WIDTH_INVALID && 1175 WLAN_REG_IS_6GHZ_CHAN_FREQ(awgn_info->center_freq)); 1176 } 1177 1178 /** 1179 * wlan_dcs_vdev_get_op_chan_info() - get operating channel info for vdev 1180 * @vdev: pointer to vdev object 1181 * @cfreq: Center frequency of primary channel 1182 * @cfreq0: Center frequency of segment 1 1183 * @cfreq1: Center frequency of segment 2 1184 * @ch_width: Channel width, enum phy_ch_width 1185 * 1186 * Return: QDF_STATUS 1187 */ 1188 static QDF_STATUS 1189 wlan_dcs_vdev_get_op_chan_info(struct wlan_objmgr_vdev *vdev, 1190 qdf_freq_t *cfreq, qdf_freq_t *cfreq0, 1191 qdf_freq_t *cfreq1, enum phy_ch_width *ch_width) 1192 { 1193 struct wlan_channel *chan; 1194 1195 if (!vdev) 1196 return QDF_STATUS_E_INVAL; 1197 1198 *cfreq = 0; 1199 *cfreq0 = 0; 1200 *cfreq1 = 0; 1201 *ch_width = 0; 1202 1203 if (wlan_vdev_mlme_is_active(vdev) != QDF_STATUS_SUCCESS) 1204 return QDF_STATUS_E_INVAL; 1205 1206 chan = wlan_vdev_get_active_channel(vdev); 1207 if (!chan) 1208 return QDF_STATUS_E_INVAL; 1209 1210 *cfreq = chan->ch_freq; 1211 *cfreq0 = chan->ch_cfreq1; 1212 *cfreq1 = chan->ch_cfreq2; 1213 *ch_width = chan->ch_width; 1214 1215 return QDF_STATUS_SUCCESS; 1216 } 1217 1218 /** 1219 * wlan_dcs_process_awgn_sta() - process AWGN event for STA 1220 * @pdev: pointer to pdev object 1221 * @object: vdev object 1222 * @arg: Arguments to the handler 1223 * 1224 * Return: void 1225 */ 1226 static void wlan_dcs_process_awgn_sta(struct wlan_objmgr_pdev *pdev, 1227 void *object, void *arg) 1228 { 1229 struct wlan_objmgr_vdev *vdev = object; 1230 struct wlan_host_dcs_awgn_info *awgn_info = arg; 1231 enum phy_ch_width ch_width; 1232 enum phy_ch_width tgt_width = CH_WIDTH_INVALID; 1233 qdf_freq_t op_freq, cfreq0, cfreq1; 1234 qdf_freq_t tgt_freq = 0; 1235 QDF_STATUS status; 1236 uint8_t vdev_id; 1237 bool found; 1238 1239 if (!vdev || !pdev) 1240 return; 1241 1242 if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE) 1243 return; 1244 1245 vdev_id = wlan_vdev_get_id(vdev); 1246 status = wlan_dcs_vdev_get_op_chan_info(vdev, &op_freq, &cfreq0, 1247 &cfreq1, &ch_width); 1248 if (QDF_IS_STATUS_ERROR(status)) 1249 return; 1250 1251 if (awgn_info->center_freq != op_freq) { 1252 dcs_debug("STA-%d: freq not match", vdev_id); 1253 return; 1254 } 1255 1256 found = wlan_dcs_get_max_no_intf_bw(awgn_info, &tgt_width); 1257 if (found) { 1258 if (ch_width <= tgt_width) { 1259 dcs_debug("STA-%d: freq and bw are unchanged", vdev_id); 1260 return; 1261 } 1262 1263 tgt_freq = op_freq; 1264 } 1265 1266 /* If no width is found, means to disconnect */ 1267 dcs_debug("STA-%d: target freq %u width %u", 1268 vdev_id, tgt_freq, tgt_width); 1269 wlan_dcs_switch_chan(vdev, tgt_freq, tgt_width); 1270 } 1271 1272 /** 1273 * wlan_dcs_process_awgn_sap() - process AWGN event for SAP 1274 * @pdev: pointer to pdev object 1275 * @object: vdev object 1276 * @arg: Arguments to the handler 1277 * 1278 * Return: void 1279 */ 1280 static void wlan_dcs_process_awgn_sap(struct wlan_objmgr_pdev *pdev, 1281 void *object, void *arg) 1282 { 1283 struct wlan_objmgr_vdev *vdev = object; 1284 struct wlan_host_dcs_awgn_info *awgn_info = arg; 1285 enum phy_ch_width ch_width; 1286 enum phy_ch_width tgt_width = CH_WIDTH_INVALID; 1287 qdf_freq_t op_freq, cfreq0, cfreq1; 1288 qdf_freq_t tgt_freq = 0; 1289 QDF_STATUS status; 1290 uint8_t vdev_id; 1291 bool found; 1292 1293 if (!vdev || !pdev) 1294 return; 1295 1296 if (wlan_vdev_mlme_get_opmode(vdev) != QDF_SAP_MODE) 1297 return; 1298 1299 vdev_id = wlan_vdev_get_id(vdev); 1300 status = wlan_dcs_vdev_get_op_chan_info(vdev, &op_freq, &cfreq0, &cfreq1, &ch_width); 1301 if (QDF_IS_STATUS_ERROR(status)) 1302 return; 1303 1304 if (awgn_info->center_freq != op_freq) { 1305 dcs_debug("SAP-%d: freq not match rpt:%u - op:%u", 1306 vdev_id, awgn_info->center_freq, op_freq); 1307 return; 1308 } 1309 1310 found = wlan_dcs_get_max_no_intf_bw(awgn_info, &tgt_width); 1311 if (found) { 1312 if (ch_width <= tgt_width) { 1313 dcs_debug("SAP-%d: both freq and bw are unchanged", 1314 vdev_id); 1315 return; 1316 } 1317 1318 tgt_freq = op_freq; 1319 } else { 1320 wlan_dcs_sap_select_chan(vdev, awgn_info, &tgt_freq, 1321 &tgt_width, true); 1322 } 1323 1324 /* If no chan is selected, means to stop sap */ 1325 dcs_debug("SAP-%d: target freq %u width %u", 1326 vdev_id, tgt_freq, tgt_width); 1327 wlan_dcs_switch_chan(vdev, tgt_freq, tgt_width); 1328 } 1329 1330 /** 1331 * wlan_dcs_awgnim_process() - process awgn IM 1332 * @psoc: psoc ptr 1333 * @pdev_id: pdev id 1334 * @awgn_info: pointer to awgn info 1335 * 1336 * This function triggers channel change for all STAs and SAPs, according 1337 * to AWGN info. 1338 * 1339 * Return: None. 1340 */ 1341 static void 1342 wlan_dcs_awgn_process(struct wlan_objmgr_psoc *psoc, uint8_t pdev_id, 1343 struct wlan_host_dcs_awgn_info *awgn_info) 1344 { 1345 struct wlan_objmgr_pdev *pdev; 1346 1347 if (!wlan_dcs_is_awgnim_valid(awgn_info)) { 1348 dcs_err("Invalid awgnim event"); 1349 return; 1350 } 1351 1352 pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_DCS_ID); 1353 if (!pdev) { 1354 dcs_err("Invalid pdev id %d", pdev_id); 1355 return; 1356 } 1357 1358 dcs_debug("pdev id %u width %u freq %u freq0 %u fre1 %u bitmap 0x%x", 1359 pdev_id, awgn_info->channel_width, awgn_info->center_freq, 1360 awgn_info->center_freq0, awgn_info->center_freq1, 1361 awgn_info->chan_bw_intf_bitmap); 1362 1363 wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, 1364 wlan_dcs_process_awgn_sta, 1365 awgn_info, 0, WLAN_DCS_ID); 1366 1367 wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, 1368 wlan_dcs_process_awgn_sap, 1369 awgn_info, 0, WLAN_DCS_ID); 1370 1371 wlan_objmgr_pdev_release_ref(pdev, WLAN_DCS_ID); 1372 } 1373 1374 QDF_STATUS 1375 wlan_dcs_process(struct wlan_objmgr_psoc *psoc, 1376 struct wlan_host_dcs_event *event) 1377 { 1378 struct dcs_pdev_priv_obj *dcs_pdev_priv; 1379 bool start_dcs_cbk_handler = false; 1380 1381 if (!psoc || !event) { 1382 dcs_err("psoc or event is NULL"); 1383 return QDF_STATUS_E_INVAL; 1384 } 1385 1386 dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc, 1387 event->dcs_param.pdev_id); 1388 if (!dcs_pdev_priv) { 1389 dcs_err("dcs pdev private object is null"); 1390 return QDF_STATUS_E_INVAL; 1391 } 1392 1393 if (unlikely(dcs_pdev_priv->dcs_host_params.dcs_debug 1394 >= DCS_DEBUG_VERBOSE)) 1395 dcs_debug("dcs_enable: %u, interference_type: %u, pdev_id: %u", 1396 dcs_pdev_priv->dcs_host_params.dcs_enable, 1397 event->dcs_param.interference_type, 1398 event->dcs_param.pdev_id); 1399 1400 switch (event->dcs_param.interference_type) { 1401 case WLAN_HOST_DCS_CWIM: 1402 break; 1403 case WLAN_HOST_DCS_WLANIM: 1404 if (!dcs_pdev_priv->dcs_host_params.dcs_enable) 1405 break; 1406 1407 if (dcs_pdev_priv->dcs_host_params.dcs_enable & 1408 WLAN_HOST_DCS_WLANIM) 1409 start_dcs_cbk_handler = 1410 wlan_dcs_wlan_interference_process( 1411 &event->wlan_stat, 1412 dcs_pdev_priv); 1413 if (dcs_pdev_priv->user_cb && 1414 dcs_pdev_priv->dcs_host_params.notify_user) { 1415 dcs_pdev_priv->dcs_host_params.notify_user = 0; 1416 dcs_pdev_priv->user_cb(dcs_pdev_priv->requestor_vdev_id, 1417 &dcs_pdev_priv->dcs_im_stats.user_dcs_im_stats, 1418 0); 1419 } 1420 if (start_dcs_cbk_handler) 1421 wlan_dcs_frequency_control(psoc, 1422 dcs_pdev_priv, 1423 event); 1424 break; 1425 case WLAN_HOST_DCS_AWGNIM: 1426 /* Skip frequency control for AWGNIM */ 1427 wlan_dcs_awgn_process(psoc, event->dcs_param.pdev_id, 1428 &event->awgn_info); 1429 break; 1430 default: 1431 dcs_err("unidentified interference type reported"); 1432 break; 1433 } 1434 1435 return QDF_STATUS_SUCCESS; 1436 } 1437 1438 void wlan_dcs_clear(struct wlan_objmgr_psoc *psoc, uint32_t pdev_id) 1439 { 1440 struct dcs_pdev_priv_obj *dcs_pdev_priv; 1441 1442 if (!psoc) { 1443 dcs_err("psoc is null"); 1444 return; 1445 } 1446 1447 dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc, pdev_id); 1448 if (!dcs_pdev_priv) { 1449 dcs_err("dcs pdev private object is null"); 1450 return; 1451 } 1452 1453 qdf_timer_stop(&dcs_pdev_priv->dcs_disable_timer); 1454 qdf_mem_set(&dcs_pdev_priv->dcs_im_stats, 1455 sizeof(dcs_pdev_priv->dcs_im_stats), 0); 1456 qdf_mem_set(dcs_pdev_priv->dcs_freq_ctrl_params.timestamp, 1457 MAX_DCS_TIME_RECORD * sizeof(unsigned long), 0); 1458 dcs_pdev_priv->dcs_freq_ctrl_params.dcs_happened_count = 0; 1459 dcs_pdev_priv->dcs_freq_ctrl_params.disable_delay_process = false; 1460 wlan_dcs_set_algorithm_process(psoc, pdev_id, false); 1461 } 1462 1463 void wlan_dcs_set_algorithm_process(struct wlan_objmgr_psoc *psoc, 1464 uint32_t pdev_id, 1465 bool dcs_algorithm_process) 1466 { 1467 struct dcs_pdev_priv_obj *dcs_pdev_priv; 1468 1469 dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc, pdev_id); 1470 if (!dcs_pdev_priv) { 1471 dcs_err("dcs pdev private object is null"); 1472 return; 1473 } 1474 1475 if (dcs_pdev_priv->dcs_host_params.force_disable_algorithm) { 1476 dcs_debug("dcs algorithm is disabled forcely"); 1477 dcs_pdev_priv->dcs_host_params.dcs_algorithm_process = false; 1478 return; 1479 } 1480 1481 dcs_pdev_priv->dcs_host_params.dcs_algorithm_process = 1482 dcs_algorithm_process; 1483 } 1484