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