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