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