xref: /wlan-dirver/qca-wifi-host-cmn/umac/dcs/core/src/wlan_dcs.c (revision 06d0b5348967845f004ebe7c2348bf8f467ad2f9)
1 /*
2  * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /**
19  * DOC: wlan_dcs.c
20  *
21  * This file provide definitions for following:
22  * - (de)register to WMI events for psoc enable
23  * - send dcs wmi command
24  * - dcs algorithm handling
25  */
26 
27 #include <target_if_dcs.h>
28 #include "wlan_dcs.h"
29 #include <wlan_objmgr_psoc_obj_i.h>
30 #include "wlan_utility.h"
31 #ifdef WLAN_POLICY_MGR_ENABLE
32 #include "wlan_policy_mgr_api.h"
33 #endif
34 #include <wlan_reg_services_api.h>
35 
36 struct dcs_pdev_priv_obj *
37 wlan_dcs_get_pdev_private_obj(struct wlan_objmgr_psoc *psoc, uint32_t pdev_id)
38 {
39 	struct dcs_psoc_priv_obj *dcs_psoc_obj;
40 	struct dcs_pdev_priv_obj *dcs_pdev_priv = NULL;
41 
42 	if (!psoc) {
43 		dcs_err("psoc is null");
44 		goto end;
45 	}
46 
47 	dcs_psoc_obj = wlan_objmgr_psoc_get_comp_private_obj(
48 							psoc,
49 							WLAN_UMAC_COMP_DCS);
50 	if (!dcs_psoc_obj) {
51 		dcs_err("dcs psoc object is null");
52 		goto end;
53 	}
54 
55 	if (pdev_id >= WLAN_DCS_MAX_PDEVS) {
56 		dcs_err("invalid pdev_id: %u", pdev_id);
57 		goto end;
58 	}
59 
60 	dcs_pdev_priv = &dcs_psoc_obj->dcs_pdev_priv[pdev_id];
61 end:
62 
63 	return dcs_pdev_priv;
64 }
65 
66 QDF_STATUS wlan_dcs_attach(struct wlan_objmgr_psoc *psoc)
67 {
68 	struct wlan_target_if_dcs_tx_ops *dcs_tx_ops;
69 
70 	if (!psoc) {
71 		dcs_err("psoc is null");
72 		return QDF_STATUS_E_NULL_VALUE;
73 	}
74 
75 	dcs_tx_ops = target_if_dcs_get_tx_ops(psoc);
76 	if (!dcs_tx_ops) {
77 		dcs_err("tx_ops is null!");
78 		return QDF_STATUS_E_NULL_VALUE;
79 	}
80 
81 	if (!dcs_tx_ops->dcs_attach) {
82 		dcs_err("dcs_attach function is null!");
83 		return QDF_STATUS_E_NULL_VALUE;
84 	}
85 
86 	return dcs_tx_ops->dcs_attach(psoc);
87 }
88 
89 QDF_STATUS wlan_dcs_detach(struct wlan_objmgr_psoc *psoc)
90 {
91 	struct wlan_target_if_dcs_tx_ops *dcs_tx_ops;
92 
93 	if (!psoc) {
94 		dcs_err("psoc is null");
95 		return QDF_STATUS_E_NULL_VALUE;
96 	}
97 
98 	dcs_tx_ops = target_if_dcs_get_tx_ops(psoc);
99 	if (!dcs_tx_ops) {
100 		dcs_err("tx_ops is null!");
101 		return QDF_STATUS_E_NULL_VALUE;
102 	}
103 
104 	if (!dcs_tx_ops->dcs_detach) {
105 		dcs_err("dcs_detach function is null!");
106 		return QDF_STATUS_E_NULL_VALUE;
107 	}
108 
109 	return dcs_tx_ops->dcs_detach(psoc);
110 }
111 
112 QDF_STATUS wlan_dcs_cmd_send(struct wlan_objmgr_psoc *psoc,
113 			     uint32_t pdev_id,
114 			     bool is_host_pdev_id)
115 {
116 	struct wlan_target_if_dcs_tx_ops *dcs_tx_ops;
117 	struct dcs_pdev_priv_obj *dcs_pdev_priv;
118 	uint32_t dcs_enable;
119 
120 	if (!psoc) {
121 		dcs_err("psoc is null");
122 		return QDF_STATUS_E_NULL_VALUE;
123 	}
124 
125 	dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc, pdev_id);
126 	if (!dcs_pdev_priv) {
127 		dcs_err("dcs pdev private object is null");
128 		return QDF_STATUS_E_NULL_VALUE;
129 	}
130 
131 	dcs_enable = dcs_pdev_priv->dcs_host_params.dcs_enable &
132 			dcs_pdev_priv->dcs_host_params.dcs_enable_cfg;
133 	dcs_tx_ops = target_if_dcs_get_tx_ops(psoc);
134 
135 	if (dcs_tx_ops && dcs_tx_ops->dcs_cmd_send) {
136 		dcs_debug("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_im_copy_stats() - dcs target interference mitigation statistics copy
148  * @prev_stats: previous statistics pointer
149  * @curr_stats: current statistics pointer
150  *
151  * Return: None
152  */
153 static inline void
154 wlan_dcs_im_copy_stats(struct wlan_host_dcs_im_tgt_stats *prev_stats,
155 		       struct wlan_host_dcs_im_tgt_stats *curr_stats)
156 {
157 	if (!prev_stats || !curr_stats) {
158 		dcs_err("previous or current stats is null");
159 		return;
160 	}
161 
162 	/*
163 	 * Right now no other actions are required beyond memcopy,
164 	 * if required the rest of the code would follow.
165 	 */
166 	qdf_mem_copy(prev_stats, curr_stats,
167 		     sizeof(struct wlan_host_dcs_im_tgt_stats));
168 }
169 
170 /**
171  * wlan_dcs_im_print_stats() - print current/previous dcs target im statistics
172  * @prev_stats: previous statistics pointer
173  * @curr_stats: current statistics pointer
174  *
175  * Return: None
176  */
177 static void
178 wlan_dcs_im_print_stats(struct wlan_host_dcs_im_tgt_stats *prev_stats,
179 			struct wlan_host_dcs_im_tgt_stats *curr_stats)
180 {
181 	if (!prev_stats || !curr_stats) {
182 		dcs_err("previous or current stats is null");
183 		return;
184 	}
185 
186 	/* Debug, dump all received stats first */
187 	dcs_debug("tgt_curr/tsf: %u", curr_stats->reg_tsf32);
188 	dcs_debug("tgt_curr/last_ack_rssi: %u", curr_stats->last_ack_rssi);
189 	dcs_debug("tgt_curr/tx_waste_time: %u", curr_stats->tx_waste_time);
190 	dcs_debug("tgt_curr/dcs_rx_time: %u", curr_stats->rx_time);
191 	dcs_debug("tgt_curr/listen_time: %u",
192 		  curr_stats->mib_stats.listen_time);
193 	dcs_debug("tgt_curr/tx_frame_cnt: %u",
194 		  curr_stats->mib_stats.reg_tx_frame_cnt);
195 	dcs_debug("tgt_curr/rx_frame_cnt: %u",
196 		  curr_stats->mib_stats.reg_rx_frame_cnt);
197 	dcs_debug("tgt_curr/rxclr_cnt: %u",
198 		  curr_stats->mib_stats.reg_rxclr_cnt);
199 	dcs_debug("tgt_curr/reg_cycle_cnt: %u",
200 		  curr_stats->mib_stats.reg_cycle_cnt);
201 	dcs_debug("tgt_curr/rxclr_ext_cnt: %u",
202 		  curr_stats->mib_stats.reg_rxclr_ext_cnt);
203 	dcs_debug("tgt_curr/ofdm_phyerr_cnt: %u",
204 		  curr_stats->mib_stats.reg_ofdm_phyerr_cnt);
205 	dcs_debug("tgt_curr/cck_phyerr_cnt: %u",
206 		  curr_stats->mib_stats.reg_cck_phyerr_cnt);
207 
208 	dcs_debug("tgt_prev/tsf: %u", prev_stats->reg_tsf32);
209 	dcs_debug("tgt_prev/last_ack_rssi: %u", prev_stats->last_ack_rssi);
210 	dcs_debug("tgt_prev/tx_waste_time: %u", prev_stats->tx_waste_time);
211 	dcs_debug("tgt_prev/rx_time: %u", prev_stats->rx_time);
212 	dcs_debug("tgt_prev/listen_time: %u",
213 		  prev_stats->mib_stats.listen_time);
214 	dcs_debug("tgt_prev/tx_frame_cnt: %u",
215 		  prev_stats->mib_stats.reg_tx_frame_cnt);
216 	dcs_debug("tgt_prev/rx_frame_cnt: %u",
217 		  prev_stats->mib_stats.reg_rx_frame_cnt);
218 	dcs_debug("tgt_prev/rxclr_cnt: %u",
219 		  prev_stats->mib_stats.reg_rxclr_cnt);
220 	dcs_debug("tgt_prev/reg_cycle_cnt: %u",
221 		  prev_stats->mib_stats.reg_cycle_cnt);
222 	dcs_debug("tgt_prev/rxclr_ext_cnt: %u",
223 		  prev_stats->mib_stats.reg_rxclr_ext_cnt);
224 	dcs_debug("tgt_prev/ofdm_phyerr_cnt: %u",
225 		  prev_stats->mib_stats.reg_ofdm_phyerr_cnt);
226 	dcs_debug("tgt_prev/cck_phyerr_cnt: %u",
227 		  prev_stats->mib_stats.reg_cck_phyerr_cnt);
228 }
229 
230 /**
231  * wlan_dcs_update_chan_util() - update chan utilization of dcs stats
232  * @p_dcs_im_stats: pointer to pdev_dcs_im_stats
233  * @rx_cu: rx channel utilization
234  * @tx_cu: tx channel utilization
235  * @obss_rx_cu: obss rx channel utilization
236  * @total_cu: total channel utilization
237  * @chan_nf: Channel noise floor (units are in dBm)
238  *
239  * Return: Void
240  */
241 static void wlan_dcs_update_chan_util(struct pdev_dcs_im_stats *p_dcs_im_stats,
242 				      uint32_t rx_cu, uint32_t tx_cu,
243 				      uint32_t obss_rx_cu,
244 				      uint32_t total_cu, uint32_t chan_nf)
245 {
246 	if (p_dcs_im_stats) {
247 		p_dcs_im_stats->dcs_ch_util_im_stats.rx_cu = rx_cu;
248 		p_dcs_im_stats->dcs_ch_util_im_stats.tx_cu = tx_cu;
249 		p_dcs_im_stats->dcs_ch_util_im_stats.obss_rx_cu = obss_rx_cu;
250 		p_dcs_im_stats->dcs_ch_util_im_stats.total_cu = total_cu;
251 		p_dcs_im_stats->dcs_ch_util_im_stats.chan_nf = chan_nf;
252 	}
253 }
254 
255 /**
256  * wlan_dcs_wlan_interference_process() - dcs detection algorithm handling
257  * @curr_stats: current target im stats pointer
258  * @dcs_pdev_priv: dcs pdev priv pointer
259  *
260  * Return: true or false means start dcs callback handler or not
261  */
262 static bool
263 wlan_dcs_wlan_interference_process(
264 				struct wlan_host_dcs_im_tgt_stats *curr_stats,
265 				struct dcs_pdev_priv_obj *dcs_pdev_priv)
266 {
267 	struct wlan_host_dcs_im_tgt_stats *prev_stats;
268 	struct pdev_dcs_params dcs_host_params;
269 	struct pdev_dcs_im_stats *p_dcs_im_stats;
270 	bool start_dcs_cbk_handler = false;
271 
272 	uint32_t reg_tsf_delta = 0;
273 	uint32_t scaled_reg_tsf_delta;
274 	uint32_t rxclr_delta = 0;
275 	uint32_t rxclr_ext_delta = 0;
276 	uint32_t cycle_count_delta = 0;
277 	uint32_t scaled_cycle_count_delta;
278 	uint32_t tx_frame_delta = 0;
279 	uint32_t rx_frame_delta = 0;
280 	uint32_t my_bss_rx_delta = 0;
281 	uint32_t reg_total_cu = 0;
282 	uint32_t reg_tx_cu = 0;
283 	uint32_t reg_rx_cu = 0;
284 	uint32_t obss_rx_cu = 0;
285 	uint32_t reg_unused_cu = 0;
286 	uint32_t rx_time_cu = 0;
287 	uint32_t reg_ofdm_phyerr_delta = 0;
288 	uint32_t reg_cck_phyerr_delta = 0;
289 	uint32_t reg_ofdm_phyerr_cu = 0;
290 	uint32_t ofdm_phy_err_rate = 0;
291 	uint32_t cck_phy_err_rate = 0;
292 	uint32_t max_phy_err_rate = 0;
293 	uint32_t max_phy_err_count = 0;
294 	uint32_t total_wasted_cu = 0;
295 	uint32_t wasted_tx_cu = 0;
296 	uint32_t tx_err = 0;
297 	uint32_t too_many_phy_errors = 0;
298 
299 	if (!curr_stats) {
300 		dcs_err("curr_stats is NULL");
301 		goto end;
302 	}
303 
304 	if (!dcs_pdev_priv) {
305 		dcs_err("dcs pdev private object is NULL");
306 		goto end;
307 	}
308 
309 	dcs_host_params = dcs_pdev_priv->dcs_host_params;
310 	p_dcs_im_stats = &dcs_pdev_priv->dcs_im_stats;
311 	prev_stats =  &dcs_pdev_priv->dcs_im_stats.prev_dcs_im_stats;
312 
313 	if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE))
314 		wlan_dcs_im_print_stats(prev_stats, curr_stats);
315 
316 	/*
317 	 * Counters would have wrapped. Ideally we should be able to figure this
318 	 * out, but we never know how many times counters wrapped, just ignore.
319 	 */
320 	if ((curr_stats->mib_stats.listen_time <= 0) ||
321 	    (curr_stats->reg_tsf32 <= prev_stats->reg_tsf32)) {
322 		if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE))
323 			dcs_debug("ignoring due to negative TSF value");
324 		goto copy_stats;
325 	}
326 
327 	reg_tsf_delta = curr_stats->reg_tsf32 - prev_stats->reg_tsf32;
328 
329 	/*
330 	 * Do nothing if current stats are not seeming good, probably
331 	 * a reset happened on chip, force cleared
332 	 */
333 	if (prev_stats->mib_stats.reg_rxclr_cnt >
334 		curr_stats->mib_stats.reg_rxclr_cnt) {
335 		if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE))
336 			dcs_debug("ignoring due to negative rxclr count");
337 		goto copy_stats;
338 	}
339 
340 	rxclr_delta = curr_stats->mib_stats.reg_rxclr_cnt -
341 			prev_stats->mib_stats.reg_rxclr_cnt;
342 	rxclr_ext_delta = curr_stats->mib_stats.reg_rxclr_ext_cnt -
343 				prev_stats->mib_stats.reg_rxclr_ext_cnt;
344 	tx_frame_delta = curr_stats->mib_stats.reg_tx_frame_cnt -
345 				prev_stats->mib_stats.reg_tx_frame_cnt;
346 
347 	rx_frame_delta = curr_stats->mib_stats.reg_rx_frame_cnt -
348 				prev_stats->mib_stats.reg_rx_frame_cnt;
349 
350 	cycle_count_delta = curr_stats->mib_stats.reg_cycle_cnt -
351 				prev_stats->mib_stats.reg_cycle_cnt;
352 
353 	my_bss_rx_delta = curr_stats->my_bss_rx_cycle_count -
354 				prev_stats->my_bss_rx_cycle_count;
355 
356 	if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE))
357 		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",
358 			  rxclr_delta, rxclr_ext_delta, tx_frame_delta,
359 			  rx_frame_delta, cycle_count_delta, my_bss_rx_delta);
360 
361 	/* Update user stats */
362 	wlan_dcs_pdev_obj_lock(dcs_pdev_priv);
363 	if (dcs_pdev_priv->dcs_host_params.user_request_count) {
364 		struct wlan_host_dcs_im_user_stats *p_user_stats =
365 					     &p_dcs_im_stats->user_dcs_im_stats;
366 
367 		p_user_stats->cycle_count += cycle_count_delta;
368 		p_user_stats->rxclr_count += rxclr_delta;
369 		p_user_stats->rx_frame_count += rx_frame_delta;
370 		p_user_stats->my_bss_rx_cycle_count += my_bss_rx_delta;
371 		if (0 == p_user_stats->max_rssi &&
372 		    0 == p_user_stats->min_rssi) {
373 			p_user_stats->max_rssi = curr_stats->last_ack_rssi;
374 			p_user_stats->min_rssi = curr_stats->last_ack_rssi;
375 		} else {
376 			if (curr_stats->last_ack_rssi > p_user_stats->max_rssi)
377 				p_user_stats->max_rssi =
378 						      curr_stats->last_ack_rssi;
379 			if (curr_stats->last_ack_rssi < p_user_stats->min_rssi)
380 				p_user_stats->min_rssi =
381 						      curr_stats->last_ack_rssi;
382 		}
383 		dcs_pdev_priv->dcs_host_params.user_request_count--;
384 		if (0 == dcs_pdev_priv->dcs_host_params.user_request_count)
385 			dcs_pdev_priv->dcs_host_params.notify_user = 1;
386 	}
387 	wlan_dcs_pdev_obj_unlock(dcs_pdev_priv);
388 
389 	/*
390 	 * Total channel utiliztaion is the amount of time RXCLR is
391 	 * counted. RXCLR is counted, when 'RX is NOT clear', please
392 	 * refer to mac documentation. It means either TX or RX is ON
393 	 *
394 	 * Why shift by 8 ? after multiplication it could overflow. At one
395 	 * second rate, normally neither cycle_count_delta nor the tsf_delta
396 	 * would be zero after shift by 8 bits. In corner case, host resets
397 	 * dcs stats, and at the same time tsf counters is wrapped.
398 	 * Then all the variable in prev_stats are 0, and the variable in
399 	 * curr_stats may be a small value, so add check for cycle_count_delta
400 	 * and the tsf_delta after shift by 8 bits.
401 	 */
402 	scaled_cycle_count_delta = cycle_count_delta >> 8;
403 	scaled_reg_tsf_delta = reg_tsf_delta >> 8;
404 	if (!scaled_cycle_count_delta || !scaled_reg_tsf_delta) {
405 		if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE))
406 			dcs_debug("cycle count or TSF NULL --Investigate--");
407 		goto copy_stats;
408 	}
409 	reg_total_cu = ((rxclr_delta >> 8) * 100) / scaled_cycle_count_delta;
410 	reg_tx_cu = ((tx_frame_delta >> 8) * 100) / scaled_cycle_count_delta;
411 	reg_rx_cu = ((rx_frame_delta >> 8) * 100) / scaled_cycle_count_delta;
412 	rx_time_cu = ((curr_stats->rx_time >> 8) * 100) / scaled_reg_tsf_delta;
413 	obss_rx_cu = (((rx_frame_delta - my_bss_rx_delta) >> 8) * 100) /
414 		     scaled_cycle_count_delta;
415 	wlan_dcs_update_chan_util(p_dcs_im_stats, reg_rx_cu, reg_tx_cu,
416 				  obss_rx_cu, reg_total_cu,
417 				  curr_stats->chan_nf);
418 
419 	/*
420 	 * Amount of the time AP received cannot go higher than the receive
421 	 * cycle count delta. If at all it is, there should have been a
422 	 * computation error, ceil it to receive_cycle_count_diff
423 	 */
424 	if (rx_time_cu > reg_rx_cu)
425 		rx_time_cu = reg_rx_cu;
426 
427 	if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE))
428 		dcs_debug("reg_total_cu: %u, reg_tx_cu: %u, reg_rx_cu: %u, rx_time_cu: %u, obss_rx_cu: %u dcs_algorithm: %d",
429 			  reg_total_cu, reg_tx_cu, reg_rx_cu,
430 			  rx_time_cu, obss_rx_cu,
431 			  dcs_host_params.dcs_algorithm_process);
432 
433 	/*
434 	 * For below scenario, will ignore dcs event data and won't do
435 	 * interference detection algorithm calculation:
436 	 * 1: Current SAP channel isn't on 5G band
437 	 * 2: In the process of ACS
438 	 * 3: In the process of dcs disabling dcs_restart_delay time duration
439 	 */
440 	if (!dcs_host_params.dcs_algorithm_process)
441 		goto copy_stats;
442 
443 	/*
444 	 * Unusable channel utilization is amount of time that we
445 	 * spent in backoff or waiting for other transmit/receive to
446 	 * complete. If there is interference it is more likely that
447 	 * we overshoot the limit. In case of multiple stations, we
448 	 * still see increased channel utilization.  This assumption may
449 	 * not be true for the VOW scenario where either multicast or
450 	 * unicast-UDP is used ( mixed traffic would still cause high
451 	 * channel utilization).
452 	 */
453 	wasted_tx_cu = ((curr_stats->tx_waste_time >> 8) * 100) /
454 							scaled_reg_tsf_delta;
455 
456 	/*
457 	 * Transmit channel utilization cannot go higher than the amount of time
458 	 * wasted, if so cap the wastage to transmit channel utillzation. This
459 	 * could happen to compution error.
460 	 */
461 	if (reg_tx_cu < wasted_tx_cu)
462 		wasted_tx_cu = reg_tx_cu;
463 
464 	tx_err = (reg_tx_cu && wasted_tx_cu) ?
465 			(wasted_tx_cu * 100) / reg_tx_cu : 0;
466 
467 	/*
468 	 * The below actually gives amount of time we are not using, or the
469 	 * interferer is active.
470 	 * rx_time_cu is what computed receive time *NOT* rx_cycle_count
471 	 * rx_cycle_count is our receive+interferer's transmit
472 	 * un-used is really total_cycle_counts -
473 	 *      (our_rx_time(rx_time_cu) + our_receive_time)
474 	 */
475 	reg_unused_cu = (reg_total_cu >= (reg_tx_cu + rx_time_cu)) ?
476 				(reg_total_cu - (reg_tx_cu + rx_time_cu)) : 0;
477 
478 	/* If any retransmissions are there, count them as wastage */
479 	total_wasted_cu = reg_unused_cu + wasted_tx_cu;
480 
481 	/* Check ofdm and cck errors */
482 	if (unlikely(curr_stats->mib_stats.reg_ofdm_phyerr_cnt <
483 			prev_stats->mib_stats.reg_ofdm_phyerr_cnt))
484 		reg_ofdm_phyerr_delta =
485 			curr_stats->mib_stats.reg_ofdm_phyerr_cnt;
486 	else
487 		reg_ofdm_phyerr_delta =
488 			curr_stats->mib_stats.reg_ofdm_phyerr_cnt -
489 				prev_stats->mib_stats.reg_ofdm_phyerr_cnt;
490 
491 	if (unlikely(curr_stats->mib_stats.reg_cck_phyerr_cnt <
492 			prev_stats->mib_stats.reg_cck_phyerr_cnt))
493 		reg_cck_phyerr_delta = curr_stats->mib_stats.reg_cck_phyerr_cnt;
494 	else
495 		reg_cck_phyerr_delta =
496 			curr_stats->mib_stats.reg_cck_phyerr_cnt -
497 				prev_stats->mib_stats.reg_cck_phyerr_cnt;
498 
499 	/*
500 	 * Add the influence of ofdm phy errors to the wasted channel
501 	 * utillization, this computed through time wasted in errors
502 	 */
503 	reg_ofdm_phyerr_cu = reg_ofdm_phyerr_delta *
504 				dcs_host_params.phy_err_penalty;
505 	total_wasted_cu +=
506 		(reg_ofdm_phyerr_cu > 0) ?
507 		(((reg_ofdm_phyerr_cu >> 8) * 100) / scaled_reg_tsf_delta) : 0;
508 
509 	ofdm_phy_err_rate = (curr_stats->mib_stats.reg_ofdm_phyerr_cnt * 1000) /
510 				curr_stats->mib_stats.listen_time;
511 	cck_phy_err_rate = (curr_stats->mib_stats.reg_cck_phyerr_cnt * 1000) /
512 				curr_stats->mib_stats.listen_time;
513 
514 	if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) {
515 		dcs_debug("reg_unused_cu: %u, reg_ofdm_phyerr_delta: %u, reg_cck_phyerr_delta: %u, reg_ofdm_phyerr_cu: %u",
516 			  reg_unused_cu, reg_ofdm_phyerr_delta,
517 			  reg_cck_phyerr_delta, reg_ofdm_phyerr_cu);
518 		dcs_debug("total_wasted_cu: %u, ofdm_phy_err_rate: %u, cck_phy_err_rate: %u",
519 			  total_wasted_cu, ofdm_phy_err_rate, cck_phy_err_rate);
520 		dcs_debug("new_unused_cu: %u, reg_ofdm_phy_error_cu: %u",
521 			  reg_unused_cu,
522 			 (curr_stats->mib_stats.reg_ofdm_phyerr_cnt * 100) /
523 					curr_stats->mib_stats.listen_time);
524 	}
525 
526 	/* Check if the error rates are higher than the thresholds */
527 	max_phy_err_rate = QDF_MAX(ofdm_phy_err_rate, cck_phy_err_rate);
528 
529 	max_phy_err_count = QDF_MAX(curr_stats->mib_stats.reg_ofdm_phyerr_cnt,
530 				    curr_stats->mib_stats.reg_cck_phyerr_cnt);
531 
532 	if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE))
533 		dcs_debug("max_phy_err_rate: %u, max_phy_err_count: %u",
534 			  max_phy_err_rate, max_phy_err_count);
535 
536 	if (((max_phy_err_rate >= dcs_host_params.phy_err_threshold) &&
537 	     (max_phy_err_count > dcs_host_params.phy_err_threshold)) ||
538 		(curr_stats->phyerr_cnt > dcs_host_params.radar_err_threshold))
539 		too_many_phy_errors = 1;
540 
541 	if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_CRITICAL)) {
542 		dcs_debug("total_cu: %u, tx_cu: %u, rx_cu: %u, rx_time_cu: %u, unused cu: %u",
543 			  reg_total_cu, reg_tx_cu,
544 			  reg_rx_cu, rx_time_cu, reg_unused_cu);
545 		dcs_debug("phyerr: %u, total_wasted_cu: %u, phyerror_cu: %u, wasted_cu: %u, reg_tx_cu: %u, reg_rx_cu: %u",
546 			  too_many_phy_errors, total_wasted_cu,
547 			  reg_ofdm_phyerr_cu, wasted_tx_cu,
548 			  reg_tx_cu, reg_rx_cu);
549 		dcs_debug("tx_err: %u", tx_err);
550 	}
551 
552 	if (reg_unused_cu >= dcs_host_params.coch_intfr_threshold)
553 		/* Quickly reach to decision */
554 		p_dcs_im_stats->im_intfr_cnt += 2;
555 	else if (too_many_phy_errors &&
556 		 (((total_wasted_cu >
557 			(dcs_host_params.coch_intfr_threshold + 10)) &&
558 		((reg_tx_cu + reg_rx_cu) > dcs_host_params.user_max_cu)) ||
559 		((reg_tx_cu > DCS_TX_MAX_CU) &&
560 			(tx_err >= dcs_host_params.tx_err_threshold))))
561 		p_dcs_im_stats->im_intfr_cnt++;
562 
563 	if (p_dcs_im_stats->im_intfr_cnt >=
564 		dcs_host_params.intfr_detection_threshold) {
565 		if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_CRITICAL)) {
566 			dcs_debug("interference threshold exceeded");
567 			dcs_debug("unused_cu: %u, too_any_phy_errors: %u, total_wasted_cu: %u, reg_tx_cu: %u, reg_rx_cu: %u",
568 				  reg_unused_cu, too_many_phy_errors,
569 				  total_wasted_cu, reg_tx_cu, reg_rx_cu);
570 		}
571 
572 		p_dcs_im_stats->im_intfr_cnt = 0;
573 		p_dcs_im_stats->im_samp_cnt = 0;
574 		/*
575 		 * Once the interference is detected, change the channel, as on
576 		 * today this is common routine for wirelesslan and
577 		 * non-wirelesslan interference. Name as such kept the same
578 		 * because of the DA code, which is using the same function.
579 		 */
580 		start_dcs_cbk_handler = true;
581 	} else if (0 == p_dcs_im_stats->im_intfr_cnt ||
582 			p_dcs_im_stats->im_samp_cnt >=
583 				dcs_host_params.intfr_detection_window) {
584 		p_dcs_im_stats->im_intfr_cnt = 0;
585 		p_dcs_im_stats->im_samp_cnt = 0;
586 	}
587 
588 	/* Count the current run too */
589 	p_dcs_im_stats->im_samp_cnt++;
590 
591 	if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE))
592 		dcs_debug("intfr_count: %u, sample_count: %u",
593 			  p_dcs_im_stats->im_intfr_cnt,
594 			  p_dcs_im_stats->im_samp_cnt);
595 copy_stats:
596 	 /* Copy the stats for next cycle */
597 	wlan_dcs_im_copy_stats(prev_stats, curr_stats);
598 end:
599 	return start_dcs_cbk_handler;
600 }
601 
602 void wlan_dcs_disable_timer_fn(void *dcs_timer_args)
603 {
604 	struct pdev_dcs_timer_args *dcs_timer_args_ctx;
605 	struct wlan_objmgr_psoc *psoc;
606 	uint32_t pdev_id;
607 	struct dcs_psoc_priv_obj *dcs_psoc_priv;
608 	struct dcs_pdev_priv_obj *dcs_pdev_priv;
609 
610 	if (!dcs_timer_args) {
611 		dcs_err("dcs timer args is null");
612 		return;
613 	}
614 
615 	dcs_timer_args_ctx = (struct pdev_dcs_timer_args *)dcs_timer_args;
616 	psoc = dcs_timer_args_ctx->psoc;
617 	pdev_id = dcs_timer_args_ctx->pdev_id;
618 
619 	dcs_psoc_priv =
620 		wlan_objmgr_psoc_get_comp_private_obj(psoc, WLAN_UMAC_COMP_DCS);
621 	if (!dcs_psoc_priv) {
622 		dcs_err("dcs psoc private object is null");
623 		return;
624 	}
625 
626 	dcs_pdev_priv = &dcs_psoc_priv->dcs_pdev_priv[pdev_id];
627 	dcs_pdev_priv->dcs_freq_ctrl_params.disable_delay_process = false;
628 
629 	dcs_info("dcs disable timeout, enable dcs detection again");
630 	wlan_dcs_set_algorithm_process(psoc, pdev_id, true);
631 }
632 
633 /**
634  * wlan_dcs_frequency_control() - dcs frequency control handling
635  * @psoc: psoc pointer
636  * @dcs_pdev_priv: dcs pdev priv pointer
637  * @event: dcs stats event pointer
638  *
639  * Return: none
640  */
641 static void wlan_dcs_frequency_control(struct wlan_objmgr_psoc *psoc,
642 				       struct dcs_pdev_priv_obj *dcs_pdev_priv,
643 				       struct wlan_host_dcs_event *event)
644 {
645 	struct dcs_psoc_priv_obj *dcs_psoc_priv;
646 	struct pdev_dcs_freq_ctrl_params *dcs_freq_ctrl_params;
647 	uint8_t timestamp_pos;
648 	unsigned long current_time;
649 	uint8_t delta_pos;
650 	unsigned long delta_time;
651 	bool disable_dcs_sometime = false;
652 
653 	if (!psoc || !dcs_pdev_priv || !event) {
654 		dcs_err("psoc or dcs_pdev_priv or event is null");
655 		return;
656 	}
657 
658 	dcs_freq_ctrl_params = &dcs_pdev_priv->dcs_freq_ctrl_params;
659 	if (dcs_freq_ctrl_params->disable_delay_process) {
660 		dcs_err("In the process of dcs disable, shouldn't go to here");
661 		return;
662 	}
663 
664 	current_time = qdf_get_system_timestamp();
665 	if (dcs_freq_ctrl_params->dcs_happened_count >=
666 		dcs_freq_ctrl_params->disable_threshold_per_5mins) {
667 		delta_pos =
668 			dcs_freq_ctrl_params->dcs_happened_count -
669 			dcs_freq_ctrl_params->disable_threshold_per_5mins;
670 		delta_pos = delta_pos % MAX_DCS_TIME_RECORD;
671 
672 		delta_time = current_time -
673 				dcs_freq_ctrl_params->timestamp[delta_pos];
674 		if (delta_time < DCS_FREQ_CONTROL_TIME)
675 			disable_dcs_sometime = true;
676 	}
677 
678 	if (!disable_dcs_sometime) {
679 		timestamp_pos = dcs_freq_ctrl_params->dcs_happened_count %
680 							MAX_DCS_TIME_RECORD;
681 		dcs_freq_ctrl_params->timestamp[timestamp_pos] = current_time;
682 		dcs_freq_ctrl_params->dcs_happened_count++;
683 	}
684 
685 	/*
686 	 * Before start dcs callback handler or disable dcs for some time,
687 	 * need to ignore dcs event data and won't do interference detection
688 	 * algorithm calculation for disabling dcs detection firstly.
689 	 */
690 	wlan_dcs_set_algorithm_process(psoc, event->dcs_param.pdev_id, false);
691 
692 	if (disable_dcs_sometime) {
693 		dcs_freq_ctrl_params->disable_delay_process = true;
694 		dcs_pdev_priv->dcs_timer_args.psoc = psoc;
695 		dcs_pdev_priv->dcs_timer_args.pdev_id =
696 						event->dcs_param.pdev_id;
697 		qdf_timer_start(&dcs_pdev_priv->dcs_disable_timer,
698 				dcs_pdev_priv->dcs_freq_ctrl_params.
699 				restart_delay * 60 * 1000);
700 		dcs_info("start dcs disable timer");
701 	} else {
702 		dcs_psoc_priv = wlan_objmgr_psoc_get_comp_private_obj(
703 							psoc,
704 							WLAN_UMAC_COMP_DCS);
705 		if (!dcs_psoc_priv) {
706 			dcs_err("dcs private psoc object is null");
707 			return;
708 		}
709 
710 		dcs_info("start dcs callback handler");
711 		dcs_psoc_priv->dcs_cbk.cbk(psoc, event->dcs_param.pdev_id,
712 					   event->dcs_param.interference_type,
713 					   dcs_psoc_priv->dcs_cbk.arg);
714 	}
715 }
716 
717 /**
718  * wlan_dcs_switch_chan() - switch channel for vdev
719  * @vdev: vdev ptr
720  * @tgt_freq: target frequency
721  * @tgt_width: target channel width
722  *
723  * Return: QDF_STATUS
724  */
725 static QDF_STATUS
726 wlan_dcs_switch_chan(struct wlan_objmgr_vdev *vdev, qdf_freq_t tgt_freq,
727 		     enum phy_ch_width tgt_width)
728 {
729 	struct wlan_objmgr_psoc *psoc;
730 	struct dcs_psoc_priv_obj *dcs_psoc_priv;
731 	dcs_switch_chan_cb switch_chan_cb;
732 
733 	psoc = wlan_vdev_get_psoc(vdev);
734 	if (!psoc)
735 		return QDF_STATUS_E_INVAL;
736 
737 	dcs_psoc_priv = wlan_objmgr_psoc_get_comp_private_obj(psoc,
738 					WLAN_UMAC_COMP_DCS);
739 	if (!dcs_psoc_priv)
740 		return QDF_STATUS_E_INVAL;
741 
742 	switch_chan_cb = dcs_psoc_priv->switch_chan_cb;
743 	if (!switch_chan_cb)
744 		return QDF_STATUS_E_NOSUPPORT;
745 
746 	return switch_chan_cb(vdev, tgt_freq, tgt_width);
747 }
748 
749 #ifdef WLAN_POLICY_MGR_ENABLE
750 /**
751  * wlan_dcs_get_pcl_for_sap() - get preferred channel list for SAP
752  * @vdev: vdev ptr
753  * @freq_list: Pointer to PCL
754  * @freq_list_sz: Max size of PCL
755  *
756  * Return: number of channels in PCL
757  */
758 static uint32_t wlan_dcs_get_pcl_for_sap(struct wlan_objmgr_vdev *vdev,
759 					 qdf_freq_t *freq_list,
760 					 uint32_t freq_list_sz)
761 {
762 	struct wlan_objmgr_psoc *psoc;
763 	struct wlan_objmgr_pdev *pdev;
764 	struct policy_mgr_pcl_list *pcl;
765 	qdf_freq_t freq;
766 	enum channel_state state;
767 	QDF_STATUS status;
768 	int i, j;
769 
770 	psoc = wlan_vdev_get_psoc(vdev);
771 	if (!psoc)
772 		return 0;
773 
774 	pdev = wlan_vdev_get_pdev(vdev);
775 	if (!pdev)
776 		return 0;
777 
778 	pcl = qdf_mem_malloc(sizeof(*pcl));
779 	if (!pcl)
780 		return 0;
781 
782 	status = policy_mgr_get_pcl_for_vdev_id(psoc,
783 						PM_SAP_MODE,
784 						pcl->pcl_list, &pcl->pcl_len,
785 						pcl->weight_list,
786 						QDF_ARRAY_SIZE(pcl->weight_list),
787 						wlan_vdev_get_id(vdev));
788 	if (QDF_IS_STATUS_ERROR(status) || !pcl->pcl_len) {
789 		qdf_mem_free(pcl);
790 		return 0;
791 	}
792 
793 	for (i = 0, j = 0; i < pcl->pcl_len && i < freq_list_sz; i++) {
794 		freq = (qdf_freq_t)pcl->pcl_list[i];
795 		state = wlan_reg_get_channel_state_for_pwrmode(
796 							pdev,
797 							freq,
798 							REG_CURRENT_PWR_MODE);
799 		if (state != CHANNEL_STATE_ENABLE)
800 			continue;
801 
802 		freq_list[j++] = freq;
803 	}
804 
805 	qdf_mem_free(pcl);
806 	return j;
807 }
808 #else
809 static uint32_t wlan_dcs_get_pcl_for_sap(struct wlan_objmgr_vdev *vdev,
810 					 qdf_freq_t *freq_list,
811 					 uint32_t freq_list_sz)
812 {
813 	struct wlan_objmgr_pdev *pdev;
814 	struct regulatory_channel *cur_chan_list;
815 	qdf_freq_t freq;
816 	enum channel_state state;
817 	int i, j;
818 
819 	pdev = wlan_vdev_get_pdev(vdev);
820 	if (!pdev)
821 		return 0;
822 
823 	cur_chan_list = qdf_mem_malloc(NUM_CHANNELS *
824 			sizeof(struct regulatory_channel));
825 	if (!cur_chan_list)
826 		return 0;
827 
828 	if (wlan_reg_get_current_chan_list(pdev, cur_chan_list) !=
829 					   QDF_STATUS_SUCCESS) {
830 		qdf_mem_free(cur_chan_list);
831 		return 0;
832 	}
833 
834 	for (i = 0, j = 0; i < NUM_CHANNELS && i < freq_list_sz; i++) {
835 		freq = cur_chan_list[i].center_freq;
836 		state = wlan_reg_get_channel_state_for_pwrmode(
837 						       pdev,
838 						       freq,
839 						       REG_CURRENT_PWR_MODE);
840 		if (state != CHANNEL_STATE_ENABLE)
841 			continue;
842 
843 		freq_list[j++] = freq;
844 	}
845 
846 	qdf_mem_free(cur_chan_list);
847 	return j;
848 }
849 #endif
850 
851 /**
852  * wlan_dcs_awgn_get_intf_for_seg() - get interference for specified segment
853  * @awgn_info: awgn info pointer
854  * @segment: segment index in channel band
855  *
856  * This function extracts the information from awgn event and check interference
857  * within the specified segment.
858  *
859  * Return: true if interference is found within the segment, false otherwise.
860  */
861 static bool
862 wlan_dcs_awgn_get_intf_for_seg(struct wlan_host_dcs_awgn_info *awgn_info,
863 			       uint32_t segment)
864 {
865 	uint32_t seg_mask;
866 
867 	switch (segment) {
868 	case WLAN_DCS_SEG_PRI20:
869 		seg_mask = WLAN_DCS_SEG_PRI20_MASK;
870 		break;
871 	case WLAN_DCS_SEG_SEC20:
872 		seg_mask = WLAN_DCS_SEG_SEC20_MASK;
873 		break;
874 	case WLAN_DCS_SEG_SEC40:
875 		seg_mask = WLAN_DCS_SEG_SEC40_MASK;
876 		break;
877 	case WLAN_DCS_SEG_SEC80:
878 		seg_mask = WLAN_DCS_SEG_SEC80_MASK;
879 		break;
880 	case WLAN_DCS_SEG_SEC160:
881 		seg_mask = WLAN_DCS_SEG_SEC160_MASK;
882 		break;
883 	default:
884 		seg_mask = 0xFFFFFFFF;
885 		break;
886 	}
887 
888 	return (awgn_info->chan_bw_intf_bitmap & seg_mask);
889 }
890 
891 /**
892  * wlan_dcs_get_max_seg_idx() - get max segment index for channel width
893  * @width: channel width
894  *
895  * Return: max segment index(enum wlan_dcs_chan_seg) for the channel width.
896  */
897 static enum wlan_dcs_chan_seg wlan_dcs_get_max_seg_idx(enum phy_ch_width width)
898 {
899 	switch (width) {
900 	case CH_WIDTH_160MHZ:
901 	case CH_WIDTH_80P80MHZ:
902 		return WLAN_DCS_SEG_SEC80;
903 	case CH_WIDTH_80MHZ:
904 		return WLAN_DCS_SEG_SEC40;
905 	case CH_WIDTH_40MHZ:
906 		return WLAN_DCS_SEG_SEC20;
907 	case CH_WIDTH_20MHZ:
908 		return WLAN_DCS_SEG_PRI20;
909 	default:
910 		dcs_err("Invalid ch width %d", width);
911 		return WLAN_DCS_SEG_INVALID;
912 	}
913 }
914 
915 /**
916  * wlan_dcs_get_chan_width_for_seg() - get channel width for specified segment
917  * @seg_idx: segment index
918  *
919  * Return: channel width for segment index
920  */
921 static enum phy_ch_width
922 wlan_dcs_get_chan_width_for_seg(enum wlan_dcs_chan_seg seg_idx)
923 {
924 	switch (seg_idx) {
925 	case WLAN_DCS_SEG_SEC80:
926 		return CH_WIDTH_160MHZ;
927 	case WLAN_DCS_SEG_SEC40:
928 		return CH_WIDTH_80MHZ;
929 	case WLAN_DCS_SEG_SEC20:
930 		return CH_WIDTH_40MHZ;
931 	case WLAN_DCS_SEG_PRI20:
932 		return CH_WIDTH_20MHZ;
933 	default:
934 		dcs_err("Invalid seg idx %d", seg_idx);
935 		return CH_WIDTH_INVALID;
936 	}
937 }
938 
939 /**
940  * wlan_dcs_get_max_no_intf_bw() - get max no interference band width
941  * @awgn_info: pointer to awgn info
942  * @width: pointer to channel width
943  *
944  * This function tries to get max no interference band width according to
945  * awgn event.
946  *
947  * Return: true if valid no interference band width is found, false otherwise.
948  */
949 static bool
950 wlan_dcs_get_max_no_intf_bw(struct wlan_host_dcs_awgn_info *awgn_info,
951 			    enum phy_ch_width *width)
952 {
953 	enum wlan_dcs_chan_seg seg_idx, max_seg_idx;
954 
955 	max_seg_idx = wlan_dcs_get_max_seg_idx(awgn_info->channel_width);
956 	if (max_seg_idx == WLAN_DCS_SEG_INVALID)
957 		return false;
958 
959 	seg_idx = WLAN_DCS_SEG_PRI20;
960 	while (seg_idx <= max_seg_idx) {
961 		if (wlan_dcs_awgn_get_intf_for_seg(awgn_info, seg_idx)) {
962 			dcs_debug("Intf found for seg idx %d", seg_idx);
963 			break;
964 		}
965 		seg_idx++;
966 	}
967 
968 	/* scroll back to the last no-intf idx */
969 	seg_idx--;
970 
971 	if (seg_idx == WLAN_DCS_SEG_INVALID) {
972 		/* If pri20 contains interference, do full channel change */
973 		dcs_debug("Primary 20MHz Channel interference detected");
974 		return false;
975 	}
976 
977 	*width = wlan_dcs_get_chan_width_for_seg(seg_idx);
978 	if (*width == CH_WIDTH_160MHZ &&
979 	    awgn_info->channel_width == CH_WIDTH_80P80MHZ)
980 		*width = CH_WIDTH_80P80MHZ;
981 
982 	dcs_debug("Found the max no intf width %d", *width);
983 	return (*width != CH_WIDTH_INVALID);
984 }
985 
986 /**
987  * wlan_dcs_get_available_chan_for_bw() - get available channel for specified
988  *  band width
989  * @pdev: pdev ptr
990  * @awgn_info: pointer to awgn info
991  * @bw: channel width
992  * @freq_list: List of preferred channels
993  * @freq_num: Number of channels in the PCL
994  * @random: request for random channel
995  *
996  * Return: the selected channel frequency, 0 if no available chan is found.
997  */
998 static qdf_freq_t
999 wlan_dcs_get_available_chan_for_bw(struct wlan_objmgr_pdev *pdev,
1000 				   struct wlan_host_dcs_awgn_info *awgn_info,
1001 				   enum phy_ch_width bw, qdf_freq_t *freq_list,
1002 				   uint32_t freq_num, bool random)
1003 {
1004 	int i, j = 0;
1005 	uint32_t random_chan_idx;
1006 	qdf_freq_t freq, selected_freq = 0;
1007 	const struct bonded_channel_freq *bonded_chan_ptr = NULL;
1008 	enum channel_state state;
1009 	uint16_t chan_cfreq;
1010 	bool is_safe = true;
1011 
1012 	if (!freq_list || !freq_num)
1013 		return selected_freq;
1014 
1015 	for (i = 0; i < freq_num; i++) {
1016 		if (j && !random) {
1017 			selected_freq = freq_list[0];
1018 			dcs_debug("get the first available freq %u for bw %u",
1019 				  selected_freq, bw);
1020 			break;
1021 		}
1022 
1023 		freq = freq_list[i];
1024 		if (!WLAN_REG_IS_SAME_BAND_FREQS(freq, awgn_info->center_freq))
1025 			continue;
1026 
1027 		/**
1028 		 * DFS channel may need CAC during restart, which costs time
1029 		 * and may cause failure.
1030 		 */
1031 		if (wlan_reg_is_dfs_for_freq(pdev, freq)) {
1032 			dcs_debug("skip dfs freq %u", freq);
1033 			continue;
1034 		}
1035 
1036 		if (bonded_chan_ptr &&
1037 		    freq >= bonded_chan_ptr->start_freq &&
1038 		    freq <= bonded_chan_ptr->end_freq) {
1039 			if (is_safe) {
1040 				dcs_debug("add freq directly [%d] = %u",
1041 					  j, freq);
1042 				freq_list[j++] = freq;
1043 			}
1044 			continue;
1045 		}
1046 
1047 		state = wlan_reg_get_5g_bonded_channel_and_state_for_pwrmode(
1048 				pdev, freq, bw, &bonded_chan_ptr,
1049 				REG_CURRENT_PWR_MODE,
1050 				NO_SCHANS_PUNC);
1051 		if (state != CHANNEL_STATE_ENABLE)
1052 			continue;
1053 
1054 		/* no bonding channel for 20MHz */
1055 		if (bw == CH_WIDTH_20MHZ) {
1056 			if (WLAN_DCS_IS_FREQ_IN_WIDTH(awgn_info->center_freq,
1057 						      awgn_info->center_freq0,
1058 						      awgn_info->center_freq1,
1059 						      awgn_info->channel_width,
1060 						      freq))
1061 				continue;
1062 
1063 			dcs_debug("add freq[%d] = %u", j, freq);
1064 			freq_list[j++] = freq;
1065 			continue;
1066 		}
1067 
1068 		is_safe = true;
1069 		chan_cfreq =  bonded_chan_ptr->start_freq;
1070 		while (chan_cfreq <= bonded_chan_ptr->end_freq) {
1071 			if (WLAN_DCS_IS_FREQ_IN_WIDTH(awgn_info->center_freq,
1072 						      awgn_info->center_freq0,
1073 						      awgn_info->center_freq1,
1074 						      awgn_info->channel_width,
1075 						      chan_cfreq)) {
1076 				is_safe = false;
1077 				break;
1078 			}
1079 			chan_cfreq = chan_cfreq + 20;
1080 		}
1081 		if (is_safe) {
1082 			dcs_debug("add freq[%d] = %u", j, freq);
1083 			freq_list[j++] = freq;
1084 		}
1085 	}
1086 
1087 	if (j && random) {
1088 		qdf_get_random_bytes(&random_chan_idx, sizeof(random_chan_idx));
1089 		random_chan_idx = random_chan_idx % j;
1090 		selected_freq = freq_list[random_chan_idx];
1091 		dcs_debug("get freq[%d] = %u for bw %u",
1092 			  random_chan_idx, selected_freq, bw);
1093 	}
1094 
1095 	return selected_freq;
1096 }
1097 
1098 /**
1099  * wlan_dcs_sap_get_available_chan() - get available channel for sap
1100  * @vdev: vdev ptr
1101  * @awgn_info: pointer to awgn info
1102  * @tgt_freq: frequency of the selected channel
1103  * @tgt_width: band width of the selected channel
1104  * @random: request for random channel
1105  *
1106  * This function tries to get no-interference chan with max possible bandwidth
1107  * from pcl for sap according to awgn info.
1108  *
1109  * Return: true if available channel is found, false otherwise.
1110  */
1111 static bool
1112 wlan_dcs_sap_select_chan(struct wlan_objmgr_vdev *vdev,
1113 			 struct wlan_host_dcs_awgn_info *awgn_info,
1114 			 qdf_freq_t *tgt_freq, enum phy_ch_width *tgt_width,
1115 			 bool random)
1116 {
1117 	int32_t tmp_width;
1118 	qdf_freq_t tmp_freq = 0;
1119 	struct wlan_objmgr_pdev *pdev;
1120 	qdf_freq_t *freq_list;
1121 	uint32_t freq_num;
1122 
1123 	freq_list = qdf_mem_malloc(sizeof(*freq_list) * NUM_CHANNELS);
1124 	if (!freq_list)
1125 		return false;
1126 
1127 	freq_num = wlan_dcs_get_pcl_for_sap(vdev, freq_list, NUM_CHANNELS);
1128 	if (!freq_num) {
1129 		qdf_mem_free(freq_list);
1130 		return false;
1131 	}
1132 
1133 	tmp_width = awgn_info->channel_width;
1134 	pdev = wlan_vdev_get_pdev(vdev);
1135 	if (!pdev) {
1136 		qdf_mem_free(freq_list);
1137 		return false;
1138 	}
1139 
1140 	while (tmp_width >= CH_WIDTH_20MHZ) {
1141 		tmp_freq = wlan_dcs_get_available_chan_for_bw(pdev, awgn_info,
1142 							      tmp_width,
1143 							      freq_list,
1144 							      freq_num,
1145 							      random);
1146 		if (tmp_freq)
1147 			break;
1148 		tmp_width--;
1149 	}
1150 
1151 	if (tmp_freq) {
1152 		*tgt_width = tmp_width;
1153 		*tgt_freq = tmp_freq;
1154 		dcs_debug("new_width: %d new_freq %u", tmp_width, tmp_freq);
1155 
1156 		qdf_mem_free(freq_list);
1157 		return true;
1158 	}
1159 
1160 	qdf_mem_free(freq_list);
1161 	return false;
1162 }
1163 
1164 /**
1165  * wlan_dcs_is_awgnim_valid() - validate awgn info
1166  * @awgn_info: pointer to awgn info
1167  *
1168  * Return: true if valid, false otherwise.
1169  */
1170 static inline bool
1171 wlan_dcs_is_awgnim_valid(struct wlan_host_dcs_awgn_info *awgn_info)
1172 {
1173 	return (awgn_info &&
1174 		awgn_info->center_freq && awgn_info->chan_bw_intf_bitmap &&
1175 		awgn_info->channel_width != CH_WIDTH_INVALID &&
1176 		WLAN_REG_IS_6GHZ_CHAN_FREQ(awgn_info->center_freq));
1177 }
1178 
1179 /**
1180  * wlan_dcs_vdev_get_op_chan_info() - get operating channel info for vdev
1181  * @vdev: pointer to vdev object
1182  * @cfreq: Center frequency of primary channel
1183  * @cfreq0: Center frequency of segment 1
1184  * @cfreq1: Center frequency of segment 2
1185  * @ch_width: Channel width, enum phy_ch_width
1186  *
1187  * Return: QDF_STATUS
1188  */
1189 static QDF_STATUS
1190 wlan_dcs_vdev_get_op_chan_info(struct wlan_objmgr_vdev *vdev,
1191 			       qdf_freq_t *cfreq, qdf_freq_t *cfreq0,
1192 			       qdf_freq_t *cfreq1, enum phy_ch_width *ch_width)
1193 {
1194 	struct wlan_channel *chan;
1195 
1196 	if (!vdev)
1197 		return QDF_STATUS_E_INVAL;
1198 
1199 	*cfreq = 0;
1200 	*cfreq0 = 0;
1201 	*cfreq1 = 0;
1202 	*ch_width = 0;
1203 
1204 	if (wlan_vdev_mlme_is_active(vdev) != QDF_STATUS_SUCCESS)
1205 		return QDF_STATUS_E_INVAL;
1206 
1207 	chan = wlan_vdev_get_active_channel(vdev);
1208 	if (!chan)
1209 		return QDF_STATUS_E_INVAL;
1210 
1211 	*cfreq = chan->ch_freq;
1212 	*cfreq0 = chan->ch_cfreq1;
1213 	*cfreq1 = chan->ch_cfreq2;
1214 	*ch_width = chan->ch_width;
1215 
1216 	return QDF_STATUS_SUCCESS;
1217 }
1218 
1219 /**
1220  * wlan_dcs_process_awgn_sta() - process AWGN event for STA
1221  * @pdev: pointer to pdev object
1222  * @object: vdev object
1223  * @arg: Arguments to the handler
1224  *
1225  * Return: void
1226  */
1227 static void wlan_dcs_process_awgn_sta(struct wlan_objmgr_pdev *pdev,
1228 				      void *object, void *arg)
1229 {
1230 	struct wlan_objmgr_vdev *vdev = object;
1231 	struct wlan_host_dcs_awgn_info *awgn_info = arg;
1232 	enum phy_ch_width ch_width;
1233 	enum phy_ch_width tgt_width = CH_WIDTH_INVALID;
1234 	qdf_freq_t op_freq, cfreq0, cfreq1;
1235 	qdf_freq_t tgt_freq = 0;
1236 	QDF_STATUS status;
1237 	uint8_t vdev_id;
1238 	bool found;
1239 
1240 	if (!vdev || !pdev)
1241 		return;
1242 
1243 	if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE)
1244 		return;
1245 
1246 	vdev_id = wlan_vdev_get_id(vdev);
1247 	status = wlan_dcs_vdev_get_op_chan_info(vdev, &op_freq, &cfreq0,
1248 						&cfreq1, &ch_width);
1249 	if (QDF_IS_STATUS_ERROR(status))
1250 		return;
1251 
1252 	if (awgn_info->center_freq != op_freq) {
1253 		dcs_debug("STA-%d: freq not match", vdev_id);
1254 		return;
1255 	}
1256 
1257 	found = wlan_dcs_get_max_no_intf_bw(awgn_info, &tgt_width);
1258 	if (found) {
1259 		if (ch_width <= tgt_width) {
1260 			dcs_debug("STA-%d: freq and bw are unchanged", vdev_id);
1261 			return;
1262 		}
1263 
1264 		tgt_freq = op_freq;
1265 	}
1266 
1267 	/* If no width is found, means to disconnect */
1268 	dcs_debug("STA-%d: target freq %u width %u",
1269 		  vdev_id, tgt_freq, tgt_width);
1270 	wlan_dcs_switch_chan(vdev, tgt_freq, tgt_width);
1271 }
1272 
1273 /**
1274  * wlan_dcs_process_awgn_sap() - process AWGN event for SAP
1275  * @pdev: pointer to pdev object
1276  * @object: vdev object
1277  * @arg: Arguments to the handler
1278  *
1279  * Return: void
1280  */
1281 static void wlan_dcs_process_awgn_sap(struct wlan_objmgr_pdev *pdev,
1282 				      void *object, void *arg)
1283 {
1284 	struct wlan_objmgr_vdev *vdev = object;
1285 	struct wlan_host_dcs_awgn_info *awgn_info = arg;
1286 	enum phy_ch_width ch_width;
1287 	enum phy_ch_width tgt_width = CH_WIDTH_INVALID;
1288 	qdf_freq_t op_freq, cfreq0, cfreq1;
1289 	qdf_freq_t tgt_freq = 0;
1290 	QDF_STATUS status;
1291 	uint8_t vdev_id;
1292 	bool found;
1293 
1294 	if (!vdev || !pdev)
1295 		return;
1296 
1297 	if (wlan_vdev_mlme_get_opmode(vdev) != QDF_SAP_MODE)
1298 		return;
1299 
1300 	vdev_id = wlan_vdev_get_id(vdev);
1301 	status = wlan_dcs_vdev_get_op_chan_info(vdev, &op_freq, &cfreq0, &cfreq1, &ch_width);
1302 	if (QDF_IS_STATUS_ERROR(status))
1303 		return;
1304 
1305 	if (awgn_info->center_freq != op_freq) {
1306 		dcs_debug("SAP-%d: freq not match rpt:%u - op:%u",
1307 			  vdev_id, awgn_info->center_freq, op_freq);
1308 		return;
1309 	}
1310 
1311 	found = wlan_dcs_get_max_no_intf_bw(awgn_info, &tgt_width);
1312 	if (found) {
1313 		if (ch_width <= tgt_width) {
1314 			dcs_debug("SAP-%d: both freq and bw are unchanged",
1315 				  vdev_id);
1316 			return;
1317 		}
1318 
1319 		tgt_freq = op_freq;
1320 	} else {
1321 		wlan_dcs_sap_select_chan(vdev, awgn_info, &tgt_freq,
1322 					 &tgt_width, true);
1323 	}
1324 
1325 	/* If no chan is selected, means to stop sap */
1326 	dcs_debug("SAP-%d: target freq %u width %u",
1327 		  vdev_id, tgt_freq, tgt_width);
1328 	wlan_dcs_switch_chan(vdev, tgt_freq, tgt_width);
1329 }
1330 
1331 /**
1332  * wlan_dcs_awgnim_process() - process awgn IM
1333  * @psoc: psoc ptr
1334  * @pdev_id: pdev id
1335  * @awgn_info: pointer to awgn info
1336  *
1337  * This function triggers channel change for all STAs and SAPs, according
1338  * to AWGN info.
1339  *
1340  * Return: None.
1341  */
1342 static void
1343 wlan_dcs_awgn_process(struct wlan_objmgr_psoc *psoc, uint8_t pdev_id,
1344 		      struct wlan_host_dcs_awgn_info *awgn_info)
1345 {
1346 	struct wlan_objmgr_pdev *pdev;
1347 
1348 	if (!wlan_dcs_is_awgnim_valid(awgn_info)) {
1349 		dcs_err("Invalid awgnim event");
1350 		return;
1351 	}
1352 
1353 	pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_DCS_ID);
1354 	if (!pdev) {
1355 		dcs_err("Invalid pdev id %d", pdev_id);
1356 		return;
1357 	}
1358 
1359 	dcs_debug("pdev id %u width %u freq %u freq0 %u fre1 %u bitmap 0x%x",
1360 		  pdev_id, awgn_info->channel_width, awgn_info->center_freq,
1361 		  awgn_info->center_freq0, awgn_info->center_freq1,
1362 		  awgn_info->chan_bw_intf_bitmap);
1363 
1364 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
1365 					  wlan_dcs_process_awgn_sta,
1366 					  awgn_info, 0, WLAN_DCS_ID);
1367 
1368 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
1369 					  wlan_dcs_process_awgn_sap,
1370 					  awgn_info, 0, WLAN_DCS_ID);
1371 
1372 	wlan_objmgr_pdev_release_ref(pdev, WLAN_DCS_ID);
1373 }
1374 
1375 #ifdef CONFIG_AFC_SUPPORT
1376 /**
1377  * wlan_dcs_afc_sel_chan() - Select SAP new channel/bandwidth when AFC updated
1378  * @psoc: pointer to soc
1379  * @vdev_id: vdev id
1380  * @cur_freq: current channel frequency
1381  * @cur_bw: current channel bandwidth
1382  * @pref_bw: pointer to bandwidth of prefer to switch to when input, and target
1383  *           bandwidth decided to switch to
1384  *
1385  * Return: target channel frequency to switch to
1386  */
1387 static qdf_freq_t wlan_dcs_afc_sel_chan(struct wlan_objmgr_psoc *psoc,
1388 					uint32_t vdev_id,
1389 					qdf_freq_t cur_freq,
1390 					enum phy_ch_width cur_bw,
1391 					enum phy_ch_width *pref_bw)
1392 {
1393 	struct dcs_psoc_priv_obj *dcs_psoc_priv;
1394 	dcs_afc_select_chan_cb afc_sel_chan_cb;
1395 
1396 	if (!psoc)
1397 		return 0;
1398 
1399 	dcs_psoc_priv = wlan_objmgr_psoc_get_comp_private_obj(
1400 			psoc,
1401 			WLAN_UMAC_COMP_DCS);
1402 	if (!dcs_psoc_priv)
1403 		return 0;
1404 
1405 	afc_sel_chan_cb = dcs_psoc_priv->afc_sel_chan_cbk.cbk;
1406 	if (!afc_sel_chan_cb)
1407 		return 0;
1408 
1409 	return afc_sel_chan_cb(dcs_psoc_priv->afc_sel_chan_cbk.arg,
1410 			       vdev_id, cur_freq, cur_bw, pref_bw);
1411 }
1412 
1413 /**
1414  * wlan_dcs_afc_get_conn_info() - Iterate function to get connection channel
1415  *                                information of every vdev
1416  * @pdev: pointer to pdev
1417  * @object: pointer to iteration object
1418  * @arg: pointer to iteration argument
1419  *
1420  * Return: void
1421  */
1422 static void
1423 wlan_dcs_afc_get_conn_info(struct wlan_objmgr_pdev *pdev,
1424 			   void *object, void *arg)
1425 {
1426 	struct wlan_objmgr_vdev *vdev = object;
1427 	struct wlan_dcs_conn_info *conn_info = arg;
1428 	enum QDF_OPMODE op_mode;
1429 	struct wlan_channel *chan;
1430 	uint8_t vdev_id;
1431 
1432 	if (!vdev || !pdev || !conn_info)
1433 		return;
1434 
1435 	if (conn_info->exit_condition)
1436 		return;
1437 
1438 	if (wlan_vdev_mlme_is_active(vdev) != QDF_STATUS_SUCCESS)
1439 		return;
1440 
1441 	vdev_id = wlan_vdev_get_id(vdev);
1442 	op_mode = wlan_vdev_mlme_get_opmode(vdev);
1443 	chan = wlan_vdev_get_active_channel(vdev);
1444 	if (!chan)
1445 		return;
1446 
1447 	switch (op_mode) {
1448 	case QDF_STA_MODE:
1449 		if (conn_info->sta_cnt >= WLAN_DCS_MAX_STA_NUM) {
1450 			dcs_debug("too many STAs");
1451 			conn_info->exit_condition = true;
1452 			break;
1453 		}
1454 		conn_info->sta[conn_info->sta_cnt].freq = chan->ch_freq;
1455 		conn_info->sta[conn_info->sta_cnt].bw = chan->ch_width;
1456 		conn_info->sta[conn_info->sta_cnt].vdev_id = vdev_id;
1457 		conn_info->sta_cnt++;
1458 		break;
1459 	case QDF_SAP_MODE:
1460 		if (WLAN_REG_IS_5GHZ_CH_FREQ(chan->ch_freq)) {
1461 			if (conn_info->sap_5ghz_cnt >= WLAN_DCS_MAX_SAP_NUM) {
1462 				dcs_debug("too many 5 GHz SAPs");
1463 				conn_info->exit_condition = true;
1464 			}
1465 			conn_info->sap_5ghz[conn_info->sap_5ghz_cnt].freq =
1466 				chan->ch_freq;
1467 			conn_info->sap_5ghz[conn_info->sap_5ghz_cnt].bw =
1468 				chan->ch_width;
1469 			conn_info->sap_5ghz[conn_info->sap_5ghz_cnt].vdev_id =
1470 				vdev_id;
1471 			conn_info->sap_5ghz_cnt++;
1472 		} else if (WLAN_REG_IS_6GHZ_CHAN_FREQ(chan->ch_freq)) {
1473 			if (conn_info->sap_6ghz_cnt >= WLAN_DCS_MAX_SAP_NUM) {
1474 				dcs_debug("too many 6 GHz SAPs");
1475 				conn_info->exit_condition = true;
1476 			}
1477 			conn_info->sap_6ghz[conn_info->sap_6ghz_cnt].freq =
1478 				chan->ch_freq;
1479 			conn_info->sap_6ghz[conn_info->sap_6ghz_cnt].bw =
1480 				chan->ch_width;
1481 			conn_info->sap_6ghz[conn_info->sap_6ghz_cnt].vdev_id =
1482 				vdev_id;
1483 			conn_info->sap_6ghz_cnt++;
1484 		}
1485 		break;
1486 	default:
1487 		dcs_debug("not support op mode %d", op_mode);
1488 		conn_info->exit_condition = true;
1489 		break;
1490 	}
1491 }
1492 
1493 /**
1494  * wlan_dcs_afc_reduce_bw() - Get target bandwidth with fixed channel frequency
1495  * @pdev: pointer to pdev
1496  * @freq: channel frequency which is fixed because SCC with STA
1497  * @input_bw: SAP current channel bandwidth
1498  *
1499  * This function check every sub 20 MHz channel state which update by AFC, and
1500  * reduce channel bandwidth if sub channel is disable.
1501  *
1502  * Return: Reduced channel bandwidth
1503  */
1504 static enum phy_ch_width wlan_dcs_afc_reduce_bw(struct wlan_objmgr_pdev *pdev,
1505 						qdf_freq_t freq,
1506 						enum phy_ch_width input_bw)
1507 {
1508 	const struct bonded_channel_freq *bonded_chan_ptr = NULL;
1509 	enum channel_state state;
1510 	qdf_freq_t start_freq;
1511 	bool find;
1512 
1513 	if (input_bw <= CH_WIDTH_20MHZ)
1514 		return input_bw;
1515 
1516 	while (input_bw > CH_WIDTH_20MHZ) {
1517 		state = wlan_reg_get_5g_bonded_channel_and_state_for_freq(
1518 				pdev, freq, input_bw, &bonded_chan_ptr);
1519 		if (state != CHANNEL_STATE_ENABLE) {
1520 			input_bw = wlan_reg_get_next_lower_bandwidth(input_bw);
1521 			continue;
1522 		}
1523 		find = false;
1524 		start_freq = bonded_chan_ptr->start_freq;
1525 		while (start_freq <= bonded_chan_ptr->end_freq) {
1526 			if (wlan_reg_is_disable_in_secondary_list_for_freq(
1527 					pdev, start_freq)) {
1528 				find = true;
1529 				break;
1530 			}
1531 			start_freq += 20;
1532 		}
1533 		if (find)
1534 			input_bw = wlan_reg_get_next_lower_bandwidth(input_bw);
1535 		else
1536 			return input_bw;
1537 	}
1538 	return input_bw;
1539 }
1540 
1541 /**
1542  * wlan_sap_update_tpc_on_channel() - Update vdev channel TPC parameters and
1543  *                                    send TPC command
1544  * @pdev: pointer to pdev
1545  * @vdev_id: vdev id
1546  * @freq: SAP 6 GHz channel frequency
1547  * @bw: SAP 6 GHz channel bandwidth
1548  *
1549  * Return: void
1550  */
1551 static void
1552 wlan_sap_update_tpc_on_channel(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id,
1553 			       qdf_freq_t freq, enum phy_ch_width bw)
1554 {
1555 	struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
1556 	struct wlan_lmac_if_reg_tx_ops *tx_ops;
1557 	struct vdev_mlme_obj *mlme_obj;
1558 	struct wlan_objmgr_vdev *vdev;
1559 	struct reg_tpc_power_info *tpc;
1560 	bool is_psd;
1561 	uint32_t i;
1562 	uint16_t tx_power;
1563 	int16_t psd_eirp;
1564 	enum reg_6g_ap_type power_type;
1565 
1566 	if (!wlan_reg_is_ext_tpc_supported(psoc))
1567 		return;
1568 
1569 	if (wlan_reg_decide_6ghz_power_within_bw_for_freq(
1570 		pdev, freq, bw, &is_psd, &tx_power, &psd_eirp, &power_type) !=
1571 	    QDF_STATUS_SUCCESS)
1572 		return;
1573 
1574 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_DCS_ID);
1575 	if (!vdev)
1576 		return;
1577 
1578 	tx_ops = wlan_reg_get_tx_ops(psoc);
1579 
1580 	mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev);
1581 	if (!mlme_obj) {
1582 		dcs_err("vdev mlme obj is NULL");
1583 		goto release_vdev;
1584 	}
1585 
1586 	tpc = &mlme_obj->reg_tpc_obj;
1587 	if (tpc->is_psd_power != is_psd) {
1588 		dcs_debug("psd flag changed");
1589 		goto release_vdev;
1590 	}
1591 	tpc->eirp_power = tx_power;
1592 	tpc->power_type_6g = power_type;
1593 	for (i = 0; i < tpc->num_pwr_levels; i++) {
1594 		if (is_psd)
1595 			tpc->chan_power_info[i].tx_power = (uint8_t)psd_eirp;
1596 		else
1597 			tpc->chan_power_info[i].tx_power = (uint8_t)tx_power;
1598 	}
1599 
1600 	dcs_debug("6 GHz pwr type %d, is psd %d, pwr %d, psd %d, num pwr %d",
1601 		  power_type, is_psd, tx_power, psd_eirp, tpc->num_pwr_levels);
1602 
1603 	if (tx_ops->set_tpc_power)
1604 		tx_ops->set_tpc_power(psoc, vdev_id, tpc);
1605 
1606 release_vdev:
1607 	wlan_objmgr_vdev_release_ref(vdev, WLAN_DCS_ID);
1608 }
1609 
1610 /**
1611  * wlan_dcs_afc_sap_dcs_with_sta() - SAP channel switch when coexist with STA
1612  * @pdev: pointer to pdev handle
1613  * @conn_info: pointer to connection context of AFC DCS
1614  *
1615  * This function update TPC or restart SAP if doing SCC on 6 GHz with STA
1616  *
1617  * Return: void
1618  */
1619 static void
1620 wlan_dcs_afc_sap_dcs_with_sta(struct wlan_objmgr_pdev *pdev,
1621 			      struct wlan_dcs_conn_info *conn_info)
1622 {
1623 	uint32_t i;
1624 	qdf_freq_t target_freq = conn_info->sta[0].freq;
1625 	enum phy_ch_width target_bw = CH_WIDTH_20MHZ;
1626 	struct wlan_objmgr_vdev *vdev;
1627 
1628 	if (!WLAN_REG_IS_6GHZ_CHAN_FREQ(conn_info->sta[0].freq))
1629 		return;
1630 
1631 	for (i = 0; i < conn_info->sap_6ghz_cnt; i++) {
1632 		if (conn_info->sap_6ghz[i].freq ==
1633 		    conn_info->sta[0].freq) {
1634 			/*
1635 			 * sta operate under control of ap, if stop sap,
1636 			 * cannot start by itself, so just update tpc as sta,
1637 			 * if tx power is minimum of SCC tpc commands, no
1638 			 * need to update sap tpc command.
1639 			 * assume sta will move to safe channel by ap and
1640 			 * sap can move channel accordingly.
1641 			 */
1642 			if (wlan_reg_is_disable_in_secondary_list_for_freq(
1643 					pdev, conn_info->sta[0].freq))
1644 				continue;
1645 
1646 			target_bw = wlan_dcs_afc_reduce_bw(
1647 					pdev,
1648 					conn_info->sap_6ghz[i].freq,
1649 					conn_info->sap_6ghz[i].bw);
1650 
1651 			if (target_bw == conn_info->sap_6ghz[i].bw) {
1652 				wlan_sap_update_tpc_on_channel(
1653 					pdev,
1654 					conn_info->sap_6ghz[i].vdev_id,
1655 					conn_info->sap_6ghz[i].freq,
1656 					target_bw);
1657 				continue;
1658 			}
1659 
1660 			vdev = wlan_objmgr_get_vdev_by_id_from_pdev(
1661 					pdev,
1662 					conn_info->sap_6ghz[i].vdev_id,
1663 					WLAN_DCS_ID);
1664 			if (!vdev)
1665 				continue;
1666 
1667 			/* tpc update once csa complete */
1668 			wlan_dcs_switch_chan(vdev, target_freq, target_bw);
1669 			wlan_objmgr_vdev_release_ref(vdev, WLAN_DCS_ID);
1670 		}
1671 	}
1672 }
1673 
1674 #ifdef WLAN_POLICY_MGR_ENABLE
1675 /**
1676  * wlan_dcs_afc_6ghz_capable() - API to check SAP configure is able to operate
1677  *                               on 6 GHz
1678  * @psoc: pointer to SOC
1679  * @vdev_id: vdev id
1680  *
1681  * Return: Return true if SAP is able to operate on 6 GHz
1682  */
1683 static inline bool
1684 wlan_dcs_afc_6ghz_capable(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
1685 {
1686 	return policy_mgr_get_ap_6ghz_capable(psoc, vdev_id, NULL);
1687 }
1688 #else
1689 static inline bool
1690 wlan_dcs_afc_6ghz_capable(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
1691 {
1692 	return false;
1693 }
1694 #endif
1695 
1696 /**
1697  * wlan_dcs_afc_5ghz6ghz_sap_dcs() - SAP on 5 GHz or 6 GHz channel to do
1698  * channel switch.
1699  * @pdev: pointer to pdev handle
1700  * @conn_info: pointer to connection context for AFC DCS
1701  *
1702  * This function is trigger by AFC event and 6 GHz channels' state has been
1703  * updated, restart SAP to SP channel if possible, gain better performance.
1704  *
1705  * Return: void
1706  */
1707 static void
1708 wlan_dcs_afc_5ghz6ghz_sap_dcs(struct wlan_objmgr_pdev *pdev,
1709 			      struct wlan_dcs_conn_info *conn_info)
1710 {
1711 	uint32_t i;
1712 	struct wlan_objmgr_vdev *vdev;
1713 	uint8_t max_bw_vdev_id;
1714 	qdf_freq_t max_bw_freq, target_freq;
1715 	enum phy_ch_width max_bw = CH_WIDTH_20MHZ;
1716 	enum phy_ch_width pref_bw;
1717 
1718 	if (conn_info->sap_5ghz_cnt) {
1719 		max_bw = conn_info->sap_5ghz[0].bw;
1720 		max_bw_vdev_id = conn_info->sap_5ghz[0].vdev_id;
1721 		max_bw_freq = conn_info->sap_5ghz[0].freq;
1722 		for (i = 1; i < conn_info->sap_5ghz_cnt; i++) {
1723 			if (conn_info->sap_5ghz[i].bw > max_bw) {
1724 				max_bw = conn_info->sap_5ghz[i].bw;
1725 				max_bw_vdev_id = conn_info->sap_5ghz[i].vdev_id;
1726 				max_bw_freq = conn_info->sap_5ghz[i].freq;
1727 			}
1728 		}
1729 	} else if (conn_info->sap_6ghz_cnt) {
1730 		max_bw = conn_info->sap_6ghz[0].bw;
1731 		max_bw_vdev_id = conn_info->sap_6ghz[0].vdev_id;
1732 		max_bw_freq = conn_info->sap_6ghz[0].freq;
1733 		for (i = 1; i < conn_info->sap_6ghz_cnt; i++) {
1734 			if (conn_info->sap_6ghz[i].bw > max_bw) {
1735 				max_bw = conn_info->sap_6ghz[i].bw;
1736 				max_bw_vdev_id = conn_info->sap_6ghz[i].vdev_id;
1737 				max_bw_freq = conn_info->sap_6ghz[i].freq;
1738 			}
1739 		}
1740 	} else {
1741 		return;
1742 	}
1743 
1744 	/*
1745 	 * After several AFC event update, if maximum bandwidth shrink to
1746 	 * 20 MHz, set prefer bandwidth to pre-defined value like 80 MHz,
1747 	 * so it can expand bandwidth and gain better performance.
1748 	 */
1749 	if (max_bw == CH_WIDTH_20MHZ)
1750 		pref_bw = WLAN_DCS_AFC_PREFER_BW;
1751 	else
1752 		pref_bw = max_bw;
1753 
1754 	target_freq = wlan_dcs_afc_sel_chan(
1755 			wlan_pdev_get_psoc(pdev),
1756 			max_bw_vdev_id,
1757 			max_bw_freq, max_bw, &pref_bw);
1758 
1759 	if (!target_freq)
1760 		return;
1761 
1762 	if (WLAN_REG_IS_6GHZ_CHAN_FREQ(target_freq) &&
1763 	    conn_info->sap_5ghz_cnt) {
1764 		for (i = 0; i < conn_info->sap_5ghz_cnt; i++) {
1765 			if (!wlan_dcs_afc_6ghz_capable(
1766 			    wlan_pdev_get_psoc(pdev),
1767 			    conn_info->sap_5ghz[i].vdev_id)) {
1768 				dcs_debug("vdev %d has no 6 GHz capability",
1769 					  conn_info->sap_5ghz[i].vdev_id);
1770 				return;
1771 			}
1772 		}
1773 	}
1774 
1775 	if (conn_info->sap_5ghz_cnt) {
1776 		for (i = 0; i < conn_info->sap_5ghz_cnt; i++) {
1777 			if (target_freq == conn_info->sap_5ghz[i].freq &&
1778 			    pref_bw == conn_info->sap_5ghz[i].bw)
1779 				continue;
1780 			vdev = wlan_objmgr_get_vdev_by_id_from_pdev(
1781 					pdev,
1782 					conn_info->sap_5ghz[i].vdev_id,
1783 					WLAN_DCS_ID);
1784 			if (!vdev)
1785 				continue;
1786 
1787 			wlan_dcs_switch_chan(vdev, target_freq, pref_bw);
1788 			wlan_objmgr_vdev_release_ref(vdev, WLAN_DCS_ID);
1789 		}
1790 	} else if (conn_info->sap_6ghz_cnt) {
1791 		for (i = 0; i < conn_info->sap_6ghz_cnt; i++) {
1792 			if (target_freq == conn_info->sap_6ghz[i].freq &&
1793 			    pref_bw == conn_info->sap_6ghz[i].bw)
1794 				continue;
1795 			vdev = wlan_objmgr_get_vdev_by_id_from_pdev(
1796 					pdev,
1797 					conn_info->sap_6ghz[i].vdev_id,
1798 					WLAN_DCS_ID);
1799 			if (!vdev)
1800 				continue;
1801 
1802 			wlan_dcs_switch_chan(vdev, target_freq, pref_bw);
1803 			wlan_objmgr_vdev_release_ref(vdev, WLAN_DCS_ID);
1804 		}
1805 	}
1806 }
1807 
1808 /**
1809  * wlan_dcs_afc_process() - Dynamic SAP channel switch after AFC update
1810  * @psoc: psoc handle
1811  * @pdev_id: pdev id
1812  *
1813  * Return: void
1814  */
1815 static void
1816 wlan_dcs_afc_process(struct wlan_objmgr_psoc *psoc, uint8_t pdev_id)
1817 {
1818 	struct wlan_objmgr_pdev *pdev;
1819 	struct wlan_dcs_conn_info conn_info = {0};
1820 
1821 	pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_DCS_ID);
1822 	if (!pdev) {
1823 		dcs_err("Invalid pdev id %d", pdev_id);
1824 		return;
1825 	}
1826 
1827 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
1828 					  wlan_dcs_afc_get_conn_info,
1829 					  &conn_info, 0, WLAN_DCS_ID);
1830 	if (conn_info.exit_condition)
1831 		goto pdev_release;
1832 
1833 	if ((conn_info.sap_5ghz_cnt && conn_info.sap_6ghz_cnt) ||
1834 	    (!conn_info.sap_5ghz_cnt && !conn_info.sap_6ghz_cnt)) {
1835 		dcs_debug("NA for %d 5 GHz SAP, %d 6 GHz SAP",
1836 			  conn_info.sap_5ghz_cnt, conn_info.sap_6ghz_cnt);
1837 		goto pdev_release;
1838 	}
1839 
1840 	if (conn_info.sta_cnt &&
1841 	    !WLAN_REG_IS_24GHZ_CH_FREQ(conn_info.sta[0].freq))
1842 		wlan_dcs_afc_sap_dcs_with_sta(pdev, &conn_info);
1843 	else
1844 		wlan_dcs_afc_5ghz6ghz_sap_dcs(pdev, &conn_info);
1845 
1846 pdev_release:
1847 	wlan_objmgr_pdev_release_ref(pdev, WLAN_DCS_ID);
1848 }
1849 #else
1850 static inline void
1851 wlan_dcs_afc_process(struct wlan_objmgr_psoc *psoc, uint8_t pdev_id) {}
1852 #endif
1853 
1854 QDF_STATUS
1855 wlan_dcs_process(struct wlan_objmgr_psoc *psoc,
1856 		 struct wlan_host_dcs_event *event)
1857 {
1858 	struct dcs_pdev_priv_obj *dcs_pdev_priv;
1859 	bool start_dcs_cbk_handler = false;
1860 
1861 	if (!psoc || !event) {
1862 		dcs_err("psoc or event is NULL");
1863 		return QDF_STATUS_E_INVAL;
1864 	}
1865 
1866 	dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc,
1867 						      event->dcs_param.pdev_id);
1868 	if (!dcs_pdev_priv) {
1869 		dcs_err("dcs pdev private object is null");
1870 		return QDF_STATUS_E_INVAL;
1871 	}
1872 
1873 	if (unlikely(dcs_pdev_priv->dcs_host_params.dcs_debug
1874 			>= DCS_DEBUG_VERBOSE))
1875 		dcs_debug("dcs_enable: %u, interference_type: %u, pdev_id: %u",
1876 			  dcs_pdev_priv->dcs_host_params.dcs_enable,
1877 			  event->dcs_param.interference_type,
1878 			  event->dcs_param.pdev_id);
1879 
1880 	switch (event->dcs_param.interference_type) {
1881 	case WLAN_HOST_DCS_CWIM:
1882 		break;
1883 	case WLAN_HOST_DCS_WLANIM:
1884 		if (!dcs_pdev_priv->dcs_host_params.dcs_enable)
1885 			break;
1886 
1887 		if (dcs_pdev_priv->dcs_host_params.dcs_enable &
1888 		    WLAN_HOST_DCS_WLANIM)
1889 			start_dcs_cbk_handler =
1890 				wlan_dcs_wlan_interference_process(
1891 							&event->wlan_stat,
1892 							dcs_pdev_priv);
1893 		if (dcs_pdev_priv->user_cb &&
1894 		    dcs_pdev_priv->dcs_host_params.notify_user) {
1895 			dcs_pdev_priv->dcs_host_params.notify_user = 0;
1896 			dcs_pdev_priv->user_cb(dcs_pdev_priv->requestor_vdev_id,
1897 				 &dcs_pdev_priv->dcs_im_stats.user_dcs_im_stats,
1898 				 0);
1899 		}
1900 		if (start_dcs_cbk_handler)
1901 			wlan_dcs_frequency_control(psoc,
1902 						   dcs_pdev_priv,
1903 						   event);
1904 		break;
1905 	case WLAN_HOST_DCS_AWGNIM:
1906 		/* Skip frequency control for AWGNIM */
1907 		wlan_dcs_awgn_process(psoc, event->dcs_param.pdev_id,
1908 				      &event->awgn_info);
1909 		break;
1910 	case WLAN_HOST_DCS_AFC:
1911 		wlan_dcs_afc_process(psoc, event->dcs_param.pdev_id);
1912 		break;
1913 	default:
1914 		dcs_err("unidentified interference type reported");
1915 		break;
1916 	}
1917 
1918 	return QDF_STATUS_SUCCESS;
1919 }
1920 
1921 void wlan_dcs_clear(struct wlan_objmgr_psoc *psoc, uint32_t pdev_id)
1922 {
1923 	struct dcs_pdev_priv_obj *dcs_pdev_priv;
1924 
1925 	if (!psoc) {
1926 		dcs_err("psoc is null");
1927 		return;
1928 	}
1929 
1930 	dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc, pdev_id);
1931 	if (!dcs_pdev_priv) {
1932 		dcs_err("dcs pdev private object is null");
1933 		return;
1934 	}
1935 
1936 	qdf_timer_stop(&dcs_pdev_priv->dcs_disable_timer);
1937 	qdf_mem_set(&dcs_pdev_priv->dcs_im_stats,
1938 		    sizeof(dcs_pdev_priv->dcs_im_stats), 0);
1939 	qdf_mem_set(dcs_pdev_priv->dcs_freq_ctrl_params.timestamp,
1940 		    MAX_DCS_TIME_RECORD * sizeof(unsigned long), 0);
1941 	dcs_pdev_priv->dcs_freq_ctrl_params.dcs_happened_count = 0;
1942 	dcs_pdev_priv->dcs_freq_ctrl_params.disable_delay_process = false;
1943 	wlan_dcs_set_algorithm_process(psoc, pdev_id, false);
1944 }
1945 
1946 void wlan_dcs_set_algorithm_process(struct wlan_objmgr_psoc *psoc,
1947 				    uint32_t pdev_id,
1948 				    bool dcs_algorithm_process)
1949 {
1950 	struct dcs_pdev_priv_obj *dcs_pdev_priv;
1951 
1952 	dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc, pdev_id);
1953 	if (!dcs_pdev_priv) {
1954 		dcs_err("dcs pdev private object is null");
1955 		return;
1956 	}
1957 
1958 	if (dcs_pdev_priv->dcs_host_params.force_disable_algorithm) {
1959 		dcs_debug("dcs algorithm is disabled forcely");
1960 		dcs_pdev_priv->dcs_host_params.dcs_algorithm_process = false;
1961 		return;
1962 	}
1963 
1964 	dcs_pdev_priv->dcs_host_params.dcs_algorithm_process =
1965 							dcs_algorithm_process;
1966 }
1967