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