1 /* 2 * Copyright (c) 2020, 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 29 struct dcs_pdev_priv_obj * 30 wlan_dcs_get_pdev_private_obj(struct wlan_objmgr_psoc *psoc, uint32_t pdev_id) 31 { 32 struct dcs_psoc_priv_obj *dcs_psoc_obj; 33 struct dcs_pdev_priv_obj *dcs_pdev_priv = NULL; 34 35 if (!psoc) { 36 dcs_err("psoc is null"); 37 goto end; 38 } 39 40 dcs_psoc_obj = wlan_objmgr_psoc_get_comp_private_obj( 41 psoc, 42 WLAN_UMAC_COMP_DCS); 43 if (!dcs_psoc_obj) { 44 dcs_err("dcs psoc object is null"); 45 goto end; 46 } 47 48 if (pdev_id >= WLAN_DCS_MAX_PDEVS) { 49 dcs_err("invalid pdev_id: %u", pdev_id); 50 goto end; 51 } 52 53 dcs_pdev_priv = &dcs_psoc_obj->dcs_pdev_priv[pdev_id]; 54 end: 55 56 return dcs_pdev_priv; 57 } 58 59 QDF_STATUS wlan_dcs_attach(struct wlan_objmgr_psoc *psoc) 60 { 61 struct wlan_target_if_dcs_tx_ops *dcs_tx_ops; 62 63 if (!psoc) { 64 dcs_err("psoc is null"); 65 return QDF_STATUS_E_NULL_VALUE; 66 } 67 68 dcs_tx_ops = target_if_dcs_get_tx_ops(psoc); 69 if (!dcs_tx_ops) { 70 dcs_err("tx_ops is null!"); 71 return QDF_STATUS_E_NULL_VALUE; 72 } 73 74 if (!dcs_tx_ops->dcs_attach) { 75 dcs_err("dcs_attach function is null!"); 76 return QDF_STATUS_E_NULL_VALUE; 77 } 78 79 return dcs_tx_ops->dcs_attach(psoc); 80 } 81 82 QDF_STATUS wlan_dcs_detach(struct wlan_objmgr_psoc *psoc) 83 { 84 struct wlan_target_if_dcs_tx_ops *dcs_tx_ops; 85 86 if (!psoc) { 87 dcs_err("psoc is null"); 88 return QDF_STATUS_E_NULL_VALUE; 89 } 90 91 dcs_tx_ops = target_if_dcs_get_tx_ops(psoc); 92 if (!dcs_tx_ops) { 93 dcs_err("tx_ops is null!"); 94 return QDF_STATUS_E_NULL_VALUE; 95 } 96 97 if (!dcs_tx_ops->dcs_detach) { 98 dcs_err("dcs_detach function is null!"); 99 return QDF_STATUS_E_NULL_VALUE; 100 } 101 102 return dcs_tx_ops->dcs_detach(psoc); 103 } 104 105 QDF_STATUS wlan_dcs_cmd_send(struct wlan_objmgr_psoc *psoc, 106 uint32_t pdev_id, 107 bool is_host_pdev_id) 108 { 109 struct wlan_target_if_dcs_tx_ops *dcs_tx_ops; 110 struct dcs_pdev_priv_obj *dcs_pdev_priv; 111 uint32_t dcs_enable; 112 113 if (!psoc) { 114 dcs_err("psoc is null"); 115 return QDF_STATUS_E_NULL_VALUE; 116 } 117 118 dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc, pdev_id); 119 if (!dcs_pdev_priv) { 120 dcs_err("dcs pdev private object is null"); 121 return QDF_STATUS_E_NULL_VALUE; 122 } 123 124 dcs_enable = dcs_pdev_priv->dcs_host_params.dcs_enable & 125 dcs_pdev_priv->dcs_host_params.dcs_enable_cfg; 126 dcs_tx_ops = target_if_dcs_get_tx_ops(psoc); 127 128 if (dcs_tx_ops->dcs_cmd_send) { 129 dcs_info("dcs_enable: %u, pdev_id: %u", dcs_enable, pdev_id); 130 return dcs_tx_ops->dcs_cmd_send(psoc, 131 pdev_id, 132 is_host_pdev_id, 133 dcs_enable); 134 } 135 136 return QDF_STATUS_SUCCESS; 137 } 138 139 /** 140 * wlan_dcs_im_copy_stats() - dcs target interference mitigation statistics copy 141 * @prev_stats: previous statistics pointer 142 * @curr_stats: current statistics pointer 143 * 144 * Return: None 145 */ 146 static inline void 147 wlan_dcs_im_copy_stats(struct wlan_host_dcs_im_tgt_stats *prev_stats, 148 struct wlan_host_dcs_im_tgt_stats *curr_stats) 149 { 150 if (!prev_stats || !curr_stats) { 151 dcs_err("previous or current stats is null"); 152 return; 153 } 154 155 /* 156 * Right now no other actions are required beyond memcopy, 157 * if required the rest of the code would follow. 158 */ 159 qdf_mem_copy(prev_stats, curr_stats, 160 sizeof(struct wlan_host_dcs_im_tgt_stats)); 161 } 162 163 /** 164 * wlan_dcs_im_print_stats() - print current/previous dcs target im statistics 165 * @prev_stats: previous statistics pointer 166 * @curr_stats: current statistics pointer 167 * 168 * Return: None 169 */ 170 static void 171 wlan_dcs_im_print_stats(struct wlan_host_dcs_im_tgt_stats *prev_stats, 172 struct wlan_host_dcs_im_tgt_stats *curr_stats) 173 { 174 if (!prev_stats || !curr_stats) { 175 dcs_err("previous or current stats is null"); 176 return; 177 } 178 179 /* Debug, dump all received stats first */ 180 dcs_debug("tgt_curr/tsf: %u", curr_stats->reg_tsf32); 181 dcs_debug("tgt_curr/last_ack_rssi: %u", curr_stats->last_ack_rssi); 182 dcs_debug("tgt_curr/tx_waste_time: %u", curr_stats->tx_waste_time); 183 dcs_debug("tgt_curr/dcs_rx_time: %u", curr_stats->rx_time); 184 dcs_debug("tgt_curr/listen_time: %u", 185 curr_stats->mib_stats.listen_time); 186 dcs_debug("tgt_curr/tx_frame_cnt: %u", 187 curr_stats->mib_stats.reg_tx_frame_cnt); 188 dcs_debug("tgt_curr/rx_frame_cnt: %u", 189 curr_stats->mib_stats.reg_rx_frame_cnt); 190 dcs_debug("tgt_curr/rxclr_cnt: %u", 191 curr_stats->mib_stats.reg_rxclr_cnt); 192 dcs_debug("tgt_curr/reg_cycle_cnt: %u", 193 curr_stats->mib_stats.reg_cycle_cnt); 194 dcs_debug("tgt_curr/rxclr_ext_cnt: %u", 195 curr_stats->mib_stats.reg_rxclr_ext_cnt); 196 dcs_debug("tgt_curr/ofdm_phyerr_cnt: %u", 197 curr_stats->mib_stats.reg_ofdm_phyerr_cnt); 198 dcs_debug("tgt_curr/cck_phyerr_cnt: %u", 199 curr_stats->mib_stats.reg_cck_phyerr_cnt); 200 201 dcs_debug("tgt_prev/tsf: %u", prev_stats->reg_tsf32); 202 dcs_debug("tgt_prev/last_ack_rssi: %u", prev_stats->last_ack_rssi); 203 dcs_debug("tgt_prev/tx_waste_time: %u", prev_stats->tx_waste_time); 204 dcs_debug("tgt_prev/rx_time: %u", prev_stats->rx_time); 205 dcs_debug("tgt_prev/listen_time: %u", 206 prev_stats->mib_stats.listen_time); 207 dcs_debug("tgt_prev/tx_frame_cnt: %u", 208 prev_stats->mib_stats.reg_tx_frame_cnt); 209 dcs_debug("tgt_prev/rx_frame_cnt: %u", 210 prev_stats->mib_stats.reg_rx_frame_cnt); 211 dcs_debug("tgt_prev/rxclr_cnt: %u", 212 prev_stats->mib_stats.reg_rxclr_cnt); 213 dcs_debug("tgt_prev/reg_cycle_cnt: %u", 214 prev_stats->mib_stats.reg_cycle_cnt); 215 dcs_debug("tgt_prev/rxclr_ext_cnt: %u", 216 prev_stats->mib_stats.reg_rxclr_ext_cnt); 217 dcs_debug("tgt_prev/ofdm_phyerr_cnt: %u", 218 prev_stats->mib_stats.reg_ofdm_phyerr_cnt); 219 dcs_debug("tgt_prev/cck_phyerr_cnt: %u", 220 prev_stats->mib_stats.reg_cck_phyerr_cnt); 221 } 222 223 /** 224 * wlan_dcs_wlan_interference_process() - dcs detection algorithm handling 225 * @curr_stats: current target im stats pointer 226 * @dcs_pdev_priv: dcs pdev priv pointer 227 * 228 * Return: true or false means start dcs callback handler or not 229 */ 230 static bool 231 wlan_dcs_wlan_interference_process( 232 struct wlan_host_dcs_im_tgt_stats *curr_stats, 233 struct dcs_pdev_priv_obj *dcs_pdev_priv) 234 { 235 struct wlan_host_dcs_im_tgt_stats *prev_stats; 236 struct pdev_dcs_params dcs_host_params; 237 struct pdev_dcs_im_stats *p_dcs_im_stats; 238 bool start_dcs_cbk_handler = false; 239 240 uint32_t reg_tsf_delta = 0; 241 uint32_t rxclr_delta = 0; 242 uint32_t rxclr_ext_delta = 0; 243 uint32_t cycle_count_delta = 0; 244 uint32_t tx_frame_delta = 0; 245 uint32_t rx_frame_delta = 0; 246 uint32_t my_bss_rx_delta = 0; 247 uint32_t reg_total_cu = 0; 248 uint32_t reg_tx_cu = 0; 249 uint32_t reg_rx_cu = 0; 250 uint32_t reg_unused_cu = 0; 251 uint32_t rx_time_cu = 0; 252 uint32_t reg_ofdm_phyerr_delta = 0; 253 uint32_t reg_cck_phyerr_delta = 0; 254 uint32_t reg_ofdm_phyerr_cu = 0; 255 uint32_t ofdm_phy_err_rate = 0; 256 uint32_t cck_phy_err_rate = 0; 257 uint32_t max_phy_err_rate = 0; 258 uint32_t max_phy_err_count = 0; 259 uint32_t total_wasted_cu = 0; 260 uint32_t wasted_tx_cu = 0; 261 uint32_t tx_err = 0; 262 uint32_t too_many_phy_errors = 0; 263 264 if (!curr_stats) { 265 dcs_err("curr_stats is NULL"); 266 goto end; 267 } 268 269 if (!dcs_pdev_priv) { 270 dcs_err("dcs pdev private object is NULL"); 271 goto end; 272 } 273 274 dcs_host_params = dcs_pdev_priv->dcs_host_params; 275 p_dcs_im_stats = &dcs_pdev_priv->dcs_im_stats; 276 prev_stats = &dcs_pdev_priv->dcs_im_stats.prev_dcs_im_stats; 277 278 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) 279 wlan_dcs_im_print_stats(prev_stats, curr_stats); 280 281 /* 282 * Counters would have wrapped. Ideally we should be able to figure this 283 * out, but we never know how many times counters wrapped, just ignore. 284 */ 285 if ((curr_stats->mib_stats.listen_time <= 0) || 286 (curr_stats->reg_tsf32 <= prev_stats->reg_tsf32)) { 287 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) 288 dcs_debug("ignoring due to negative TSF value"); 289 goto copy_stats; 290 } 291 292 reg_tsf_delta = curr_stats->reg_tsf32 - prev_stats->reg_tsf32; 293 294 /* 295 * Do nothing if current stats are not seeming good, probably 296 * a reset happened on chip, force cleared 297 */ 298 if (prev_stats->mib_stats.reg_rxclr_cnt > 299 curr_stats->mib_stats.reg_rxclr_cnt) { 300 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) 301 dcs_debug("ignoring due to negative rxclr count"); 302 goto copy_stats; 303 } 304 305 rxclr_delta = curr_stats->mib_stats.reg_rxclr_cnt - 306 prev_stats->mib_stats.reg_rxclr_cnt; 307 rxclr_ext_delta = curr_stats->mib_stats.reg_rxclr_ext_cnt - 308 prev_stats->mib_stats.reg_rxclr_ext_cnt; 309 tx_frame_delta = curr_stats->mib_stats.reg_tx_frame_cnt - 310 prev_stats->mib_stats.reg_tx_frame_cnt; 311 312 rx_frame_delta = curr_stats->mib_stats.reg_rx_frame_cnt - 313 prev_stats->mib_stats.reg_rx_frame_cnt; 314 315 cycle_count_delta = curr_stats->mib_stats.reg_cycle_cnt - 316 prev_stats->mib_stats.reg_cycle_cnt; 317 318 my_bss_rx_delta = curr_stats->my_bss_rx_cycle_count - 319 prev_stats->my_bss_rx_cycle_count; 320 321 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) 322 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", 323 rxclr_delta, rxclr_ext_delta, tx_frame_delta, 324 rx_frame_delta, cycle_count_delta, my_bss_rx_delta); 325 326 if (0 == (cycle_count_delta >> 8)) { 327 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) 328 dcs_debug("cycle count NULL --Investigate--"); 329 goto copy_stats; 330 } 331 332 /* Update user stats */ 333 wlan_dcs_pdev_obj_lock(dcs_pdev_priv); 334 if (dcs_pdev_priv->dcs_host_params.user_request_count) { 335 struct wlan_host_dcs_im_user_stats *p_user_stats = 336 &p_dcs_im_stats->user_dcs_im_stats; 337 338 p_user_stats->cycle_count += cycle_count_delta; 339 p_user_stats->rxclr_count += rxclr_delta; 340 p_user_stats->rx_frame_count += rx_frame_delta; 341 p_user_stats->my_bss_rx_cycle_count += my_bss_rx_delta; 342 if (0 == p_user_stats->max_rssi && 343 0 == p_user_stats->min_rssi) { 344 p_user_stats->max_rssi = curr_stats->last_ack_rssi; 345 p_user_stats->min_rssi = curr_stats->last_ack_rssi; 346 } else { 347 if (curr_stats->last_ack_rssi > p_user_stats->max_rssi) 348 p_user_stats->max_rssi = 349 curr_stats->last_ack_rssi; 350 if (curr_stats->last_ack_rssi < p_user_stats->min_rssi) 351 p_user_stats->min_rssi = 352 curr_stats->last_ack_rssi; 353 } 354 dcs_pdev_priv->dcs_host_params.user_request_count--; 355 if (0 == dcs_pdev_priv->dcs_host_params.user_request_count) 356 dcs_pdev_priv->dcs_host_params.notify_user = 1; 357 } 358 wlan_dcs_pdev_obj_unlock(dcs_pdev_priv); 359 360 /* 361 * For below scenario, will ignore dcs event data and won't do 362 * interference detection algorithm calculation: 363 * 1: Current SAP channel isn't on 5G band 364 * 2: In the process of ACS 365 * 3: In the process of dcs disabling dcs_restart_delay time duration 366 */ 367 if (!dcs_host_params.dcs_algorithm_process) 368 goto copy_stats; 369 370 /* 371 * Total channel utiliztaion is the amount of time RXCLR is 372 * counted. RXCLR is counted, when 'RX is NOT clear', please 373 * refer to mac documentation. It means either TX or RX is ON 374 * 375 * Why shift by 8 ? after multiplication it could overflow. At one 376 * second rate, neither cycle_count_celta nor the tsf_delta would be 377 * zero after shift by 8 bits 378 */ 379 reg_total_cu = ((rxclr_delta >> 8) * 100) / (cycle_count_delta >> 8); 380 reg_tx_cu = ((tx_frame_delta >> 8) * 100) / (cycle_count_delta >> 8); 381 reg_rx_cu = ((rx_frame_delta >> 8) * 100) / (cycle_count_delta >> 8); 382 rx_time_cu = ((curr_stats->rx_time >> 8) * 100) / (reg_tsf_delta >> 8); 383 384 /* 385 * Amount of the time AP received cannot go higher than the receive 386 * cycle count delta. If at all it is, there should have been a 387 * computation error, ceil it to receive_cycle_count_diff 388 */ 389 if (rx_time_cu > reg_rx_cu) 390 rx_time_cu = reg_rx_cu; 391 392 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) 393 dcs_debug("reg_total_cu: %u, reg_tx_cu: %u, reg_rx_cu: %u, rx_time_cu: %u", 394 reg_total_cu, reg_tx_cu, reg_rx_cu, rx_time_cu); 395 396 /* 397 * Unusable channel utilization is amount of time that we 398 * spent in backoff or waiting for other transmit/receive to 399 * complete. If there is interference it is more likely that 400 * we overshoot the limit. In case of multiple stations, we 401 * still see increased channel utilization. This assumption may 402 * not be true for the VOW scenario where either multicast or 403 * unicast-UDP is used ( mixed traffic would still cause high 404 * channel utilization). 405 */ 406 wasted_tx_cu = ((curr_stats->tx_waste_time >> 8) * 100) / 407 (reg_tsf_delta >> 8); 408 409 /* 410 * Transmit channel utilization cannot go higher than the amount of time 411 * wasted, if so cap the wastage to transmit channel utillzation. This 412 * could happen to compution error. 413 */ 414 if (reg_tx_cu < wasted_tx_cu) 415 wasted_tx_cu = reg_tx_cu; 416 417 tx_err = (reg_tx_cu && wasted_tx_cu) ? 418 (wasted_tx_cu * 100) / reg_tx_cu : 0; 419 420 /* 421 * The below actually gives amount of time we are not using, or the 422 * interferer is active. 423 * rx_time_cu is what computed receive time *NOT* rx_cycle_count 424 * rx_cycle_count is our receive+interferer's transmit 425 * un-used is really total_cycle_counts - 426 * (our_rx_time(rx_time_cu) + our_receive_time) 427 */ 428 reg_unused_cu = (reg_total_cu >= (reg_tx_cu + rx_time_cu)) ? 429 (reg_total_cu - (reg_tx_cu + rx_time_cu)) : 0; 430 431 /* If any retransmissions are there, count them as wastage */ 432 total_wasted_cu = reg_unused_cu + wasted_tx_cu; 433 434 /* Check ofdm and cck errors */ 435 if (unlikely(curr_stats->mib_stats.reg_ofdm_phyerr_cnt < 436 prev_stats->mib_stats.reg_ofdm_phyerr_cnt)) 437 reg_ofdm_phyerr_delta = 438 curr_stats->mib_stats.reg_ofdm_phyerr_cnt; 439 else 440 reg_ofdm_phyerr_delta = 441 curr_stats->mib_stats.reg_ofdm_phyerr_cnt - 442 prev_stats->mib_stats.reg_ofdm_phyerr_cnt; 443 444 if (unlikely(curr_stats->mib_stats.reg_cck_phyerr_cnt < 445 prev_stats->mib_stats.reg_cck_phyerr_cnt)) 446 reg_cck_phyerr_delta = curr_stats->mib_stats.reg_cck_phyerr_cnt; 447 else 448 reg_cck_phyerr_delta = 449 curr_stats->mib_stats.reg_cck_phyerr_cnt - 450 prev_stats->mib_stats.reg_cck_phyerr_cnt; 451 452 /* 453 * Add the influence of ofdm phy errors to the wasted channel 454 * utillization, this computed through time wasted in errors 455 */ 456 reg_ofdm_phyerr_cu = reg_ofdm_phyerr_delta * 457 dcs_host_params.phy_err_penalty; 458 total_wasted_cu += 459 (reg_ofdm_phyerr_cu > 0) ? 460 (((reg_ofdm_phyerr_cu >> 8) * 100) / (reg_tsf_delta >> 8)) : 0; 461 462 ofdm_phy_err_rate = (curr_stats->mib_stats.reg_ofdm_phyerr_cnt * 1000) / 463 curr_stats->mib_stats.listen_time; 464 cck_phy_err_rate = (curr_stats->mib_stats.reg_cck_phyerr_cnt * 1000) / 465 curr_stats->mib_stats.listen_time; 466 467 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) { 468 dcs_debug("reg_unused_cu: %u, reg_ofdm_phyerr_delta: %u, reg_cck_phyerr_delta: %u, reg_ofdm_phyerr_cu: %u", 469 reg_unused_cu, reg_ofdm_phyerr_delta, 470 reg_cck_phyerr_delta, reg_ofdm_phyerr_cu); 471 dcs_debug("total_wasted_cu: %u, ofdm_phy_err_rate: %u, cck_phy_err_rate: %u", 472 total_wasted_cu, ofdm_phy_err_rate, cck_phy_err_rate); 473 dcs_debug("new_unused_cu: %u, reg_ofdm_phy_error_cu: %u", 474 reg_unused_cu, 475 (curr_stats->mib_stats.reg_ofdm_phyerr_cnt * 100) / 476 curr_stats->mib_stats.listen_time); 477 } 478 479 /* Check if the error rates are higher than the thresholds */ 480 max_phy_err_rate = QDF_MAX(ofdm_phy_err_rate, cck_phy_err_rate); 481 482 max_phy_err_count = QDF_MAX(curr_stats->mib_stats.reg_ofdm_phyerr_cnt, 483 curr_stats->mib_stats.reg_cck_phyerr_cnt); 484 485 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) 486 dcs_debug("max_phy_err_rate: %u, max_phy_err_count: %u", 487 max_phy_err_rate, max_phy_err_count); 488 489 if (((max_phy_err_rate >= dcs_host_params.phy_err_threshold) && 490 (max_phy_err_count > dcs_host_params.phy_err_threshold)) || 491 (curr_stats->phyerr_cnt > dcs_host_params.radar_err_threshold)) 492 too_many_phy_errors = 1; 493 494 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_CRITICAL)) { 495 dcs_debug("total_cu: %u, tx_cu: %u, rx_cu: %u, rx_time_cu: %u, unused cu: %u", 496 reg_total_cu, reg_tx_cu, 497 reg_rx_cu, rx_time_cu, reg_unused_cu); 498 dcs_debug("phyerr: %u, total_wasted_cu: %u, phyerror_cu: %u, wasted_cu: %u, reg_tx_cu: %u, reg_rx_cu: %u", 499 too_many_phy_errors, total_wasted_cu, 500 reg_ofdm_phyerr_cu, wasted_tx_cu, 501 reg_tx_cu, reg_rx_cu); 502 dcs_debug("tx_err: %u", tx_err); 503 } 504 505 if (reg_unused_cu >= dcs_host_params.coch_intfr_threshold) 506 /* Quickly reach to decision */ 507 p_dcs_im_stats->im_intfr_cnt += 2; 508 else if (too_many_phy_errors && 509 (((total_wasted_cu > 510 (dcs_host_params.coch_intfr_threshold + 10)) && 511 ((reg_tx_cu + reg_rx_cu) > dcs_host_params.user_max_cu)) || 512 ((reg_tx_cu > DCS_TX_MAX_CU) && 513 (tx_err >= dcs_host_params.tx_err_threshold)))) 514 p_dcs_im_stats->im_intfr_cnt++; 515 516 if (p_dcs_im_stats->im_intfr_cnt >= 517 dcs_host_params.intfr_detection_threshold) { 518 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_CRITICAL)) { 519 dcs_debug("interference threshold exceeded"); 520 dcs_debug("unused_cu: %u, too_any_phy_errors: %u, total_wasted_cu: %u, reg_tx_cu: %u, reg_rx_cu: %u", 521 reg_unused_cu, too_many_phy_errors, 522 total_wasted_cu, reg_tx_cu, reg_rx_cu); 523 } 524 525 p_dcs_im_stats->im_intfr_cnt = 0; 526 p_dcs_im_stats->im_samp_cnt = 0; 527 /* 528 * Once the interference is detected, change the channel, as on 529 * today this is common routine for wirelesslan and 530 * non-wirelesslan interference. Name as such kept the same 531 * because of the DA code, which is using the same function. 532 */ 533 start_dcs_cbk_handler = true; 534 } else if (0 == p_dcs_im_stats->im_intfr_cnt || 535 p_dcs_im_stats->im_samp_cnt >= 536 dcs_host_params.intfr_detection_window) { 537 p_dcs_im_stats->im_intfr_cnt = 0; 538 p_dcs_im_stats->im_samp_cnt = 0; 539 } 540 541 /* Count the current run too */ 542 p_dcs_im_stats->im_samp_cnt++; 543 544 if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) 545 dcs_debug("intfr_count: %u, sample_count: %u", 546 p_dcs_im_stats->im_intfr_cnt, 547 p_dcs_im_stats->im_samp_cnt); 548 copy_stats: 549 /* Copy the stats for next cycle */ 550 wlan_dcs_im_copy_stats(prev_stats, curr_stats); 551 end: 552 return start_dcs_cbk_handler; 553 } 554 555 void wlan_dcs_disable_timer_fn(void *dcs_timer_args) 556 { 557 struct pdev_dcs_timer_args *dcs_timer_args_ctx; 558 struct wlan_objmgr_psoc *psoc; 559 uint32_t pdev_id; 560 struct dcs_psoc_priv_obj *dcs_psoc_priv; 561 struct dcs_pdev_priv_obj *dcs_pdev_priv; 562 563 if (!dcs_timer_args) { 564 dcs_err("dcs timer args is null"); 565 return; 566 } 567 568 dcs_timer_args_ctx = (struct pdev_dcs_timer_args *)dcs_timer_args; 569 psoc = dcs_timer_args_ctx->psoc; 570 pdev_id = dcs_timer_args_ctx->pdev_id; 571 572 dcs_psoc_priv = 573 wlan_objmgr_psoc_get_comp_private_obj(psoc, WLAN_UMAC_COMP_DCS); 574 if (!dcs_psoc_priv) { 575 dcs_err("dcs psoc private object is null"); 576 return; 577 } 578 579 dcs_pdev_priv = &dcs_psoc_priv->dcs_pdev_priv[pdev_id]; 580 dcs_pdev_priv->dcs_freq_ctrl_params.disable_delay_process = false; 581 582 dcs_info("dcs disable timeout, enable dcs detection again"); 583 wlan_dcs_set_algorithm_process(psoc, pdev_id, true); 584 } 585 586 /** 587 * wlan_dcs_frequency_control() - dcs frequency control handling 588 * @psoc: psoc pointer 589 * @dcs_pdev_priv: dcs pdev priv pointer 590 * @event: dcs stats event pointer 591 * 592 * Return: none 593 */ 594 static void wlan_dcs_frequency_control(struct wlan_objmgr_psoc *psoc, 595 struct dcs_pdev_priv_obj *dcs_pdev_priv, 596 struct dcs_stats_event *event) 597 { 598 struct dcs_psoc_priv_obj *dcs_psoc_priv; 599 struct pdev_dcs_freq_ctrl_params *dcs_freq_ctrl_params; 600 uint8_t timestamp_pos; 601 unsigned long current_time; 602 uint8_t delta_pos; 603 unsigned long delta_time; 604 bool disable_dcs_sometime = false; 605 606 if (!psoc || !dcs_pdev_priv || !event) { 607 dcs_err("psoc or dcs_pdev_priv or event is null"); 608 return; 609 } 610 611 dcs_freq_ctrl_params = &dcs_pdev_priv->dcs_freq_ctrl_params; 612 if (dcs_freq_ctrl_params->disable_delay_process) { 613 dcs_err("In the process of dcs disable, shouldn't go to here"); 614 return; 615 } 616 617 current_time = qdf_get_system_timestamp(); 618 if (dcs_freq_ctrl_params->dcs_happened_count >= 619 dcs_freq_ctrl_params->disable_threshold_per_5mins) { 620 delta_pos = 621 dcs_freq_ctrl_params->dcs_happened_count - 622 dcs_freq_ctrl_params->disable_threshold_per_5mins; 623 delta_pos = delta_pos % MAX_DCS_TIME_RECORD; 624 625 delta_time = current_time - 626 dcs_freq_ctrl_params->timestamp[delta_pos]; 627 if (delta_time < DCS_FREQ_CONTROL_TIME) 628 disable_dcs_sometime = true; 629 } 630 631 if (!disable_dcs_sometime) { 632 timestamp_pos = dcs_freq_ctrl_params->dcs_happened_count % 633 MAX_DCS_TIME_RECORD; 634 dcs_freq_ctrl_params->timestamp[timestamp_pos] = current_time; 635 dcs_freq_ctrl_params->dcs_happened_count++; 636 } 637 638 /* 639 * Before start dcs callback handler or disable dcs for some time, 640 * need to ignore dcs event data and won't do interference detection 641 * algorithm calculation for disabling dcs detection firstly. 642 */ 643 wlan_dcs_set_algorithm_process(psoc, event->dcs_param.pdev_id, false); 644 645 if (disable_dcs_sometime) { 646 dcs_freq_ctrl_params->disable_delay_process = true; 647 dcs_pdev_priv->dcs_timer_args.psoc = psoc; 648 dcs_pdev_priv->dcs_timer_args.pdev_id = 649 event->dcs_param.pdev_id; 650 qdf_timer_start(&dcs_pdev_priv->dcs_disable_timer, 651 dcs_pdev_priv->dcs_freq_ctrl_params. 652 restart_delay * 60 * 1000); 653 dcs_info("start dcs disable timer"); 654 } else { 655 dcs_psoc_priv = wlan_objmgr_psoc_get_comp_private_obj( 656 psoc, 657 WLAN_UMAC_COMP_DCS); 658 if (!dcs_psoc_priv) { 659 dcs_err("dcs private psoc object is null"); 660 return; 661 } 662 663 dcs_info("start dcs callback handler"); 664 dcs_psoc_priv->dcs_cbk.cbk(psoc, event->dcs_param.pdev_id, 665 event->dcs_param.interference_type, 666 dcs_psoc_priv->dcs_cbk.arg); 667 } 668 } 669 670 QDF_STATUS 671 wlan_dcs_process(struct wlan_objmgr_psoc *psoc, struct dcs_stats_event *event) 672 { 673 struct dcs_pdev_priv_obj *dcs_pdev_priv; 674 bool start_dcs_cbk_handler = false; 675 676 if (!psoc || !event) { 677 dcs_err("psoc or event is NULL"); 678 return QDF_STATUS_E_INVAL; 679 } 680 681 dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc, 682 event->dcs_param.pdev_id); 683 if (!dcs_pdev_priv) { 684 dcs_err("dcs pdev private object is null"); 685 return QDF_STATUS_E_INVAL; 686 } 687 688 if (unlikely(dcs_pdev_priv->dcs_host_params.dcs_debug 689 >= DCS_DEBUG_VERBOSE)) 690 dcs_debug("dcs_enable: %u, interference_type: %u, pdev_id: %u", 691 dcs_pdev_priv->dcs_host_params.dcs_enable, 692 event->dcs_param.interference_type, 693 event->dcs_param.pdev_id); 694 695 if (!dcs_pdev_priv->dcs_host_params.dcs_enable) 696 return QDF_STATUS_SUCCESS; 697 698 switch (event->dcs_param.interference_type) { 699 case CAP_DCS_CWIM: 700 break; 701 case CAP_DCS_WLANIM: 702 if (dcs_pdev_priv->dcs_host_params.dcs_enable & CAP_DCS_WLANIM) 703 start_dcs_cbk_handler = 704 wlan_dcs_wlan_interference_process( 705 &event->wlan_stat, 706 dcs_pdev_priv); 707 if (dcs_pdev_priv->user_cb && 708 dcs_pdev_priv->dcs_host_params.notify_user) { 709 dcs_pdev_priv->dcs_host_params.notify_user = 0; 710 dcs_pdev_priv->user_cb(dcs_pdev_priv->requestor_vdev_id, 711 &dcs_pdev_priv->dcs_im_stats.user_dcs_im_stats, 712 0); 713 } 714 if (start_dcs_cbk_handler) 715 wlan_dcs_frequency_control(psoc, 716 dcs_pdev_priv, 717 event); 718 break; 719 default: 720 dcs_err("unidentified interference type reported"); 721 break; 722 } 723 724 return QDF_STATUS_SUCCESS; 725 } 726 727 void wlan_dcs_clear(struct wlan_objmgr_psoc *psoc, uint32_t pdev_id) 728 { 729 struct dcs_pdev_priv_obj *dcs_pdev_priv; 730 731 if (!psoc) { 732 dcs_err("psoc is null"); 733 return; 734 } 735 736 dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc, pdev_id); 737 if (!dcs_pdev_priv) { 738 dcs_err("dcs pdev private object is null"); 739 return; 740 } 741 742 qdf_timer_stop(&dcs_pdev_priv->dcs_disable_timer); 743 qdf_mem_set(&dcs_pdev_priv->dcs_im_stats, 744 sizeof(dcs_pdev_priv->dcs_im_stats), 0); 745 qdf_mem_set(dcs_pdev_priv->dcs_freq_ctrl_params.timestamp, 746 MAX_DCS_TIME_RECORD * sizeof(unsigned long), 0); 747 dcs_pdev_priv->dcs_freq_ctrl_params.dcs_happened_count = 0; 748 dcs_pdev_priv->dcs_freq_ctrl_params.disable_delay_process = false; 749 wlan_dcs_set_algorithm_process(psoc, pdev_id, false); 750 } 751 752 void wlan_dcs_set_algorithm_process(struct wlan_objmgr_psoc *psoc, 753 uint32_t pdev_id, 754 bool dcs_algorithm_process) 755 { 756 struct dcs_pdev_priv_obj *dcs_pdev_priv; 757 758 dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc, pdev_id); 759 if (!dcs_pdev_priv) { 760 dcs_err("dcs pdev private object is null"); 761 return; 762 } 763 764 dcs_pdev_priv->dcs_host_params.dcs_algorithm_process = 765 dcs_algorithm_process; 766 } 767