xref: /wlan-dirver/qca-wifi-host-cmn/umac/dcs/core/src/wlan_dcs.c (revision 45a38684b07295822dc8eba39e293408f203eec8)
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