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