xref: /wlan-dirver/qca-wifi-host-cmn/umac/dcs/core/src/wlan_dcs.c (revision 2f4b444fb7e689b83a4ab0e7b3b38f0bf4def8e0)
1 /*
2  * Copyright (c) 2020-2021, 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 #include <wlan_objmgr_psoc_obj_i.h>
29 #include "wlan_utility.h"
30 #ifdef WLAN_POLICY_MGR_ENABLE
31 #include "wlan_policy_mgr_api.h"
32 #endif
33 
34 struct dcs_pdev_priv_obj *
35 wlan_dcs_get_pdev_private_obj(struct wlan_objmgr_psoc *psoc, uint32_t pdev_id)
36 {
37 	struct dcs_psoc_priv_obj *dcs_psoc_obj;
38 	struct dcs_pdev_priv_obj *dcs_pdev_priv = NULL;
39 
40 	if (!psoc) {
41 		dcs_err("psoc is null");
42 		goto end;
43 	}
44 
45 	dcs_psoc_obj = wlan_objmgr_psoc_get_comp_private_obj(
46 							psoc,
47 							WLAN_UMAC_COMP_DCS);
48 	if (!dcs_psoc_obj) {
49 		dcs_err("dcs psoc object is null");
50 		goto end;
51 	}
52 
53 	if (pdev_id >= WLAN_DCS_MAX_PDEVS) {
54 		dcs_err("invalid pdev_id: %u", pdev_id);
55 		goto end;
56 	}
57 
58 	dcs_pdev_priv = &dcs_psoc_obj->dcs_pdev_priv[pdev_id];
59 end:
60 
61 	return dcs_pdev_priv;
62 }
63 
64 QDF_STATUS wlan_dcs_attach(struct wlan_objmgr_psoc *psoc)
65 {
66 	struct wlan_target_if_dcs_tx_ops *dcs_tx_ops;
67 
68 	if (!psoc) {
69 		dcs_err("psoc is null");
70 		return QDF_STATUS_E_NULL_VALUE;
71 	}
72 
73 	dcs_tx_ops = target_if_dcs_get_tx_ops(psoc);
74 	if (!dcs_tx_ops) {
75 		dcs_err("tx_ops is null!");
76 		return QDF_STATUS_E_NULL_VALUE;
77 	}
78 
79 	if (!dcs_tx_ops->dcs_attach) {
80 		dcs_err("dcs_attach function is null!");
81 		return QDF_STATUS_E_NULL_VALUE;
82 	}
83 
84 	return dcs_tx_ops->dcs_attach(psoc);
85 }
86 
87 QDF_STATUS wlan_dcs_detach(struct wlan_objmgr_psoc *psoc)
88 {
89 	struct wlan_target_if_dcs_tx_ops *dcs_tx_ops;
90 
91 	if (!psoc) {
92 		dcs_err("psoc is null");
93 		return QDF_STATUS_E_NULL_VALUE;
94 	}
95 
96 	dcs_tx_ops = target_if_dcs_get_tx_ops(psoc);
97 	if (!dcs_tx_ops) {
98 		dcs_err("tx_ops is null!");
99 		return QDF_STATUS_E_NULL_VALUE;
100 	}
101 
102 	if (!dcs_tx_ops->dcs_detach) {
103 		dcs_err("dcs_detach function is null!");
104 		return QDF_STATUS_E_NULL_VALUE;
105 	}
106 
107 	return dcs_tx_ops->dcs_detach(psoc);
108 }
109 
110 QDF_STATUS wlan_dcs_cmd_send(struct wlan_objmgr_psoc *psoc,
111 			     uint32_t pdev_id,
112 			     bool is_host_pdev_id)
113 {
114 	struct wlan_target_if_dcs_tx_ops *dcs_tx_ops;
115 	struct dcs_pdev_priv_obj *dcs_pdev_priv;
116 	uint32_t dcs_enable;
117 
118 	if (!psoc) {
119 		dcs_err("psoc is null");
120 		return QDF_STATUS_E_NULL_VALUE;
121 	}
122 
123 	dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc, pdev_id);
124 	if (!dcs_pdev_priv) {
125 		dcs_err("dcs pdev private object is null");
126 		return QDF_STATUS_E_NULL_VALUE;
127 	}
128 
129 	dcs_enable = dcs_pdev_priv->dcs_host_params.dcs_enable &
130 			dcs_pdev_priv->dcs_host_params.dcs_enable_cfg;
131 	dcs_tx_ops = target_if_dcs_get_tx_ops(psoc);
132 
133 	if (dcs_tx_ops && dcs_tx_ops->dcs_cmd_send) {
134 		dcs_info("dcs_enable: %u, pdev_id: %u", dcs_enable, pdev_id);
135 		return dcs_tx_ops->dcs_cmd_send(psoc,
136 						pdev_id,
137 						is_host_pdev_id,
138 						dcs_enable);
139 	}
140 
141 	return QDF_STATUS_SUCCESS;
142 }
143 
144 /**
145  * wlan_dcs_im_copy_stats() - dcs target interference mitigation statistics copy
146  * @prev_stats: previous statistics pointer
147  * @curr_stats: current statistics pointer
148  *
149  * Return: None
150  */
151 static inline void
152 wlan_dcs_im_copy_stats(struct wlan_host_dcs_im_tgt_stats *prev_stats,
153 		       struct wlan_host_dcs_im_tgt_stats *curr_stats)
154 {
155 	if (!prev_stats || !curr_stats) {
156 		dcs_err("previous or current stats is null");
157 		return;
158 	}
159 
160 	/*
161 	 * Right now no other actions are required beyond memcopy,
162 	 * if required the rest of the code would follow.
163 	 */
164 	qdf_mem_copy(prev_stats, curr_stats,
165 		     sizeof(struct wlan_host_dcs_im_tgt_stats));
166 }
167 
168 /**
169  * wlan_dcs_im_print_stats() - print current/previous dcs target im statistics
170  * @prev_stats: previous statistics pointer
171  * @curr_stats: current statistics pointer
172  *
173  * Return: None
174  */
175 static void
176 wlan_dcs_im_print_stats(struct wlan_host_dcs_im_tgt_stats *prev_stats,
177 			struct wlan_host_dcs_im_tgt_stats *curr_stats)
178 {
179 	if (!prev_stats || !curr_stats) {
180 		dcs_err("previous or current stats is null");
181 		return;
182 	}
183 
184 	/* Debug, dump all received stats first */
185 	dcs_debug("tgt_curr/tsf: %u", curr_stats->reg_tsf32);
186 	dcs_debug("tgt_curr/last_ack_rssi: %u", curr_stats->last_ack_rssi);
187 	dcs_debug("tgt_curr/tx_waste_time: %u", curr_stats->tx_waste_time);
188 	dcs_debug("tgt_curr/dcs_rx_time: %u", curr_stats->rx_time);
189 	dcs_debug("tgt_curr/listen_time: %u",
190 		  curr_stats->mib_stats.listen_time);
191 	dcs_debug("tgt_curr/tx_frame_cnt: %u",
192 		  curr_stats->mib_stats.reg_tx_frame_cnt);
193 	dcs_debug("tgt_curr/rx_frame_cnt: %u",
194 		  curr_stats->mib_stats.reg_rx_frame_cnt);
195 	dcs_debug("tgt_curr/rxclr_cnt: %u",
196 		  curr_stats->mib_stats.reg_rxclr_cnt);
197 	dcs_debug("tgt_curr/reg_cycle_cnt: %u",
198 		  curr_stats->mib_stats.reg_cycle_cnt);
199 	dcs_debug("tgt_curr/rxclr_ext_cnt: %u",
200 		  curr_stats->mib_stats.reg_rxclr_ext_cnt);
201 	dcs_debug("tgt_curr/ofdm_phyerr_cnt: %u",
202 		  curr_stats->mib_stats.reg_ofdm_phyerr_cnt);
203 	dcs_debug("tgt_curr/cck_phyerr_cnt: %u",
204 		  curr_stats->mib_stats.reg_cck_phyerr_cnt);
205 
206 	dcs_debug("tgt_prev/tsf: %u", prev_stats->reg_tsf32);
207 	dcs_debug("tgt_prev/last_ack_rssi: %u", prev_stats->last_ack_rssi);
208 	dcs_debug("tgt_prev/tx_waste_time: %u", prev_stats->tx_waste_time);
209 	dcs_debug("tgt_prev/rx_time: %u", prev_stats->rx_time);
210 	dcs_debug("tgt_prev/listen_time: %u",
211 		  prev_stats->mib_stats.listen_time);
212 	dcs_debug("tgt_prev/tx_frame_cnt: %u",
213 		  prev_stats->mib_stats.reg_tx_frame_cnt);
214 	dcs_debug("tgt_prev/rx_frame_cnt: %u",
215 		  prev_stats->mib_stats.reg_rx_frame_cnt);
216 	dcs_debug("tgt_prev/rxclr_cnt: %u",
217 		  prev_stats->mib_stats.reg_rxclr_cnt);
218 	dcs_debug("tgt_prev/reg_cycle_cnt: %u",
219 		  prev_stats->mib_stats.reg_cycle_cnt);
220 	dcs_debug("tgt_prev/rxclr_ext_cnt: %u",
221 		  prev_stats->mib_stats.reg_rxclr_ext_cnt);
222 	dcs_debug("tgt_prev/ofdm_phyerr_cnt: %u",
223 		  prev_stats->mib_stats.reg_ofdm_phyerr_cnt);
224 	dcs_debug("tgt_prev/cck_phyerr_cnt: %u",
225 		  prev_stats->mib_stats.reg_cck_phyerr_cnt);
226 }
227 
228 /**
229  * wlan_dcs_wlan_interference_process() - dcs detection algorithm handling
230  * @curr_stats: current target im stats pointer
231  * @dcs_pdev_priv: dcs pdev priv pointer
232  *
233  * Return: true or false means start dcs callback handler or not
234  */
235 static bool
236 wlan_dcs_wlan_interference_process(
237 				struct wlan_host_dcs_im_tgt_stats *curr_stats,
238 				struct dcs_pdev_priv_obj *dcs_pdev_priv)
239 {
240 	struct wlan_host_dcs_im_tgt_stats *prev_stats;
241 	struct pdev_dcs_params dcs_host_params;
242 	struct pdev_dcs_im_stats *p_dcs_im_stats;
243 	bool start_dcs_cbk_handler = false;
244 
245 	uint32_t reg_tsf_delta = 0;
246 	uint32_t rxclr_delta = 0;
247 	uint32_t rxclr_ext_delta = 0;
248 	uint32_t cycle_count_delta = 0;
249 	uint32_t tx_frame_delta = 0;
250 	uint32_t rx_frame_delta = 0;
251 	uint32_t my_bss_rx_delta = 0;
252 	uint32_t reg_total_cu = 0;
253 	uint32_t reg_tx_cu = 0;
254 	uint32_t reg_rx_cu = 0;
255 	uint32_t reg_unused_cu = 0;
256 	uint32_t rx_time_cu = 0;
257 	uint32_t reg_ofdm_phyerr_delta = 0;
258 	uint32_t reg_cck_phyerr_delta = 0;
259 	uint32_t reg_ofdm_phyerr_cu = 0;
260 	uint32_t ofdm_phy_err_rate = 0;
261 	uint32_t cck_phy_err_rate = 0;
262 	uint32_t max_phy_err_rate = 0;
263 	uint32_t max_phy_err_count = 0;
264 	uint32_t total_wasted_cu = 0;
265 	uint32_t wasted_tx_cu = 0;
266 	uint32_t tx_err = 0;
267 	uint32_t too_many_phy_errors = 0;
268 
269 	if (!curr_stats) {
270 		dcs_err("curr_stats is NULL");
271 		goto end;
272 	}
273 
274 	if (!dcs_pdev_priv) {
275 		dcs_err("dcs pdev private object is NULL");
276 		goto end;
277 	}
278 
279 	dcs_host_params = dcs_pdev_priv->dcs_host_params;
280 	p_dcs_im_stats = &dcs_pdev_priv->dcs_im_stats;
281 	prev_stats =  &dcs_pdev_priv->dcs_im_stats.prev_dcs_im_stats;
282 
283 	if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE))
284 		wlan_dcs_im_print_stats(prev_stats, curr_stats);
285 
286 	/*
287 	 * Counters would have wrapped. Ideally we should be able to figure this
288 	 * out, but we never know how many times counters wrapped, just ignore.
289 	 */
290 	if ((curr_stats->mib_stats.listen_time <= 0) ||
291 	    (curr_stats->reg_tsf32 <= prev_stats->reg_tsf32)) {
292 		if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE))
293 			dcs_debug("ignoring due to negative TSF value");
294 		goto copy_stats;
295 	}
296 
297 	reg_tsf_delta = curr_stats->reg_tsf32 - prev_stats->reg_tsf32;
298 
299 	/*
300 	 * Do nothing if current stats are not seeming good, probably
301 	 * a reset happened on chip, force cleared
302 	 */
303 	if (prev_stats->mib_stats.reg_rxclr_cnt >
304 		curr_stats->mib_stats.reg_rxclr_cnt) {
305 		if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE))
306 			dcs_debug("ignoring due to negative rxclr count");
307 		goto copy_stats;
308 	}
309 
310 	rxclr_delta = curr_stats->mib_stats.reg_rxclr_cnt -
311 			prev_stats->mib_stats.reg_rxclr_cnt;
312 	rxclr_ext_delta = curr_stats->mib_stats.reg_rxclr_ext_cnt -
313 				prev_stats->mib_stats.reg_rxclr_ext_cnt;
314 	tx_frame_delta = curr_stats->mib_stats.reg_tx_frame_cnt -
315 				prev_stats->mib_stats.reg_tx_frame_cnt;
316 
317 	rx_frame_delta = curr_stats->mib_stats.reg_rx_frame_cnt -
318 				prev_stats->mib_stats.reg_rx_frame_cnt;
319 
320 	cycle_count_delta = curr_stats->mib_stats.reg_cycle_cnt -
321 				prev_stats->mib_stats.reg_cycle_cnt;
322 
323 	my_bss_rx_delta = curr_stats->my_bss_rx_cycle_count -
324 				prev_stats->my_bss_rx_cycle_count;
325 
326 	if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE))
327 		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",
328 			  rxclr_delta, rxclr_ext_delta, tx_frame_delta,
329 			  rx_frame_delta, cycle_count_delta, my_bss_rx_delta);
330 
331 	if (0 == (cycle_count_delta >> 8)) {
332 		if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE))
333 			dcs_debug("cycle count NULL --Investigate--");
334 		goto copy_stats;
335 	}
336 
337 	/* Update user stats */
338 	wlan_dcs_pdev_obj_lock(dcs_pdev_priv);
339 	if (dcs_pdev_priv->dcs_host_params.user_request_count) {
340 		struct wlan_host_dcs_im_user_stats *p_user_stats =
341 					     &p_dcs_im_stats->user_dcs_im_stats;
342 
343 		p_user_stats->cycle_count += cycle_count_delta;
344 		p_user_stats->rxclr_count += rxclr_delta;
345 		p_user_stats->rx_frame_count += rx_frame_delta;
346 		p_user_stats->my_bss_rx_cycle_count += my_bss_rx_delta;
347 		if (0 == p_user_stats->max_rssi &&
348 		    0 == p_user_stats->min_rssi) {
349 			p_user_stats->max_rssi = curr_stats->last_ack_rssi;
350 			p_user_stats->min_rssi = curr_stats->last_ack_rssi;
351 		} else {
352 			if (curr_stats->last_ack_rssi > p_user_stats->max_rssi)
353 				p_user_stats->max_rssi =
354 						      curr_stats->last_ack_rssi;
355 			if (curr_stats->last_ack_rssi < p_user_stats->min_rssi)
356 				p_user_stats->min_rssi =
357 						      curr_stats->last_ack_rssi;
358 		}
359 		dcs_pdev_priv->dcs_host_params.user_request_count--;
360 		if (0 == dcs_pdev_priv->dcs_host_params.user_request_count)
361 			dcs_pdev_priv->dcs_host_params.notify_user = 1;
362 	}
363 	wlan_dcs_pdev_obj_unlock(dcs_pdev_priv);
364 
365 	/*
366 	 * For below scenario, will ignore dcs event data and won't do
367 	 * interference detection algorithm calculation:
368 	 * 1: Current SAP channel isn't on 5G band
369 	 * 2: In the process of ACS
370 	 * 3: In the process of dcs disabling dcs_restart_delay time duration
371 	 */
372 	if (!dcs_host_params.dcs_algorithm_process)
373 		goto copy_stats;
374 
375 	/*
376 	 * Total channel utiliztaion is the amount of time RXCLR is
377 	 * counted. RXCLR is counted, when 'RX is NOT clear', please
378 	 * refer to mac documentation. It means either TX or RX is ON
379 	 *
380 	 * Why shift by 8 ? after multiplication it could overflow. At one
381 	 * second rate, neither cycle_count_celta nor the tsf_delta would be
382 	 * zero after shift by 8 bits
383 	 */
384 	reg_total_cu = ((rxclr_delta >> 8) * 100) / (cycle_count_delta >> 8);
385 	reg_tx_cu = ((tx_frame_delta >> 8) * 100) / (cycle_count_delta >> 8);
386 	reg_rx_cu = ((rx_frame_delta >> 8) * 100) / (cycle_count_delta >> 8);
387 	rx_time_cu = ((curr_stats->rx_time >> 8) * 100) / (reg_tsf_delta >> 8);
388 
389 	/*
390 	 * Amount of the time AP received cannot go higher than the receive
391 	 * cycle count delta. If at all it is, there should have been a
392 	 * computation error, ceil it to receive_cycle_count_diff
393 	 */
394 	if (rx_time_cu > reg_rx_cu)
395 		rx_time_cu = reg_rx_cu;
396 
397 	if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE))
398 		dcs_debug("reg_total_cu: %u, reg_tx_cu: %u, reg_rx_cu: %u, rx_time_cu: %u",
399 			  reg_total_cu, reg_tx_cu, reg_rx_cu, rx_time_cu);
400 
401 	/*
402 	 * Unusable channel utilization is amount of time that we
403 	 * spent in backoff or waiting for other transmit/receive to
404 	 * complete. If there is interference it is more likely that
405 	 * we overshoot the limit. In case of multiple stations, we
406 	 * still see increased channel utilization.  This assumption may
407 	 * not be true for the VOW scenario where either multicast or
408 	 * unicast-UDP is used ( mixed traffic would still cause high
409 	 * channel utilization).
410 	 */
411 	wasted_tx_cu = ((curr_stats->tx_waste_time >> 8) * 100) /
412 							(reg_tsf_delta >> 8);
413 
414 	/*
415 	 * Transmit channel utilization cannot go higher than the amount of time
416 	 * wasted, if so cap the wastage to transmit channel utillzation. This
417 	 * could happen to compution error.
418 	 */
419 	if (reg_tx_cu < wasted_tx_cu)
420 		wasted_tx_cu = reg_tx_cu;
421 
422 	tx_err = (reg_tx_cu && wasted_tx_cu) ?
423 			(wasted_tx_cu * 100) / reg_tx_cu : 0;
424 
425 	/*
426 	 * The below actually gives amount of time we are not using, or the
427 	 * interferer is active.
428 	 * rx_time_cu is what computed receive time *NOT* rx_cycle_count
429 	 * rx_cycle_count is our receive+interferer's transmit
430 	 * un-used is really total_cycle_counts -
431 	 *      (our_rx_time(rx_time_cu) + our_receive_time)
432 	 */
433 	reg_unused_cu = (reg_total_cu >= (reg_tx_cu + rx_time_cu)) ?
434 				(reg_total_cu - (reg_tx_cu + rx_time_cu)) : 0;
435 
436 	/* If any retransmissions are there, count them as wastage */
437 	total_wasted_cu = reg_unused_cu + wasted_tx_cu;
438 
439 	/* Check ofdm and cck errors */
440 	if (unlikely(curr_stats->mib_stats.reg_ofdm_phyerr_cnt <
441 			prev_stats->mib_stats.reg_ofdm_phyerr_cnt))
442 		reg_ofdm_phyerr_delta =
443 			curr_stats->mib_stats.reg_ofdm_phyerr_cnt;
444 	else
445 		reg_ofdm_phyerr_delta =
446 			curr_stats->mib_stats.reg_ofdm_phyerr_cnt -
447 				prev_stats->mib_stats.reg_ofdm_phyerr_cnt;
448 
449 	if (unlikely(curr_stats->mib_stats.reg_cck_phyerr_cnt <
450 			prev_stats->mib_stats.reg_cck_phyerr_cnt))
451 		reg_cck_phyerr_delta = curr_stats->mib_stats.reg_cck_phyerr_cnt;
452 	else
453 		reg_cck_phyerr_delta =
454 			curr_stats->mib_stats.reg_cck_phyerr_cnt -
455 				prev_stats->mib_stats.reg_cck_phyerr_cnt;
456 
457 	/*
458 	 * Add the influence of ofdm phy errors to the wasted channel
459 	 * utillization, this computed through time wasted in errors
460 	 */
461 	reg_ofdm_phyerr_cu = reg_ofdm_phyerr_delta *
462 				dcs_host_params.phy_err_penalty;
463 	total_wasted_cu +=
464 		(reg_ofdm_phyerr_cu > 0) ?
465 		(((reg_ofdm_phyerr_cu >> 8) * 100) / (reg_tsf_delta >> 8)) : 0;
466 
467 	ofdm_phy_err_rate = (curr_stats->mib_stats.reg_ofdm_phyerr_cnt * 1000) /
468 				curr_stats->mib_stats.listen_time;
469 	cck_phy_err_rate = (curr_stats->mib_stats.reg_cck_phyerr_cnt * 1000) /
470 				curr_stats->mib_stats.listen_time;
471 
472 	if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) {
473 		dcs_debug("reg_unused_cu: %u, reg_ofdm_phyerr_delta: %u, reg_cck_phyerr_delta: %u, reg_ofdm_phyerr_cu: %u",
474 			  reg_unused_cu, reg_ofdm_phyerr_delta,
475 			  reg_cck_phyerr_delta, reg_ofdm_phyerr_cu);
476 		dcs_debug("total_wasted_cu: %u, ofdm_phy_err_rate: %u, cck_phy_err_rate: %u",
477 			  total_wasted_cu, ofdm_phy_err_rate, cck_phy_err_rate);
478 		dcs_debug("new_unused_cu: %u, reg_ofdm_phy_error_cu: %u",
479 			  reg_unused_cu,
480 			 (curr_stats->mib_stats.reg_ofdm_phyerr_cnt * 100) /
481 					curr_stats->mib_stats.listen_time);
482 	}
483 
484 	/* Check if the error rates are higher than the thresholds */
485 	max_phy_err_rate = QDF_MAX(ofdm_phy_err_rate, cck_phy_err_rate);
486 
487 	max_phy_err_count = QDF_MAX(curr_stats->mib_stats.reg_ofdm_phyerr_cnt,
488 				    curr_stats->mib_stats.reg_cck_phyerr_cnt);
489 
490 	if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE))
491 		dcs_debug("max_phy_err_rate: %u, max_phy_err_count: %u",
492 			  max_phy_err_rate, max_phy_err_count);
493 
494 	if (((max_phy_err_rate >= dcs_host_params.phy_err_threshold) &&
495 	     (max_phy_err_count > dcs_host_params.phy_err_threshold)) ||
496 		(curr_stats->phyerr_cnt > dcs_host_params.radar_err_threshold))
497 		too_many_phy_errors = 1;
498 
499 	if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_CRITICAL)) {
500 		dcs_debug("total_cu: %u, tx_cu: %u, rx_cu: %u, rx_time_cu: %u, unused cu: %u",
501 			  reg_total_cu, reg_tx_cu,
502 			  reg_rx_cu, rx_time_cu, reg_unused_cu);
503 		dcs_debug("phyerr: %u, total_wasted_cu: %u, phyerror_cu: %u, wasted_cu: %u, reg_tx_cu: %u, reg_rx_cu: %u",
504 			  too_many_phy_errors, total_wasted_cu,
505 			  reg_ofdm_phyerr_cu, wasted_tx_cu,
506 			  reg_tx_cu, reg_rx_cu);
507 		dcs_debug("tx_err: %u", tx_err);
508 	}
509 
510 	if (reg_unused_cu >= dcs_host_params.coch_intfr_threshold)
511 		/* Quickly reach to decision */
512 		p_dcs_im_stats->im_intfr_cnt += 2;
513 	else if (too_many_phy_errors &&
514 		 (((total_wasted_cu >
515 			(dcs_host_params.coch_intfr_threshold + 10)) &&
516 		((reg_tx_cu + reg_rx_cu) > dcs_host_params.user_max_cu)) ||
517 		((reg_tx_cu > DCS_TX_MAX_CU) &&
518 			(tx_err >= dcs_host_params.tx_err_threshold))))
519 		p_dcs_im_stats->im_intfr_cnt++;
520 
521 	if (p_dcs_im_stats->im_intfr_cnt >=
522 		dcs_host_params.intfr_detection_threshold) {
523 		if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_CRITICAL)) {
524 			dcs_debug("interference threshold exceeded");
525 			dcs_debug("unused_cu: %u, too_any_phy_errors: %u, total_wasted_cu: %u, reg_tx_cu: %u, reg_rx_cu: %u",
526 				  reg_unused_cu, too_many_phy_errors,
527 				  total_wasted_cu, reg_tx_cu, reg_rx_cu);
528 		}
529 
530 		p_dcs_im_stats->im_intfr_cnt = 0;
531 		p_dcs_im_stats->im_samp_cnt = 0;
532 		/*
533 		 * Once the interference is detected, change the channel, as on
534 		 * today this is common routine for wirelesslan and
535 		 * non-wirelesslan interference. Name as such kept the same
536 		 * because of the DA code, which is using the same function.
537 		 */
538 		start_dcs_cbk_handler = true;
539 	} else if (0 == p_dcs_im_stats->im_intfr_cnt ||
540 			p_dcs_im_stats->im_samp_cnt >=
541 				dcs_host_params.intfr_detection_window) {
542 		p_dcs_im_stats->im_intfr_cnt = 0;
543 		p_dcs_im_stats->im_samp_cnt = 0;
544 	}
545 
546 	/* Count the current run too */
547 	p_dcs_im_stats->im_samp_cnt++;
548 
549 	if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE))
550 		dcs_debug("intfr_count: %u, sample_count: %u",
551 			  p_dcs_im_stats->im_intfr_cnt,
552 			  p_dcs_im_stats->im_samp_cnt);
553 copy_stats:
554 	 /* Copy the stats for next cycle */
555 	wlan_dcs_im_copy_stats(prev_stats, curr_stats);
556 end:
557 	return start_dcs_cbk_handler;
558 }
559 
560 void wlan_dcs_disable_timer_fn(void *dcs_timer_args)
561 {
562 	struct pdev_dcs_timer_args *dcs_timer_args_ctx;
563 	struct wlan_objmgr_psoc *psoc;
564 	uint32_t pdev_id;
565 	struct dcs_psoc_priv_obj *dcs_psoc_priv;
566 	struct dcs_pdev_priv_obj *dcs_pdev_priv;
567 
568 	if (!dcs_timer_args) {
569 		dcs_err("dcs timer args is null");
570 		return;
571 	}
572 
573 	dcs_timer_args_ctx = (struct pdev_dcs_timer_args *)dcs_timer_args;
574 	psoc = dcs_timer_args_ctx->psoc;
575 	pdev_id = dcs_timer_args_ctx->pdev_id;
576 
577 	dcs_psoc_priv =
578 		wlan_objmgr_psoc_get_comp_private_obj(psoc, WLAN_UMAC_COMP_DCS);
579 	if (!dcs_psoc_priv) {
580 		dcs_err("dcs psoc private object is null");
581 		return;
582 	}
583 
584 	dcs_pdev_priv = &dcs_psoc_priv->dcs_pdev_priv[pdev_id];
585 	dcs_pdev_priv->dcs_freq_ctrl_params.disable_delay_process = false;
586 
587 	dcs_info("dcs disable timeout, enable dcs detection again");
588 	wlan_dcs_set_algorithm_process(psoc, pdev_id, true);
589 }
590 
591 /**
592  * wlan_dcs_frequency_control() - dcs frequency control handling
593  * @psoc: psoc pointer
594  * @dcs_pdev_priv: dcs pdev priv pointer
595  * @event: dcs stats event pointer
596  *
597  * Return: none
598  */
599 static void wlan_dcs_frequency_control(struct wlan_objmgr_psoc *psoc,
600 				       struct dcs_pdev_priv_obj *dcs_pdev_priv,
601 				       struct wlan_host_dcs_event *event)
602 {
603 	struct dcs_psoc_priv_obj *dcs_psoc_priv;
604 	struct pdev_dcs_freq_ctrl_params *dcs_freq_ctrl_params;
605 	uint8_t timestamp_pos;
606 	unsigned long current_time;
607 	uint8_t delta_pos;
608 	unsigned long delta_time;
609 	bool disable_dcs_sometime = false;
610 
611 	if (!psoc || !dcs_pdev_priv || !event) {
612 		dcs_err("psoc or dcs_pdev_priv or event is null");
613 		return;
614 	}
615 
616 	dcs_freq_ctrl_params = &dcs_pdev_priv->dcs_freq_ctrl_params;
617 	if (dcs_freq_ctrl_params->disable_delay_process) {
618 		dcs_err("In the process of dcs disable, shouldn't go to here");
619 		return;
620 	}
621 
622 	current_time = qdf_get_system_timestamp();
623 	if (dcs_freq_ctrl_params->dcs_happened_count >=
624 		dcs_freq_ctrl_params->disable_threshold_per_5mins) {
625 		delta_pos =
626 			dcs_freq_ctrl_params->dcs_happened_count -
627 			dcs_freq_ctrl_params->disable_threshold_per_5mins;
628 		delta_pos = delta_pos % MAX_DCS_TIME_RECORD;
629 
630 		delta_time = current_time -
631 				dcs_freq_ctrl_params->timestamp[delta_pos];
632 		if (delta_time < DCS_FREQ_CONTROL_TIME)
633 			disable_dcs_sometime = true;
634 	}
635 
636 	if (!disable_dcs_sometime) {
637 		timestamp_pos = dcs_freq_ctrl_params->dcs_happened_count %
638 							MAX_DCS_TIME_RECORD;
639 		dcs_freq_ctrl_params->timestamp[timestamp_pos] = current_time;
640 		dcs_freq_ctrl_params->dcs_happened_count++;
641 	}
642 
643 	/*
644 	 * Before start dcs callback handler or disable dcs for some time,
645 	 * need to ignore dcs event data and won't do interference detection
646 	 * algorithm calculation for disabling dcs detection firstly.
647 	 */
648 	wlan_dcs_set_algorithm_process(psoc, event->dcs_param.pdev_id, false);
649 
650 	if (disable_dcs_sometime) {
651 		dcs_freq_ctrl_params->disable_delay_process = true;
652 		dcs_pdev_priv->dcs_timer_args.psoc = psoc;
653 		dcs_pdev_priv->dcs_timer_args.pdev_id =
654 						event->dcs_param.pdev_id;
655 		qdf_timer_start(&dcs_pdev_priv->dcs_disable_timer,
656 				dcs_pdev_priv->dcs_freq_ctrl_params.
657 				restart_delay * 60 * 1000);
658 		dcs_info("start dcs disable timer");
659 	} else {
660 		dcs_psoc_priv = wlan_objmgr_psoc_get_comp_private_obj(
661 							psoc,
662 							WLAN_UMAC_COMP_DCS);
663 		if (!dcs_psoc_priv) {
664 			dcs_err("dcs private psoc object is null");
665 			return;
666 		}
667 
668 		dcs_info("start dcs callback handler");
669 		dcs_psoc_priv->dcs_cbk.cbk(psoc, event->dcs_param.pdev_id,
670 					   event->dcs_param.interference_type,
671 					   dcs_psoc_priv->dcs_cbk.arg);
672 	}
673 }
674 
675 /**
676  * wlan_dcs_switch_chan() - switch channel for vdev
677  * @vdev: vdev ptr
678  * @tgt_freq: target frequency
679  * @tgt_width: target channel width
680  *
681  * Return: QDF_STATUS
682  */
683 static QDF_STATUS
684 wlan_dcs_switch_chan(struct wlan_objmgr_vdev *vdev, qdf_freq_t tgt_freq,
685 		     enum phy_ch_width tgt_width)
686 {
687 	struct wlan_objmgr_psoc *psoc;
688 	struct dcs_psoc_priv_obj *dcs_psoc_priv;
689 	dcs_switch_chan_cb switch_chan_cb;
690 
691 	psoc = wlan_vdev_get_psoc(vdev);
692 	if (!psoc)
693 		return QDF_STATUS_E_INVAL;
694 
695 	dcs_psoc_priv = wlan_objmgr_psoc_get_comp_private_obj(psoc,
696 					WLAN_UMAC_COMP_DCS);
697 	if (!dcs_psoc_priv)
698 		return QDF_STATUS_E_INVAL;
699 
700 	switch_chan_cb = dcs_psoc_priv->switch_chan_cb;
701 	if (!switch_chan_cb)
702 		return QDF_STATUS_E_NOSUPPORT;
703 
704 	return switch_chan_cb(vdev, tgt_freq, tgt_width);
705 }
706 
707 #ifdef WLAN_POLICY_MGR_ENABLE
708 /**
709  * wlan_dcs_get_pcl_for_sap() - get preferred channel list for SAP
710  * @vdev: vdev ptr
711  * @freq_list: Pointer to PCL
712  * @freq_list_sz: Max size of PCL
713  *
714  * Return: number of channels in PCL
715  */
716 static uint32_t wlan_dcs_get_pcl_for_sap(struct wlan_objmgr_vdev *vdev,
717 					 qdf_freq_t *freq_list,
718 					 uint32_t freq_list_sz)
719 {
720 	struct wlan_objmgr_psoc *psoc;
721 	struct wlan_objmgr_pdev *pdev;
722 	struct policy_mgr_pcl_list *pcl;
723 	qdf_freq_t freq;
724 	enum channel_state state;
725 	QDF_STATUS status;
726 	int i, j;
727 
728 	psoc = wlan_vdev_get_psoc(vdev);
729 	if (!psoc)
730 		return 0;
731 
732 	pdev = wlan_vdev_get_pdev(vdev);
733 	if (!pdev)
734 		return 0;
735 
736 	pcl = qdf_mem_malloc(sizeof(*pcl));
737 	if (!pcl)
738 		return 0;
739 
740 	status = policy_mgr_get_pcl_for_vdev_id(psoc,
741 						PM_SAP_MODE,
742 						pcl->pcl_list, &pcl->pcl_len,
743 						pcl->weight_list,
744 						QDF_ARRAY_SIZE(pcl->weight_list),
745 						wlan_vdev_get_id(vdev));
746 	if (QDF_IS_STATUS_ERROR(status) || !pcl->pcl_len) {
747 		qdf_mem_free(pcl);
748 		return 0;
749 	}
750 
751 	for (i = 0, j = 0; i < pcl->pcl_len && i < freq_list_sz; i++) {
752 		freq = (qdf_freq_t)pcl->pcl_list[i];
753 		state = wlan_reg_get_channel_state_for_freq(pdev, freq);
754 		if (state != CHANNEL_STATE_ENABLE)
755 			continue;
756 
757 		freq_list[j++] = freq;
758 	}
759 
760 	qdf_mem_free(pcl);
761 	return j;
762 }
763 #else
764 static uint32_t wlan_dcs_get_pcl_for_sap(struct wlan_objmgr_vdev *vdev,
765 					 qdf_freq_t *freq_list,
766 					 uint32_t freq_list_sz)
767 {
768 	struct wlan_objmgr_pdev *pdev;
769 	struct regulatory_channel *cur_chan_list;
770 	qdf_freq_t freq;
771 	enum channel_state state;
772 	int i, j;
773 
774 	pdev = wlan_vdev_get_pdev(vdev);
775 	if (!pdev)
776 		return 0;
777 
778 	cur_chan_list = qdf_mem_malloc(NUM_CHANNELS *
779 			sizeof(struct regulatory_channel));
780 	if (!cur_chan_list)
781 		return 0;
782 
783 	if (wlan_reg_get_current_chan_list(pdev, cur_chan_list) !=
784 					   QDF_STATUS_SUCCESS) {
785 		qdf_mem_free(cur_chan_list);
786 		return 0;
787 	}
788 
789 	for (i = 0, j = 0; i < NUM_CHANNELS && i < freq_list_sz; i++) {
790 		freq = cur_chan_list[i].center_freq;
791 		state = wlan_reg_get_channel_state_for_freq(pdev, freq);
792 		if (state != CHANNEL_STATE_ENABLE)
793 			continue;
794 
795 		freq_list[j++] = freq;
796 	}
797 
798 	qdf_mem_free(cur_chan_list);
799 	return j;
800 }
801 #endif
802 
803 /**
804  * wlan_dcs_awgn_get_intf_for_seg() - get interference for specified segment
805  * @awgn_info: awgn info pointer
806  * @segment: segment index in channel band
807  *
808  * This function extracts the information from awgn event and check interference
809  * within the specified segment.
810  *
811  * Return: true if interference is found within the segment, false otherwise.
812  */
813 static bool
814 wlan_dcs_awgn_get_intf_for_seg(struct wlan_host_dcs_awgn_info *awgn_info,
815 			       uint32_t segment)
816 {
817 	uint32_t seg_mask;
818 
819 	switch (segment) {
820 	case WLAN_DCS_SEG_PRI20:
821 		seg_mask = WLAN_DCS_SEG_PRI20_MASK;
822 		break;
823 	case WLAN_DCS_SEG_SEC20:
824 		seg_mask = WLAN_DCS_SEG_SEC20_MASK;
825 		break;
826 	case WLAN_DCS_SEG_SEC40:
827 		seg_mask = WLAN_DCS_SEG_SEC40_MASK;
828 		break;
829 	case WLAN_DCS_SEG_SEC80:
830 		seg_mask = WLAN_DCS_SEG_SEC80_MASK;
831 		break;
832 	case WLAN_DCS_SEG_SEC160:
833 		seg_mask = WLAN_DCS_SEG_SEC160_MASK;
834 		break;
835 	default:
836 		seg_mask = 0xFFFFFFFF;
837 		break;
838 	}
839 
840 	return (awgn_info->chan_bw_intf_bitmap & seg_mask);
841 }
842 
843 /**
844  * wlan_dcs_get_max_seg_idx() - get max segment index for channel width
845  * @width: channel width
846  *
847  * Return: max segment index(enum wlan_dcs_chan_seg) for the channel width.
848  */
849 static enum wlan_dcs_chan_seg wlan_dcs_get_max_seg_idx(enum phy_ch_width width)
850 {
851 	switch (width) {
852 	case CH_WIDTH_160MHZ: /* fallthrough */
853 	case CH_WIDTH_80P80MHZ:
854 		return WLAN_DCS_SEG_SEC80;
855 	case CH_WIDTH_80MHZ:
856 		return WLAN_DCS_SEG_SEC40;
857 	case CH_WIDTH_40MHZ:
858 		return WLAN_DCS_SEG_SEC20;
859 	case CH_WIDTH_20MHZ:
860 		return WLAN_DCS_SEG_PRI20;
861 	default:
862 		dcs_err("Invalid ch width %d", width);
863 		return WLAN_DCS_SEG_INVALID;
864 	}
865 }
866 
867 /**
868  * wlan_dcs_get_chan_width_for_seg() - get channel width for specified segment
869  * @seg_idx: segment index
870  *
871  * Return: channel width for segment index
872  */
873 static enum phy_ch_width
874 wlan_dcs_get_chan_width_for_seg(enum wlan_dcs_chan_seg seg_idx)
875 {
876 	switch (seg_idx) {
877 	case WLAN_DCS_SEG_SEC80:
878 		return CH_WIDTH_160MHZ;
879 	case WLAN_DCS_SEG_SEC40:
880 		return CH_WIDTH_80MHZ;
881 	case WLAN_DCS_SEG_SEC20:
882 		return CH_WIDTH_40MHZ;
883 	case WLAN_DCS_SEG_PRI20:
884 		return CH_WIDTH_20MHZ;
885 	default:
886 		dcs_err("Invalid seg idx %d", seg_idx);
887 		return CH_WIDTH_INVALID;
888 	}
889 }
890 
891 /**
892  * wlan_dcs_get_max_no_intf_bw() - get max no interference band width
893  * @awgn_info: pointer to awgn info
894  * @width: pointer to channel width
895  *
896  * This function trys to get max no interference band width according to
897  * awgn event.
898  *
899  * Return: true if valid no interference band width is found, false otherwise.
900  */
901 static bool
902 wlan_dcs_get_max_no_intf_bw(struct wlan_host_dcs_awgn_info *awgn_info,
903 			    enum phy_ch_width *width)
904 {
905 	enum wlan_dcs_chan_seg seg_idx, max_seg_idx;
906 
907 	max_seg_idx = wlan_dcs_get_max_seg_idx(awgn_info->channel_width);
908 	if (max_seg_idx == WLAN_DCS_SEG_INVALID)
909 		return false;
910 
911 	seg_idx = WLAN_DCS_SEG_PRI20;
912 	while (seg_idx <= max_seg_idx) {
913 		if (wlan_dcs_awgn_get_intf_for_seg(awgn_info, seg_idx)) {
914 			dcs_debug("Intf found for seg idx %d", seg_idx);
915 			break;
916 		}
917 		seg_idx++;
918 	}
919 
920 	/* scroll back to the last no-intf idx */
921 	seg_idx--;
922 
923 	if (seg_idx == WLAN_DCS_SEG_INVALID) {
924 		/* If pri20 contains interference, do full channel change */
925 		dcs_debug("Primary 20MHz Channel interference detected");
926 		return false;
927 	}
928 
929 	*width = wlan_dcs_get_chan_width_for_seg(seg_idx);
930 	if (*width == CH_WIDTH_160MHZ &&
931 	    awgn_info->channel_width == CH_WIDTH_80P80MHZ)
932 		*width = CH_WIDTH_80P80MHZ;
933 
934 	dcs_debug("Found the max no intf width %d", *width);
935 	return (*width != CH_WIDTH_INVALID);
936 }
937 
938 /**
939  * wlan_dcs_get_available_chan_for_bw() - get available channel for specified
940  *  band width
941  * @pdev: pdev ptr
942  * @awgn_info: pointer to awgn info
943  * @bw: channel width
944  * @freq_list: List of preferred channels
945  * @freq_num: Number of channels in the PCL
946  * @random: request for random channel
947  *
948  * Return: the selected channel frequency, 0 if no available chan is found.
949  */
950 static qdf_freq_t
951 wlan_dcs_get_available_chan_for_bw(struct wlan_objmgr_pdev *pdev,
952 				   struct wlan_host_dcs_awgn_info *awgn_info,
953 				   enum phy_ch_width bw, qdf_freq_t *freq_list,
954 				   uint32_t freq_num, bool random)
955 {
956 	int i, j = 0;
957 	uint32_t random_chan_idx;
958 	qdf_freq_t freq, selected_freq = 0;
959 	const struct bonded_channel_freq *bonded_chan_ptr = NULL;
960 	enum channel_state state;
961 	uint16_t chan_cfreq;
962 	bool is_safe = true;
963 
964 	if (!freq_list || !freq_num)
965 		return selected_freq;
966 
967 	for (i = 0; i < freq_num; i++) {
968 		if (j && !random) {
969 			selected_freq = freq_list[0];
970 			dcs_debug("get the first available freq %u for bw %u",
971 				  selected_freq, bw);
972 			break;
973 		}
974 
975 		freq = freq_list[i];
976 		if (!WLAN_REG_IS_SAME_BAND_FREQS(freq, awgn_info->center_freq))
977 			continue;
978 
979 		/**
980 		 * DFS channel may need CAC during restart, which costs time
981 		 * and may cause failure.
982 		 */
983 		if (wlan_reg_is_dfs_for_freq(pdev, freq)) {
984 			dcs_debug("skip dfs freq %u", freq);
985 			continue;
986 		}
987 
988 		if (bonded_chan_ptr &&
989 		    freq >= bonded_chan_ptr->start_freq &&
990 		    freq <= bonded_chan_ptr->end_freq) {
991 			if (is_safe) {
992 				dcs_debug("add freq directly [%d] = %u",
993 					  j, freq);
994 				freq_list[j++] = freq;
995 			}
996 			continue;
997 		}
998 
999 		state = wlan_reg_get_5g_bonded_channel_and_state_for_freq(
1000 				pdev, freq, bw, &bonded_chan_ptr);
1001 		if (state != CHANNEL_STATE_ENABLE)
1002 			continue;
1003 
1004 		/* no bonding channel for 20MHz */
1005 		if (bw == CH_WIDTH_20MHZ) {
1006 			if (WLAN_DCS_IS_FREQ_IN_WIDTH(awgn_info->center_freq,
1007 						      awgn_info->center_freq0,
1008 						      awgn_info->center_freq1,
1009 						      awgn_info->channel_width,
1010 						      freq))
1011 				continue;
1012 
1013 			dcs_debug("add freq[%d] = %u", j, freq);
1014 			freq_list[j++] = freq;
1015 			continue;
1016 		}
1017 
1018 		is_safe = true;
1019 		chan_cfreq =  bonded_chan_ptr->start_freq;
1020 		while (chan_cfreq <= bonded_chan_ptr->end_freq) {
1021 			if (WLAN_DCS_IS_FREQ_IN_WIDTH(awgn_info->center_freq,
1022 						      awgn_info->center_freq0,
1023 						      awgn_info->center_freq1,
1024 						      awgn_info->channel_width,
1025 						      chan_cfreq)) {
1026 				is_safe = false;
1027 				break;
1028 			}
1029 			chan_cfreq = chan_cfreq + 20;
1030 		}
1031 		if (is_safe) {
1032 			dcs_debug("add freq[%d] = %u", j, freq);
1033 			freq_list[j++] = freq;
1034 		}
1035 	}
1036 
1037 	if (j && random) {
1038 		qdf_get_random_bytes(&random_chan_idx, sizeof(random_chan_idx));
1039 		random_chan_idx = random_chan_idx % j;
1040 		selected_freq = freq_list[random_chan_idx];
1041 		dcs_debug("get freq[%d] = %u for bw %u",
1042 			  random_chan_idx, selected_freq, bw);
1043 	}
1044 
1045 	return selected_freq;
1046 }
1047 
1048 /**
1049  * wlan_dcs_sap_get_available_chan() - get available channel for sap
1050  * @vdev: vdev ptr
1051  * @awgn_info: pointer to awgn info
1052  * @tgt_freq: frequency of the selected channel
1053  * @tgt_width: band width of the selected channel
1054  * @random: request for random channel
1055  *
1056  * This function trys to get no-interference chan with max possible bandwidth
1057  * from pcl for sap according to awgn info.
1058  *
1059  * Return: true if available channel is found, false otherwise.
1060  */
1061 static bool
1062 wlan_dcs_sap_select_chan(struct wlan_objmgr_vdev *vdev,
1063 			 struct wlan_host_dcs_awgn_info *awgn_info,
1064 			 qdf_freq_t *tgt_freq, enum phy_ch_width *tgt_width,
1065 			 bool random)
1066 {
1067 	int32_t tmp_width;
1068 	qdf_freq_t tmp_freq = 0;
1069 	struct wlan_objmgr_pdev *pdev;
1070 	qdf_freq_t *freq_list;
1071 	uint32_t freq_num;
1072 
1073 	freq_list = qdf_mem_malloc(sizeof(*freq_list) * NUM_CHANNELS);
1074 	if (!freq_list)
1075 		return false;
1076 
1077 	freq_num = wlan_dcs_get_pcl_for_sap(vdev, freq_list, NUM_CHANNELS);
1078 	if (!freq_num) {
1079 		qdf_mem_free(freq_list);
1080 		return false;
1081 	}
1082 
1083 	tmp_width = awgn_info->channel_width;
1084 	pdev = wlan_vdev_get_pdev(vdev);
1085 	if (!pdev) {
1086 		qdf_mem_free(freq_list);
1087 		return false;
1088 	}
1089 
1090 	while (tmp_width >= CH_WIDTH_20MHZ) {
1091 		tmp_freq = wlan_dcs_get_available_chan_for_bw(pdev, awgn_info,
1092 							      tmp_width,
1093 							      freq_list,
1094 							      freq_num,
1095 							      random);
1096 		if (tmp_freq)
1097 			break;
1098 		tmp_width--;
1099 	}
1100 
1101 	if (tmp_freq) {
1102 		*tgt_width = tmp_width;
1103 		*tgt_freq = tmp_freq;
1104 		dcs_debug("new_width: %d new_freq %u", tmp_width, tmp_freq);
1105 
1106 		qdf_mem_free(freq_list);
1107 		return true;
1108 	}
1109 
1110 	qdf_mem_free(freq_list);
1111 	return false;
1112 }
1113 
1114 /**
1115  * wlan_dcs_is_awgnim_valid() - validate awgn info
1116  * @awgn_info: pointer to awgn info
1117  *
1118  * Return: true if valid, false otherwise.
1119  */
1120 static inline bool
1121 wlan_dcs_is_awgnim_valid(struct wlan_host_dcs_awgn_info *awgn_info)
1122 {
1123 	return (awgn_info &&
1124 		awgn_info->center_freq && awgn_info->chan_bw_intf_bitmap &&
1125 		awgn_info->channel_width != CH_WIDTH_INVALID &&
1126 		WLAN_REG_IS_6GHZ_CHAN_FREQ(awgn_info->center_freq));
1127 }
1128 
1129 /**
1130  * wlan_dcs_vdev_get_op_chan_info() - get operating channel info for vdev
1131  * @vdev: pointer to vdev object
1132  * @cfreq: Center frequency of primary channel
1133  * @cfreq0: Center frequency of segment 1
1134  * @cfreq1: Center frequency of segment 2
1135  * @ch_width: Channel width, enum phy_ch_width
1136  *
1137  * Return: QDF_STATUS
1138  */
1139 static QDF_STATUS
1140 wlan_dcs_vdev_get_op_chan_info(struct wlan_objmgr_vdev *vdev,
1141 			       qdf_freq_t *cfreq, qdf_freq_t *cfreq0,
1142 			       qdf_freq_t *cfreq1, enum phy_ch_width *ch_width)
1143 {
1144 	struct wlan_channel *chan;
1145 
1146 	if (!vdev)
1147 		return QDF_STATUS_E_INVAL;
1148 
1149 	*cfreq = 0;
1150 	*cfreq0 = 0;
1151 	*cfreq1 = 0;
1152 	*ch_width = 0;
1153 
1154 	if (wlan_vdev_mlme_is_active(vdev) != QDF_STATUS_SUCCESS)
1155 		return QDF_STATUS_E_INVAL;
1156 
1157 	chan = wlan_vdev_get_active_channel(vdev);
1158 	if (!chan)
1159 		return QDF_STATUS_E_INVAL;
1160 
1161 	*cfreq = chan->ch_freq;
1162 	*cfreq0 = chan->ch_cfreq1;
1163 	*cfreq1 = chan->ch_cfreq2;
1164 	*ch_width = chan->ch_width;
1165 
1166 	return QDF_STATUS_SUCCESS;
1167 }
1168 
1169 /**
1170  * wlan_dcs_process_awgn_sta() - process AWGN event for STA
1171  * @pdev: pointer to pdev object
1172  * @object: vdev object
1173  * @arg: Arguments to the handler
1174  *
1175  * Return: void
1176  */
1177 static void wlan_dcs_process_awgn_sta(struct wlan_objmgr_pdev *pdev,
1178 				      void *object, void *arg)
1179 {
1180 	struct wlan_objmgr_vdev *vdev = object;
1181 	struct wlan_host_dcs_awgn_info *awgn_info = arg;
1182 	enum phy_ch_width ch_width;
1183 	enum phy_ch_width tgt_width = CH_WIDTH_INVALID;
1184 	qdf_freq_t op_freq, cfreq0, cfreq1;
1185 	qdf_freq_t tgt_freq = 0;
1186 	QDF_STATUS status;
1187 	uint8_t vdev_id;
1188 	bool found;
1189 
1190 	if (!vdev || !pdev)
1191 		return;
1192 
1193 	if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE)
1194 		return;
1195 
1196 	vdev_id = wlan_vdev_get_id(vdev);
1197 	status = wlan_dcs_vdev_get_op_chan_info(vdev, &op_freq, &cfreq0,
1198 						&cfreq1, &ch_width);
1199 	if (QDF_IS_STATUS_ERROR(status))
1200 		return;
1201 
1202 	if (awgn_info->center_freq != op_freq) {
1203 		dcs_debug("STA-%d: freq not match", vdev_id);
1204 		return;
1205 	}
1206 
1207 	found = wlan_dcs_get_max_no_intf_bw(awgn_info, &tgt_width);
1208 	if (found) {
1209 		if (ch_width <= tgt_width) {
1210 			dcs_debug("STA-%d: freq and bw are unchanged", vdev_id);
1211 			return;
1212 		}
1213 
1214 		tgt_freq = op_freq;
1215 	}
1216 
1217 	/* If no width is found, means to disconnect */
1218 	dcs_debug("STA-%d: target freq %u width %u",
1219 		  vdev_id, tgt_freq, tgt_width);
1220 	wlan_dcs_switch_chan(vdev, tgt_freq, tgt_width);
1221 }
1222 
1223 /**
1224  * wlan_dcs_process_awgn_sap() - process AWGN event for SAP
1225  * @pdev: pointer to pdev object
1226  * @object: vdev object
1227  * @arg: Arguments to the handler
1228  *
1229  * Return: void
1230  */
1231 static void wlan_dcs_process_awgn_sap(struct wlan_objmgr_pdev *pdev,
1232 				      void *object, void *arg)
1233 {
1234 	struct wlan_objmgr_vdev *vdev = object;
1235 	struct wlan_host_dcs_awgn_info *awgn_info = arg;
1236 	enum phy_ch_width ch_width;
1237 	enum phy_ch_width tgt_width = CH_WIDTH_INVALID;
1238 	qdf_freq_t op_freq, cfreq0, cfreq1;
1239 	qdf_freq_t tgt_freq = 0;
1240 	QDF_STATUS status;
1241 	uint8_t vdev_id;
1242 	bool found;
1243 
1244 	if (!vdev || !pdev)
1245 		return;
1246 
1247 	if (wlan_vdev_mlme_get_opmode(vdev) != QDF_SAP_MODE)
1248 		return;
1249 
1250 	vdev_id = wlan_vdev_get_id(vdev);
1251 	status = wlan_dcs_vdev_get_op_chan_info(vdev, &op_freq, &cfreq0, &cfreq1, &ch_width);
1252 	if (QDF_IS_STATUS_ERROR(status))
1253 		return;
1254 
1255 	if (awgn_info->center_freq != op_freq) {
1256 		dcs_debug("SAP-%d: freq not match rpt:%u - op:%u",
1257 			  vdev_id, awgn_info->center_freq, op_freq);
1258 		return;
1259 	}
1260 
1261 	found = wlan_dcs_get_max_no_intf_bw(awgn_info, &tgt_width);
1262 	if (found) {
1263 		if (ch_width <= tgt_width) {
1264 			dcs_debug("SAP-%d: both freq and bw are unchanged",
1265 				  vdev_id);
1266 			return;
1267 		}
1268 
1269 		tgt_freq = op_freq;
1270 	} else {
1271 		wlan_dcs_sap_select_chan(vdev, awgn_info, &tgt_freq,
1272 					 &tgt_width, true);
1273 	}
1274 
1275 	/* If no chan is selected, means to stop sap */
1276 	dcs_debug("SAP-%d: target freq %u width %u",
1277 		  vdev_id, tgt_freq, tgt_width);
1278 	wlan_dcs_switch_chan(vdev, tgt_freq, tgt_width);
1279 }
1280 
1281 /**
1282  * wlan_dcs_awgnim_process() - process awgn IM
1283  * @psoc: psoc ptr
1284  * @pdev_id: pdev id
1285  * @awgn_info: pointer to awgn info
1286  *
1287  * This function triggers channel change for all STAs and SAPs, according
1288  * to AWGN info.
1289  *
1290  * Return: None.
1291  */
1292 static void
1293 wlan_dcs_awgn_process(struct wlan_objmgr_psoc *psoc, uint8_t pdev_id,
1294 		      struct wlan_host_dcs_awgn_info *awgn_info)
1295 {
1296 	struct wlan_objmgr_pdev *pdev;
1297 
1298 	if (!wlan_dcs_is_awgnim_valid(awgn_info)) {
1299 		dcs_err("Invalid awgnim event");
1300 		return;
1301 	}
1302 
1303 	pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_DCS_ID);
1304 	if (!pdev) {
1305 		dcs_err("Invalid pdev id %d", pdev_id);
1306 		return;
1307 	}
1308 
1309 	dcs_debug("pdev id %u width %u freq %u freq0 %u fre1 %u bitmap 0x%x",
1310 		  pdev_id, awgn_info->channel_width, awgn_info->center_freq,
1311 		  awgn_info->center_freq0, awgn_info->center_freq1,
1312 		  awgn_info->chan_bw_intf_bitmap);
1313 
1314 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
1315 					  wlan_dcs_process_awgn_sta,
1316 					  awgn_info, 0, WLAN_DCS_ID);
1317 
1318 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
1319 					  wlan_dcs_process_awgn_sap,
1320 					  awgn_info, 0, WLAN_DCS_ID);
1321 
1322 	wlan_objmgr_pdev_release_ref(pdev, WLAN_DCS_ID);
1323 }
1324 
1325 QDF_STATUS
1326 wlan_dcs_process(struct wlan_objmgr_psoc *psoc,
1327 		 struct wlan_host_dcs_event *event)
1328 {
1329 	struct dcs_pdev_priv_obj *dcs_pdev_priv;
1330 	bool start_dcs_cbk_handler = false;
1331 
1332 	if (!psoc || !event) {
1333 		dcs_err("psoc or event is NULL");
1334 		return QDF_STATUS_E_INVAL;
1335 	}
1336 
1337 	dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc,
1338 						      event->dcs_param.pdev_id);
1339 	if (!dcs_pdev_priv) {
1340 		dcs_err("dcs pdev private object is null");
1341 		return QDF_STATUS_E_INVAL;
1342 	}
1343 
1344 	if (unlikely(dcs_pdev_priv->dcs_host_params.dcs_debug
1345 			>= DCS_DEBUG_VERBOSE))
1346 		dcs_debug("dcs_enable: %u, interference_type: %u, pdev_id: %u",
1347 			  dcs_pdev_priv->dcs_host_params.dcs_enable,
1348 			  event->dcs_param.interference_type,
1349 			  event->dcs_param.pdev_id);
1350 
1351 	switch (event->dcs_param.interference_type) {
1352 	case WLAN_HOST_DCS_CWIM:
1353 		break;
1354 	case WLAN_HOST_DCS_WLANIM:
1355 		if (!dcs_pdev_priv->dcs_host_params.dcs_enable)
1356 			break;
1357 
1358 		if (dcs_pdev_priv->dcs_host_params.dcs_enable &
1359 		    WLAN_HOST_DCS_WLANIM)
1360 			start_dcs_cbk_handler =
1361 				wlan_dcs_wlan_interference_process(
1362 							&event->wlan_stat,
1363 							dcs_pdev_priv);
1364 		if (dcs_pdev_priv->user_cb &&
1365 		    dcs_pdev_priv->dcs_host_params.notify_user) {
1366 			dcs_pdev_priv->dcs_host_params.notify_user = 0;
1367 			dcs_pdev_priv->user_cb(dcs_pdev_priv->requestor_vdev_id,
1368 				 &dcs_pdev_priv->dcs_im_stats.user_dcs_im_stats,
1369 				 0);
1370 		}
1371 		if (start_dcs_cbk_handler)
1372 			wlan_dcs_frequency_control(psoc,
1373 						   dcs_pdev_priv,
1374 						   event);
1375 		break;
1376 	case WLAN_HOST_DCS_AWGNIM:
1377 		/* Skip frequency control for AWGNIM */
1378 		wlan_dcs_awgn_process(psoc, event->dcs_param.pdev_id,
1379 				      &event->awgn_info);
1380 		break;
1381 	default:
1382 		dcs_err("unidentified interference type reported");
1383 		break;
1384 	}
1385 
1386 	return QDF_STATUS_SUCCESS;
1387 }
1388 
1389 void wlan_dcs_clear(struct wlan_objmgr_psoc *psoc, uint32_t pdev_id)
1390 {
1391 	struct dcs_pdev_priv_obj *dcs_pdev_priv;
1392 
1393 	if (!psoc) {
1394 		dcs_err("psoc is null");
1395 		return;
1396 	}
1397 
1398 	dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc, pdev_id);
1399 	if (!dcs_pdev_priv) {
1400 		dcs_err("dcs pdev private object is null");
1401 		return;
1402 	}
1403 
1404 	qdf_timer_stop(&dcs_pdev_priv->dcs_disable_timer);
1405 	qdf_mem_set(&dcs_pdev_priv->dcs_im_stats,
1406 		    sizeof(dcs_pdev_priv->dcs_im_stats), 0);
1407 	qdf_mem_set(dcs_pdev_priv->dcs_freq_ctrl_params.timestamp,
1408 		    MAX_DCS_TIME_RECORD * sizeof(unsigned long), 0);
1409 	dcs_pdev_priv->dcs_freq_ctrl_params.dcs_happened_count = 0;
1410 	dcs_pdev_priv->dcs_freq_ctrl_params.disable_delay_process = false;
1411 	wlan_dcs_set_algorithm_process(psoc, pdev_id, false);
1412 }
1413 
1414 void wlan_dcs_set_algorithm_process(struct wlan_objmgr_psoc *psoc,
1415 				    uint32_t pdev_id,
1416 				    bool dcs_algorithm_process)
1417 {
1418 	struct dcs_pdev_priv_obj *dcs_pdev_priv;
1419 
1420 	dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc, pdev_id);
1421 	if (!dcs_pdev_priv) {
1422 		dcs_err("dcs pdev private object is null");
1423 		return;
1424 	}
1425 
1426 	dcs_pdev_priv->dcs_host_params.dcs_algorithm_process =
1427 							dcs_algorithm_process;
1428 }
1429