xref: /wlan-dirver/qca-wifi-host-cmn/umac/dcs/core/src/wlan_dcs.c (revision 5aac5cb621aadb06962f4018dc642f2e7b4a8d24)
1 /*
2  * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022-2023 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 QDF_STATUS
718 wlan_dcs_switch_chan(struct wlan_objmgr_vdev *vdev, qdf_freq_t tgt_freq,
719 		     enum phy_ch_width tgt_width)
720 {
721 	struct wlan_objmgr_psoc *psoc;
722 	struct dcs_psoc_priv_obj *dcs_psoc_priv;
723 	dcs_switch_chan_cb switch_chan_cb;
724 
725 	psoc = wlan_vdev_get_psoc(vdev);
726 	if (!psoc)
727 		return QDF_STATUS_E_INVAL;
728 
729 	dcs_psoc_priv = wlan_objmgr_psoc_get_comp_private_obj(psoc,
730 					WLAN_UMAC_COMP_DCS);
731 	if (!dcs_psoc_priv)
732 		return QDF_STATUS_E_INVAL;
733 
734 	switch_chan_cb = dcs_psoc_priv->switch_chan_cb;
735 	if (!switch_chan_cb)
736 		return QDF_STATUS_E_NOSUPPORT;
737 
738 	return switch_chan_cb(vdev, tgt_freq, tgt_width);
739 }
740 
741 #ifdef WLAN_POLICY_MGR_ENABLE
742 /**
743  * wlan_dcs_get_pcl_for_sap() - get preferred channel list for SAP
744  * @vdev: vdev ptr
745  * @freq_list: Pointer to PCL
746  * @freq_list_sz: Max size of PCL
747  *
748  * Return: number of channels in PCL
749  */
750 static uint32_t wlan_dcs_get_pcl_for_sap(struct wlan_objmgr_vdev *vdev,
751 					 qdf_freq_t *freq_list,
752 					 uint32_t freq_list_sz)
753 {
754 	struct wlan_objmgr_psoc *psoc;
755 	struct wlan_objmgr_pdev *pdev;
756 	struct policy_mgr_pcl_list *pcl;
757 	qdf_freq_t freq;
758 	enum channel_state state;
759 	QDF_STATUS status;
760 	int i, j;
761 
762 	psoc = wlan_vdev_get_psoc(vdev);
763 	if (!psoc)
764 		return 0;
765 
766 	pdev = wlan_vdev_get_pdev(vdev);
767 	if (!pdev)
768 		return 0;
769 
770 	pcl = qdf_mem_malloc(sizeof(*pcl));
771 	if (!pcl)
772 		return 0;
773 
774 	status = policy_mgr_get_pcl_for_vdev_id(psoc,
775 						PM_SAP_MODE,
776 						pcl->pcl_list, &pcl->pcl_len,
777 						pcl->weight_list,
778 						QDF_ARRAY_SIZE(pcl->weight_list),
779 						wlan_vdev_get_id(vdev));
780 	if (QDF_IS_STATUS_ERROR(status) || !pcl->pcl_len) {
781 		qdf_mem_free(pcl);
782 		return 0;
783 	}
784 
785 	for (i = 0, j = 0; i < pcl->pcl_len && i < freq_list_sz; i++) {
786 		freq = (qdf_freq_t)pcl->pcl_list[i];
787 		state = wlan_reg_get_channel_state_for_pwrmode(
788 							pdev,
789 							freq,
790 							REG_CURRENT_PWR_MODE);
791 		if (state != CHANNEL_STATE_ENABLE)
792 			continue;
793 
794 		freq_list[j++] = freq;
795 	}
796 
797 	qdf_mem_free(pcl);
798 	return j;
799 }
800 #else
801 static uint32_t wlan_dcs_get_pcl_for_sap(struct wlan_objmgr_vdev *vdev,
802 					 qdf_freq_t *freq_list,
803 					 uint32_t freq_list_sz)
804 {
805 	struct wlan_objmgr_pdev *pdev;
806 	struct regulatory_channel *cur_chan_list;
807 	qdf_freq_t freq;
808 	enum channel_state state;
809 	int i, j;
810 
811 	pdev = wlan_vdev_get_pdev(vdev);
812 	if (!pdev)
813 		return 0;
814 
815 	cur_chan_list = qdf_mem_malloc(NUM_CHANNELS *
816 			sizeof(struct regulatory_channel));
817 	if (!cur_chan_list)
818 		return 0;
819 
820 	if (wlan_reg_get_current_chan_list(pdev, cur_chan_list) !=
821 					   QDF_STATUS_SUCCESS) {
822 		qdf_mem_free(cur_chan_list);
823 		return 0;
824 	}
825 
826 	for (i = 0, j = 0; i < NUM_CHANNELS && i < freq_list_sz; i++) {
827 		freq = cur_chan_list[i].center_freq;
828 		state = wlan_reg_get_channel_state_for_pwrmode(
829 						       pdev,
830 						       freq,
831 						       REG_CURRENT_PWR_MODE);
832 		if (state != CHANNEL_STATE_ENABLE)
833 			continue;
834 
835 		freq_list[j++] = freq;
836 	}
837 
838 	qdf_mem_free(cur_chan_list);
839 	return j;
840 }
841 #endif
842 
843 /**
844  * wlan_dcs_awgn_get_intf_for_seg() - get interference for specified segment
845  * @awgn_info: awgn info pointer
846  * @segment: segment index in channel band
847  *
848  * This function extracts the information from awgn event and check interference
849  * within the specified segment.
850  *
851  * Return: true if interference is found within the segment, false otherwise.
852  */
853 static bool
854 wlan_dcs_awgn_get_intf_for_seg(struct wlan_host_dcs_awgn_info *awgn_info,
855 			       uint32_t segment)
856 {
857 	uint32_t seg_mask;
858 
859 	switch (segment) {
860 	case WLAN_DCS_SEG_PRI20:
861 		seg_mask = WLAN_DCS_SEG_PRI20_MASK;
862 		break;
863 	case WLAN_DCS_SEG_SEC20:
864 		seg_mask = WLAN_DCS_SEG_SEC20_MASK;
865 		break;
866 	case WLAN_DCS_SEG_SEC40:
867 		seg_mask = WLAN_DCS_SEG_SEC40_MASK;
868 		break;
869 	case WLAN_DCS_SEG_SEC80:
870 		seg_mask = WLAN_DCS_SEG_SEC80_MASK;
871 		break;
872 	case WLAN_DCS_SEG_SEC160:
873 		seg_mask = WLAN_DCS_SEG_SEC160_MASK;
874 		break;
875 	default:
876 		seg_mask = 0xFFFFFFFF;
877 		break;
878 	}
879 
880 	return (awgn_info->chan_bw_intf_bitmap & seg_mask);
881 }
882 
883 /**
884  * wlan_dcs_get_max_seg_idx() - get max segment index for channel width
885  * @width: channel width
886  *
887  * Return: max segment index(enum wlan_dcs_chan_seg) for the channel width.
888  */
889 static enum wlan_dcs_chan_seg wlan_dcs_get_max_seg_idx(enum phy_ch_width width)
890 {
891 	switch (width) {
892 	case CH_WIDTH_160MHZ:
893 	case CH_WIDTH_80P80MHZ:
894 		return WLAN_DCS_SEG_SEC80;
895 	case CH_WIDTH_80MHZ:
896 		return WLAN_DCS_SEG_SEC40;
897 	case CH_WIDTH_40MHZ:
898 		return WLAN_DCS_SEG_SEC20;
899 	case CH_WIDTH_20MHZ:
900 		return WLAN_DCS_SEG_PRI20;
901 	default:
902 		dcs_err("Invalid ch width %d", width);
903 		return WLAN_DCS_SEG_INVALID;
904 	}
905 }
906 
907 /**
908  * wlan_dcs_get_chan_width_for_seg() - get channel width for specified segment
909  * @seg_idx: segment index
910  *
911  * Return: channel width for segment index
912  */
913 static enum phy_ch_width
914 wlan_dcs_get_chan_width_for_seg(enum wlan_dcs_chan_seg seg_idx)
915 {
916 	switch (seg_idx) {
917 	case WLAN_DCS_SEG_SEC80:
918 		return CH_WIDTH_160MHZ;
919 	case WLAN_DCS_SEG_SEC40:
920 		return CH_WIDTH_80MHZ;
921 	case WLAN_DCS_SEG_SEC20:
922 		return CH_WIDTH_40MHZ;
923 	case WLAN_DCS_SEG_PRI20:
924 		return CH_WIDTH_20MHZ;
925 	default:
926 		dcs_err("Invalid seg idx %d", seg_idx);
927 		return CH_WIDTH_INVALID;
928 	}
929 }
930 
931 /**
932  * wlan_dcs_get_max_no_intf_bw() - get max no interference band width
933  * @awgn_info: pointer to awgn info
934  * @width: pointer to channel width
935  *
936  * This function tries to get max no interference band width according to
937  * awgn event.
938  *
939  * Return: true if valid no interference band width is found, false otherwise.
940  */
941 static bool
942 wlan_dcs_get_max_no_intf_bw(struct wlan_host_dcs_awgn_info *awgn_info,
943 			    enum phy_ch_width *width)
944 {
945 	enum wlan_dcs_chan_seg seg_idx, max_seg_idx;
946 
947 	max_seg_idx = wlan_dcs_get_max_seg_idx(awgn_info->channel_width);
948 	if (max_seg_idx == WLAN_DCS_SEG_INVALID)
949 		return false;
950 
951 	seg_idx = WLAN_DCS_SEG_PRI20;
952 	while (seg_idx <= max_seg_idx) {
953 		if (wlan_dcs_awgn_get_intf_for_seg(awgn_info, seg_idx)) {
954 			dcs_debug("Intf found for seg idx %d", seg_idx);
955 			break;
956 		}
957 		seg_idx++;
958 	}
959 
960 	/* scroll back to the last no-intf idx */
961 	seg_idx--;
962 
963 	if (seg_idx == WLAN_DCS_SEG_INVALID) {
964 		/* If pri20 contains interference, do full channel change */
965 		dcs_debug("Primary 20MHz Channel interference detected");
966 		return false;
967 	}
968 
969 	*width = wlan_dcs_get_chan_width_for_seg(seg_idx);
970 	if (*width == CH_WIDTH_160MHZ &&
971 	    awgn_info->channel_width == CH_WIDTH_80P80MHZ)
972 		*width = CH_WIDTH_80P80MHZ;
973 
974 	dcs_debug("Found the max no intf width %d", *width);
975 	return (*width != CH_WIDTH_INVALID);
976 }
977 
978 /**
979  * wlan_dcs_get_available_chan_for_bw() - get available channel for specified
980  *  band width
981  * @pdev: pdev ptr
982  * @awgn_info: pointer to awgn info
983  * @bw: channel width
984  * @freq_list: List of preferred channels
985  * @freq_num: Number of channels in the PCL
986  * @random: request for random channel
987  *
988  * Return: the selected channel frequency, 0 if no available chan is found.
989  */
990 static qdf_freq_t
991 wlan_dcs_get_available_chan_for_bw(struct wlan_objmgr_pdev *pdev,
992 				   struct wlan_host_dcs_awgn_info *awgn_info,
993 				   enum phy_ch_width bw, qdf_freq_t *freq_list,
994 				   uint32_t freq_num, bool random)
995 {
996 	int i, j = 0;
997 	uint32_t random_chan_idx;
998 	qdf_freq_t freq, selected_freq = 0;
999 	const struct bonded_channel_freq *bonded_chan_ptr = NULL;
1000 	enum channel_state state;
1001 	uint16_t chan_cfreq;
1002 	bool is_safe = true;
1003 
1004 	if (!freq_list || !freq_num)
1005 		return selected_freq;
1006 
1007 	for (i = 0; i < freq_num; i++) {
1008 		if (j && !random) {
1009 			selected_freq = freq_list[0];
1010 			dcs_debug("get the first available freq %u for bw %u",
1011 				  selected_freq, bw);
1012 			break;
1013 		}
1014 
1015 		freq = freq_list[i];
1016 		if (!WLAN_REG_IS_SAME_BAND_FREQS(freq, awgn_info->center_freq))
1017 			continue;
1018 
1019 		/*
1020 		 * DFS channel may need CAC during restart, which costs time
1021 		 * and may cause failure.
1022 		 */
1023 		if (wlan_reg_is_dfs_for_freq(pdev, freq)) {
1024 			dcs_debug("skip dfs freq %u", freq);
1025 			continue;
1026 		}
1027 
1028 		if (bonded_chan_ptr &&
1029 		    freq >= bonded_chan_ptr->start_freq &&
1030 		    freq <= bonded_chan_ptr->end_freq) {
1031 			if (is_safe) {
1032 				dcs_debug("add freq directly [%d] = %u",
1033 					  j, freq);
1034 				freq_list[j++] = freq;
1035 			}
1036 			continue;
1037 		}
1038 
1039 		state = wlan_reg_get_5g_bonded_channel_and_state_for_pwrmode(
1040 				pdev, freq, bw, &bonded_chan_ptr,
1041 				REG_CURRENT_PWR_MODE,
1042 				NO_SCHANS_PUNC);
1043 		if (state != CHANNEL_STATE_ENABLE)
1044 			continue;
1045 
1046 		/* no bonding channel for 20MHz */
1047 		if (bw == CH_WIDTH_20MHZ) {
1048 			if (WLAN_DCS_IS_FREQ_IN_WIDTH(awgn_info->center_freq,
1049 						      awgn_info->center_freq0,
1050 						      awgn_info->center_freq1,
1051 						      awgn_info->channel_width,
1052 						      freq))
1053 				continue;
1054 
1055 			dcs_debug("add freq[%d] = %u", j, freq);
1056 			freq_list[j++] = freq;
1057 			continue;
1058 		}
1059 
1060 		is_safe = true;
1061 		chan_cfreq =  bonded_chan_ptr->start_freq;
1062 		while (chan_cfreq <= bonded_chan_ptr->end_freq) {
1063 			if (WLAN_DCS_IS_FREQ_IN_WIDTH(awgn_info->center_freq,
1064 						      awgn_info->center_freq0,
1065 						      awgn_info->center_freq1,
1066 						      awgn_info->channel_width,
1067 						      chan_cfreq)) {
1068 				is_safe = false;
1069 				break;
1070 			}
1071 			chan_cfreq = chan_cfreq + 20;
1072 		}
1073 		if (is_safe) {
1074 			dcs_debug("add freq[%d] = %u", j, freq);
1075 			freq_list[j++] = freq;
1076 		}
1077 	}
1078 
1079 	if (j && random) {
1080 		qdf_get_random_bytes(&random_chan_idx, sizeof(random_chan_idx));
1081 		random_chan_idx = random_chan_idx % j;
1082 		selected_freq = freq_list[random_chan_idx];
1083 		dcs_debug("get freq[%d] = %u for bw %u",
1084 			  random_chan_idx, selected_freq, bw);
1085 	}
1086 
1087 	return selected_freq;
1088 }
1089 
1090 /**
1091  * wlan_dcs_sap_select_chan() - get available channel for sap
1092  * @vdev: vdev ptr
1093  * @awgn_info: pointer to awgn info
1094  * @tgt_freq: frequency of the selected channel
1095  * @tgt_width: band width of the selected channel
1096  * @random: request for random channel
1097  *
1098  * This function tries to get no-interference chan with max possible bandwidth
1099  * from pcl for sap according to awgn info.
1100  *
1101  * Return: true if available channel is found, false otherwise.
1102  */
1103 static bool
1104 wlan_dcs_sap_select_chan(struct wlan_objmgr_vdev *vdev,
1105 			 struct wlan_host_dcs_awgn_info *awgn_info,
1106 			 qdf_freq_t *tgt_freq, enum phy_ch_width *tgt_width,
1107 			 bool random)
1108 {
1109 	int32_t tmp_width;
1110 	qdf_freq_t tmp_freq = 0;
1111 	struct wlan_objmgr_pdev *pdev;
1112 	qdf_freq_t *freq_list;
1113 	uint32_t freq_num;
1114 
1115 	freq_list = qdf_mem_malloc(sizeof(*freq_list) * NUM_CHANNELS);
1116 	if (!freq_list)
1117 		return false;
1118 
1119 	freq_num = wlan_dcs_get_pcl_for_sap(vdev, freq_list, NUM_CHANNELS);
1120 	if (!freq_num) {
1121 		qdf_mem_free(freq_list);
1122 		return false;
1123 	}
1124 
1125 	tmp_width = awgn_info->channel_width;
1126 	pdev = wlan_vdev_get_pdev(vdev);
1127 	if (!pdev) {
1128 		qdf_mem_free(freq_list);
1129 		return false;
1130 	}
1131 
1132 	while (tmp_width >= CH_WIDTH_20MHZ) {
1133 		tmp_freq = wlan_dcs_get_available_chan_for_bw(pdev, awgn_info,
1134 							      tmp_width,
1135 							      freq_list,
1136 							      freq_num,
1137 							      random);
1138 		if (tmp_freq)
1139 			break;
1140 		tmp_width--;
1141 	}
1142 
1143 	if (tmp_freq) {
1144 		*tgt_width = tmp_width;
1145 		*tgt_freq = tmp_freq;
1146 		dcs_debug("new_width: %d new_freq %u", tmp_width, tmp_freq);
1147 
1148 		qdf_mem_free(freq_list);
1149 		return true;
1150 	}
1151 
1152 	qdf_mem_free(freq_list);
1153 	return false;
1154 }
1155 
1156 /**
1157  * wlan_dcs_is_awgnim_valid() - validate awgn info
1158  * @awgn_info: pointer to awgn info
1159  *
1160  * Return: true if valid, false otherwise.
1161  */
1162 static inline bool
1163 wlan_dcs_is_awgnim_valid(struct wlan_host_dcs_awgn_info *awgn_info)
1164 {
1165 	return (awgn_info &&
1166 		awgn_info->center_freq && awgn_info->chan_bw_intf_bitmap &&
1167 		awgn_info->channel_width != CH_WIDTH_INVALID &&
1168 		WLAN_REG_IS_6GHZ_CHAN_FREQ(awgn_info->center_freq));
1169 }
1170 
1171 /**
1172  * wlan_dcs_vdev_get_op_chan_info() - get operating channel info for vdev
1173  * @vdev: pointer to vdev object
1174  * @cfreq: Center frequency of primary channel
1175  * @cfreq0: Center frequency of segment 1
1176  * @cfreq1: Center frequency of segment 2
1177  * @ch_width: Channel width, enum phy_ch_width
1178  *
1179  * Return: QDF_STATUS
1180  */
1181 static QDF_STATUS
1182 wlan_dcs_vdev_get_op_chan_info(struct wlan_objmgr_vdev *vdev,
1183 			       qdf_freq_t *cfreq, qdf_freq_t *cfreq0,
1184 			       qdf_freq_t *cfreq1, enum phy_ch_width *ch_width)
1185 {
1186 	struct wlan_channel *chan;
1187 
1188 	if (!vdev)
1189 		return QDF_STATUS_E_INVAL;
1190 
1191 	*cfreq = 0;
1192 	*cfreq0 = 0;
1193 	*cfreq1 = 0;
1194 	*ch_width = 0;
1195 
1196 	if (wlan_vdev_mlme_is_active(vdev) != QDF_STATUS_SUCCESS)
1197 		return QDF_STATUS_E_INVAL;
1198 
1199 	chan = wlan_vdev_get_active_channel(vdev);
1200 	if (!chan)
1201 		return QDF_STATUS_E_INVAL;
1202 
1203 	*cfreq = chan->ch_freq;
1204 	*cfreq0 = chan->ch_cfreq1;
1205 	*cfreq1 = chan->ch_cfreq2;
1206 	*ch_width = chan->ch_width;
1207 
1208 	return QDF_STATUS_SUCCESS;
1209 }
1210 
1211 /**
1212  * wlan_dcs_process_awgn_sta() - process AWGN event for STA
1213  * @pdev: pointer to pdev object
1214  * @object: vdev object
1215  * @arg: Arguments to the handler
1216  *
1217  * Return: void
1218  */
1219 static void wlan_dcs_process_awgn_sta(struct wlan_objmgr_pdev *pdev,
1220 				      void *object, void *arg)
1221 {
1222 	struct wlan_objmgr_vdev *vdev = object;
1223 	struct wlan_host_dcs_awgn_info *awgn_info = arg;
1224 	enum phy_ch_width ch_width;
1225 	enum phy_ch_width tgt_width = CH_WIDTH_INVALID;
1226 	qdf_freq_t op_freq, cfreq0, cfreq1;
1227 	qdf_freq_t tgt_freq = 0;
1228 	QDF_STATUS status;
1229 	uint8_t vdev_id;
1230 	bool found;
1231 
1232 	if (!vdev || !pdev)
1233 		return;
1234 
1235 	if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE)
1236 		return;
1237 
1238 	vdev_id = wlan_vdev_get_id(vdev);
1239 	status = wlan_dcs_vdev_get_op_chan_info(vdev, &op_freq, &cfreq0,
1240 						&cfreq1, &ch_width);
1241 	if (QDF_IS_STATUS_ERROR(status))
1242 		return;
1243 
1244 	if (awgn_info->center_freq != op_freq) {
1245 		dcs_debug("STA-%d: freq not match", vdev_id);
1246 		return;
1247 	}
1248 
1249 	found = wlan_dcs_get_max_no_intf_bw(awgn_info, &tgt_width);
1250 	if (found) {
1251 		if (ch_width <= tgt_width) {
1252 			dcs_debug("STA-%d: freq and bw are unchanged", vdev_id);
1253 			return;
1254 		}
1255 
1256 		tgt_freq = op_freq;
1257 	}
1258 
1259 	/* If no width is found, means to disconnect */
1260 	dcs_debug("STA-%d: target freq %u width %u",
1261 		  vdev_id, tgt_freq, tgt_width);
1262 	wlan_dcs_switch_chan(vdev, tgt_freq, tgt_width);
1263 }
1264 
1265 /**
1266  * wlan_dcs_process_awgn_sap() - process AWGN event for SAP
1267  * @pdev: pointer to pdev object
1268  * @object: vdev object
1269  * @arg: Arguments to the handler
1270  *
1271  * Return: void
1272  */
1273 static void wlan_dcs_process_awgn_sap(struct wlan_objmgr_pdev *pdev,
1274 				      void *object, void *arg)
1275 {
1276 	struct wlan_objmgr_vdev *vdev = object;
1277 	struct wlan_host_dcs_awgn_info *awgn_info = arg;
1278 	enum phy_ch_width ch_width;
1279 	enum phy_ch_width tgt_width = CH_WIDTH_INVALID;
1280 	qdf_freq_t op_freq, cfreq0, cfreq1;
1281 	qdf_freq_t tgt_freq = 0;
1282 	QDF_STATUS status;
1283 	uint8_t vdev_id;
1284 	bool found;
1285 
1286 	if (!vdev || !pdev)
1287 		return;
1288 
1289 	if (wlan_vdev_mlme_get_opmode(vdev) != QDF_SAP_MODE)
1290 		return;
1291 
1292 	vdev_id = wlan_vdev_get_id(vdev);
1293 	status = wlan_dcs_vdev_get_op_chan_info(vdev, &op_freq, &cfreq0, &cfreq1, &ch_width);
1294 	if (QDF_IS_STATUS_ERROR(status))
1295 		return;
1296 
1297 	if (awgn_info->center_freq != op_freq) {
1298 		dcs_debug("SAP-%d: freq not match rpt:%u - op:%u",
1299 			  vdev_id, awgn_info->center_freq, op_freq);
1300 		return;
1301 	}
1302 
1303 	found = wlan_dcs_get_max_no_intf_bw(awgn_info, &tgt_width);
1304 	if (found) {
1305 		if (ch_width <= tgt_width) {
1306 			dcs_debug("SAP-%d: both freq and bw are unchanged",
1307 				  vdev_id);
1308 			return;
1309 		}
1310 
1311 		tgt_freq = op_freq;
1312 	} else {
1313 		wlan_dcs_sap_select_chan(vdev, awgn_info, &tgt_freq,
1314 					 &tgt_width, true);
1315 	}
1316 
1317 	/* If no chan is selected, means to stop sap */
1318 	dcs_debug("SAP-%d: target freq %u width %u",
1319 		  vdev_id, tgt_freq, tgt_width);
1320 	wlan_dcs_switch_chan(vdev, tgt_freq, tgt_width);
1321 }
1322 
1323 /**
1324  * wlan_dcs_awgn_process() - process awgn IM
1325  * @psoc: psoc ptr
1326  * @pdev_id: pdev id
1327  * @awgn_info: pointer to awgn info
1328  *
1329  * This function triggers channel change for all STAs and SAPs, according
1330  * to AWGN info.
1331  *
1332  * Return: None.
1333  */
1334 static void
1335 wlan_dcs_awgn_process(struct wlan_objmgr_psoc *psoc, uint8_t pdev_id,
1336 		      struct wlan_host_dcs_awgn_info *awgn_info)
1337 {
1338 	struct wlan_objmgr_pdev *pdev;
1339 
1340 	if (!wlan_dcs_is_awgnim_valid(awgn_info)) {
1341 		dcs_err("Invalid awgnim event");
1342 		return;
1343 	}
1344 
1345 	pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_DCS_ID);
1346 	if (!pdev) {
1347 		dcs_err("Invalid pdev id %d", pdev_id);
1348 		return;
1349 	}
1350 
1351 	dcs_debug("pdev id %u width %u freq %u freq0 %u fre1 %u bitmap 0x%x",
1352 		  pdev_id, awgn_info->channel_width, awgn_info->center_freq,
1353 		  awgn_info->center_freq0, awgn_info->center_freq1,
1354 		  awgn_info->chan_bw_intf_bitmap);
1355 
1356 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
1357 					  wlan_dcs_process_awgn_sta,
1358 					  awgn_info, 0, WLAN_DCS_ID);
1359 
1360 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
1361 					  wlan_dcs_process_awgn_sap,
1362 					  awgn_info, 0, WLAN_DCS_ID);
1363 
1364 	wlan_objmgr_pdev_release_ref(pdev, WLAN_DCS_ID);
1365 }
1366 
1367 #ifdef CONFIG_AFC_SUPPORT
1368 /**
1369  * wlan_dcs_afc_sel_chan() - Select SAP new channel/bandwidth when AFC updated
1370  * @psoc: pointer to soc
1371  * @vdev_id: vdev id
1372  * @cur_freq: current channel frequency
1373  * @cur_bw: current channel bandwidth
1374  * @pref_bw: pointer to bandwidth of prefer to switch to when input, and target
1375  *           bandwidth decided to switch to
1376  *
1377  * Return: target channel frequency to switch to
1378  */
1379 static qdf_freq_t wlan_dcs_afc_sel_chan(struct wlan_objmgr_psoc *psoc,
1380 					uint32_t vdev_id,
1381 					qdf_freq_t cur_freq,
1382 					enum phy_ch_width cur_bw,
1383 					enum phy_ch_width *pref_bw)
1384 {
1385 	struct dcs_psoc_priv_obj *dcs_psoc_priv;
1386 	dcs_afc_select_chan_cb afc_sel_chan_cb;
1387 
1388 	if (!psoc)
1389 		return 0;
1390 
1391 	dcs_psoc_priv = wlan_objmgr_psoc_get_comp_private_obj(
1392 			psoc,
1393 			WLAN_UMAC_COMP_DCS);
1394 	if (!dcs_psoc_priv)
1395 		return 0;
1396 
1397 	afc_sel_chan_cb = dcs_psoc_priv->afc_sel_chan_cbk.cbk;
1398 	if (!afc_sel_chan_cb)
1399 		return 0;
1400 
1401 	return afc_sel_chan_cb(dcs_psoc_priv->afc_sel_chan_cbk.arg,
1402 			       vdev_id, cur_freq, cur_bw, pref_bw);
1403 }
1404 
1405 /**
1406  * wlan_dcs_afc_get_conn_info() - Iterate function to get connection channel
1407  *                                information of every vdev
1408  * @pdev: pointer to pdev
1409  * @object: pointer to iteration object
1410  * @arg: pointer to iteration argument
1411  *
1412  * Return: void
1413  */
1414 static void
1415 wlan_dcs_afc_get_conn_info(struct wlan_objmgr_pdev *pdev,
1416 			   void *object, void *arg)
1417 {
1418 	struct wlan_objmgr_vdev *vdev = object;
1419 	struct wlan_dcs_conn_info *conn_info = arg;
1420 	enum QDF_OPMODE op_mode;
1421 	struct wlan_channel *chan;
1422 	uint8_t vdev_id;
1423 
1424 	if (!vdev || !pdev || !conn_info)
1425 		return;
1426 
1427 	if (conn_info->exit_condition)
1428 		return;
1429 
1430 	if (wlan_vdev_mlme_is_active(vdev) != QDF_STATUS_SUCCESS)
1431 		return;
1432 
1433 	vdev_id = wlan_vdev_get_id(vdev);
1434 	op_mode = wlan_vdev_mlme_get_opmode(vdev);
1435 	chan = wlan_vdev_get_active_channel(vdev);
1436 	if (!chan)
1437 		return;
1438 
1439 	switch (op_mode) {
1440 	case QDF_STA_MODE:
1441 		if (conn_info->sta_cnt >= WLAN_DCS_MAX_STA_NUM) {
1442 			dcs_debug("too many STAs");
1443 			conn_info->exit_condition = true;
1444 			break;
1445 		}
1446 		conn_info->sta[conn_info->sta_cnt].freq = chan->ch_freq;
1447 		conn_info->sta[conn_info->sta_cnt].bw = chan->ch_width;
1448 		conn_info->sta[conn_info->sta_cnt].vdev_id = vdev_id;
1449 		conn_info->sta_cnt++;
1450 		break;
1451 	case QDF_SAP_MODE:
1452 		if (WLAN_REG_IS_5GHZ_CH_FREQ(chan->ch_freq)) {
1453 			if (conn_info->sap_5ghz_cnt >= WLAN_DCS_MAX_SAP_NUM) {
1454 				dcs_debug("too many 5 GHz SAPs");
1455 				conn_info->exit_condition = true;
1456 			}
1457 			conn_info->sap_5ghz[conn_info->sap_5ghz_cnt].freq =
1458 				chan->ch_freq;
1459 			conn_info->sap_5ghz[conn_info->sap_5ghz_cnt].bw =
1460 				chan->ch_width;
1461 			conn_info->sap_5ghz[conn_info->sap_5ghz_cnt].vdev_id =
1462 				vdev_id;
1463 			conn_info->sap_5ghz_cnt++;
1464 		} else if (WLAN_REG_IS_6GHZ_CHAN_FREQ(chan->ch_freq)) {
1465 			if (conn_info->sap_6ghz_cnt >= WLAN_DCS_MAX_SAP_NUM) {
1466 				dcs_debug("too many 6 GHz SAPs");
1467 				conn_info->exit_condition = true;
1468 			}
1469 			conn_info->sap_6ghz[conn_info->sap_6ghz_cnt].freq =
1470 				chan->ch_freq;
1471 			conn_info->sap_6ghz[conn_info->sap_6ghz_cnt].bw =
1472 				chan->ch_width;
1473 			conn_info->sap_6ghz[conn_info->sap_6ghz_cnt].vdev_id =
1474 				vdev_id;
1475 			conn_info->sap_6ghz_cnt++;
1476 		}
1477 		break;
1478 	default:
1479 		dcs_debug("not support op mode %d", op_mode);
1480 		conn_info->exit_condition = true;
1481 		break;
1482 	}
1483 }
1484 
1485 /**
1486  * wlan_dcs_afc_reduce_bw() - Get target bandwidth with fixed channel frequency
1487  * @pdev: pointer to pdev
1488  * @freq: channel frequency which is fixed because SCC with STA
1489  * @input_bw: SAP current channel bandwidth
1490  *
1491  * This function check every sub 20 MHz channel state which update by AFC, and
1492  * reduce channel bandwidth if sub channel is disable.
1493  *
1494  * Return: Reduced channel bandwidth
1495  */
1496 static enum phy_ch_width wlan_dcs_afc_reduce_bw(struct wlan_objmgr_pdev *pdev,
1497 						qdf_freq_t freq,
1498 						enum phy_ch_width input_bw)
1499 {
1500 	const struct bonded_channel_freq *bonded_chan_ptr = NULL;
1501 	enum channel_state state;
1502 	qdf_freq_t start_freq;
1503 	bool find;
1504 
1505 	if (input_bw <= CH_WIDTH_20MHZ)
1506 		return input_bw;
1507 
1508 	while (input_bw > CH_WIDTH_20MHZ) {
1509 		state = wlan_reg_get_5g_bonded_channel_and_state_for_pwrmode(
1510 				pdev, freq, input_bw, &bonded_chan_ptr,
1511 				REG_CURRENT_PWR_MODE, NO_SCHANS_PUNC);
1512 		if (state != CHANNEL_STATE_ENABLE) {
1513 			input_bw = wlan_reg_get_next_lower_bandwidth(input_bw);
1514 			continue;
1515 		}
1516 		find = false;
1517 		start_freq = bonded_chan_ptr->start_freq;
1518 		while (start_freq <= bonded_chan_ptr->end_freq) {
1519 			if (wlan_reg_is_disable_in_secondary_list_for_freq(
1520 					pdev, start_freq)) {
1521 				find = true;
1522 				break;
1523 			}
1524 			start_freq += 20;
1525 		}
1526 		if (find)
1527 			input_bw = wlan_reg_get_next_lower_bandwidth(input_bw);
1528 		else
1529 			return input_bw;
1530 	}
1531 	return input_bw;
1532 }
1533 
1534 /**
1535  * wlan_sap_update_tpc_on_channel() - Update vdev channel TPC parameters and
1536  *                                    send TPC command
1537  * @pdev: pointer to pdev
1538  * @vdev_id: vdev id
1539  * @freq: SAP 6 GHz channel frequency
1540  * @bw: SAP 6 GHz channel bandwidth
1541  *
1542  * Return: void
1543  */
1544 static void
1545 wlan_sap_update_tpc_on_channel(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id,
1546 			       qdf_freq_t freq, enum phy_ch_width bw)
1547 {
1548 	struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev);
1549 	struct wlan_lmac_if_reg_tx_ops *tx_ops;
1550 	struct vdev_mlme_obj *mlme_obj;
1551 	struct wlan_objmgr_vdev *vdev;
1552 	struct reg_tpc_power_info *tpc;
1553 	bool is_psd;
1554 	uint32_t i;
1555 	uint16_t tx_power;
1556 	int16_t psd_eirp;
1557 	enum reg_6g_ap_type power_type;
1558 
1559 	if (!wlan_reg_is_ext_tpc_supported(psoc))
1560 		return;
1561 
1562 	if (wlan_reg_decide_6ghz_power_within_bw_for_freq(
1563 		pdev, freq, bw, &is_psd, &tx_power, &psd_eirp, &power_type,
1564 		REG_CURRENT_PWR_MODE, NO_SCHANS_PUNC) !=
1565 	    QDF_STATUS_SUCCESS)
1566 		return;
1567 
1568 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_DCS_ID);
1569 	if (!vdev)
1570 		return;
1571 
1572 	tx_ops = wlan_reg_get_tx_ops(psoc);
1573 
1574 	mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev);
1575 	if (!mlme_obj) {
1576 		dcs_err("vdev mlme obj is NULL");
1577 		goto release_vdev;
1578 	}
1579 
1580 	tpc = &mlme_obj->reg_tpc_obj;
1581 	if (tpc->is_psd_power != is_psd) {
1582 		dcs_debug("psd flag changed");
1583 		goto release_vdev;
1584 	}
1585 	tpc->eirp_power = tx_power;
1586 	tpc->power_type_6g = power_type;
1587 	for (i = 0; i < tpc->num_pwr_levels; i++) {
1588 		if (is_psd)
1589 			tpc->chan_power_info[i].tx_power = (uint8_t)psd_eirp;
1590 		else
1591 			tpc->chan_power_info[i].tx_power = (uint8_t)tx_power;
1592 	}
1593 
1594 	dcs_debug("6 GHz pwr type %d, is psd %d, pwr %d, psd %d, num pwr %d",
1595 		  power_type, is_psd, tx_power, psd_eirp, tpc->num_pwr_levels);
1596 
1597 	if (tx_ops->set_tpc_power)
1598 		tx_ops->set_tpc_power(psoc, vdev_id, tpc);
1599 
1600 release_vdev:
1601 	wlan_objmgr_vdev_release_ref(vdev, WLAN_DCS_ID);
1602 }
1603 
1604 /**
1605  * wlan_dcs_afc_sap_dcs_with_sta() - SAP channel switch when coexist with STA
1606  * @pdev: pointer to pdev handle
1607  * @conn_info: pointer to connection context of AFC DCS
1608  *
1609  * This function update TPC or restart SAP if doing SCC on 6 GHz with STA
1610  *
1611  * Return: void
1612  */
1613 static void
1614 wlan_dcs_afc_sap_dcs_with_sta(struct wlan_objmgr_pdev *pdev,
1615 			      struct wlan_dcs_conn_info *conn_info)
1616 {
1617 	uint32_t i;
1618 	qdf_freq_t target_freq = conn_info->sta[0].freq;
1619 	enum phy_ch_width target_bw = CH_WIDTH_20MHZ;
1620 	struct wlan_objmgr_vdev *vdev;
1621 
1622 	if (!WLAN_REG_IS_6GHZ_CHAN_FREQ(conn_info->sta[0].freq))
1623 		return;
1624 
1625 	for (i = 0; i < conn_info->sap_6ghz_cnt; i++) {
1626 		if (conn_info->sap_6ghz[i].freq ==
1627 		    conn_info->sta[0].freq) {
1628 			/*
1629 			 * sta operate under control of ap, if stop sap,
1630 			 * cannot start by itself, so just update tpc as sta,
1631 			 * if tx power is minimum of SCC tpc commands, no
1632 			 * need to update sap tpc command.
1633 			 * assume sta will move to safe channel by ap and
1634 			 * sap can move channel accordingly.
1635 			 */
1636 			if (wlan_reg_is_disable_in_secondary_list_for_freq(
1637 					pdev, conn_info->sta[0].freq))
1638 				continue;
1639 
1640 			target_bw = wlan_dcs_afc_reduce_bw(
1641 					pdev,
1642 					conn_info->sap_6ghz[i].freq,
1643 					conn_info->sap_6ghz[i].bw);
1644 
1645 			if (target_bw == conn_info->sap_6ghz[i].bw) {
1646 				wlan_sap_update_tpc_on_channel(
1647 					pdev,
1648 					conn_info->sap_6ghz[i].vdev_id,
1649 					conn_info->sap_6ghz[i].freq,
1650 					target_bw);
1651 				continue;
1652 			}
1653 
1654 			vdev = wlan_objmgr_get_vdev_by_id_from_pdev(
1655 					pdev,
1656 					conn_info->sap_6ghz[i].vdev_id,
1657 					WLAN_DCS_ID);
1658 			if (!vdev)
1659 				continue;
1660 
1661 			/* tpc update once csa complete */
1662 			wlan_dcs_switch_chan(vdev, target_freq, target_bw);
1663 			wlan_objmgr_vdev_release_ref(vdev, WLAN_DCS_ID);
1664 		}
1665 	}
1666 }
1667 
1668 #ifdef WLAN_POLICY_MGR_ENABLE
1669 /**
1670  * wlan_dcs_afc_6ghz_capable() - API to check SAP configure is able to operate
1671  *                               on 6 GHz
1672  * @psoc: pointer to SOC
1673  * @vdev_id: vdev id
1674  *
1675  * Return: Return true if SAP is able to operate on 6 GHz
1676  */
1677 static inline bool
1678 wlan_dcs_afc_6ghz_capable(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
1679 {
1680 	return policy_mgr_get_ap_6ghz_capable(psoc, vdev_id, NULL);
1681 }
1682 #else
1683 static inline bool
1684 wlan_dcs_afc_6ghz_capable(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id)
1685 {
1686 	return false;
1687 }
1688 #endif
1689 
1690 /**
1691  * wlan_dcs_afc_5ghz6ghz_sap_dcs() - SAP on 5 GHz or 6 GHz channel to do
1692  * channel switch.
1693  * @pdev: pointer to pdev handle
1694  * @conn_info: pointer to connection context for AFC DCS
1695  *
1696  * This function is trigger by AFC event and 6 GHz channels' state has been
1697  * updated, restart SAP to SP channel if possible, gain better performance.
1698  *
1699  * Return: void
1700  */
1701 static void
1702 wlan_dcs_afc_5ghz6ghz_sap_dcs(struct wlan_objmgr_pdev *pdev,
1703 			      struct wlan_dcs_conn_info *conn_info)
1704 {
1705 	uint32_t i;
1706 	struct wlan_objmgr_vdev *vdev;
1707 	uint8_t max_bw_vdev_id;
1708 	qdf_freq_t max_bw_freq, target_freq;
1709 	enum phy_ch_width max_bw = CH_WIDTH_20MHZ;
1710 	enum phy_ch_width pref_bw;
1711 
1712 	if (conn_info->sap_5ghz_cnt) {
1713 		max_bw = conn_info->sap_5ghz[0].bw;
1714 		max_bw_vdev_id = conn_info->sap_5ghz[0].vdev_id;
1715 		max_bw_freq = conn_info->sap_5ghz[0].freq;
1716 		for (i = 1; i < conn_info->sap_5ghz_cnt; i++) {
1717 			if (conn_info->sap_5ghz[i].bw > max_bw) {
1718 				max_bw = conn_info->sap_5ghz[i].bw;
1719 				max_bw_vdev_id = conn_info->sap_5ghz[i].vdev_id;
1720 				max_bw_freq = conn_info->sap_5ghz[i].freq;
1721 			}
1722 		}
1723 	} else if (conn_info->sap_6ghz_cnt) {
1724 		max_bw = conn_info->sap_6ghz[0].bw;
1725 		max_bw_vdev_id = conn_info->sap_6ghz[0].vdev_id;
1726 		max_bw_freq = conn_info->sap_6ghz[0].freq;
1727 		for (i = 1; i < conn_info->sap_6ghz_cnt; i++) {
1728 			if (conn_info->sap_6ghz[i].bw > max_bw) {
1729 				max_bw = conn_info->sap_6ghz[i].bw;
1730 				max_bw_vdev_id = conn_info->sap_6ghz[i].vdev_id;
1731 				max_bw_freq = conn_info->sap_6ghz[i].freq;
1732 			}
1733 		}
1734 	} else {
1735 		return;
1736 	}
1737 
1738 	/*
1739 	 * After several AFC event update, if maximum bandwidth shrink to
1740 	 * 20 MHz, set prefer bandwidth to pre-defined value like 80 MHz,
1741 	 * so it can expand bandwidth and gain better performance.
1742 	 */
1743 	if (max_bw == CH_WIDTH_20MHZ)
1744 		pref_bw = WLAN_DCS_AFC_PREFER_BW;
1745 	else
1746 		pref_bw = max_bw;
1747 
1748 	target_freq = wlan_dcs_afc_sel_chan(
1749 			wlan_pdev_get_psoc(pdev),
1750 			max_bw_vdev_id,
1751 			max_bw_freq, max_bw, &pref_bw);
1752 
1753 	if (!target_freq)
1754 		return;
1755 
1756 	if (WLAN_REG_IS_6GHZ_CHAN_FREQ(target_freq) &&
1757 	    conn_info->sap_5ghz_cnt) {
1758 		for (i = 0; i < conn_info->sap_5ghz_cnt; i++) {
1759 			if (!wlan_dcs_afc_6ghz_capable(
1760 			    wlan_pdev_get_psoc(pdev),
1761 			    conn_info->sap_5ghz[i].vdev_id)) {
1762 				dcs_debug("vdev %d has no 6 GHz capability",
1763 					  conn_info->sap_5ghz[i].vdev_id);
1764 				return;
1765 			}
1766 		}
1767 	}
1768 
1769 	if (conn_info->sap_5ghz_cnt) {
1770 		for (i = 0; i < conn_info->sap_5ghz_cnt; i++) {
1771 			if (target_freq == conn_info->sap_5ghz[i].freq &&
1772 			    pref_bw == conn_info->sap_5ghz[i].bw)
1773 				continue;
1774 			vdev = wlan_objmgr_get_vdev_by_id_from_pdev(
1775 					pdev,
1776 					conn_info->sap_5ghz[i].vdev_id,
1777 					WLAN_DCS_ID);
1778 			if (!vdev)
1779 				continue;
1780 
1781 			wlan_dcs_switch_chan(vdev, target_freq, pref_bw);
1782 			wlan_objmgr_vdev_release_ref(vdev, WLAN_DCS_ID);
1783 		}
1784 	} else if (conn_info->sap_6ghz_cnt) {
1785 		for (i = 0; i < conn_info->sap_6ghz_cnt; i++) {
1786 			if (target_freq == conn_info->sap_6ghz[i].freq &&
1787 			    pref_bw == conn_info->sap_6ghz[i].bw)
1788 				continue;
1789 			vdev = wlan_objmgr_get_vdev_by_id_from_pdev(
1790 					pdev,
1791 					conn_info->sap_6ghz[i].vdev_id,
1792 					WLAN_DCS_ID);
1793 			if (!vdev)
1794 				continue;
1795 
1796 			wlan_dcs_switch_chan(vdev, target_freq, pref_bw);
1797 			wlan_objmgr_vdev_release_ref(vdev, WLAN_DCS_ID);
1798 		}
1799 	}
1800 }
1801 
1802 /**
1803  * wlan_dcs_afc_process() - Dynamic SAP channel switch after AFC update
1804  * @psoc: psoc handle
1805  * @pdev_id: pdev id
1806  *
1807  * Return: void
1808  */
1809 static void
1810 wlan_dcs_afc_process(struct wlan_objmgr_psoc *psoc, uint8_t pdev_id)
1811 {
1812 	struct wlan_objmgr_pdev *pdev;
1813 	struct wlan_dcs_conn_info conn_info = {0};
1814 
1815 	pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_DCS_ID);
1816 	if (!pdev) {
1817 		dcs_err("Invalid pdev id %d", pdev_id);
1818 		return;
1819 	}
1820 
1821 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
1822 					  wlan_dcs_afc_get_conn_info,
1823 					  &conn_info, 0, WLAN_DCS_ID);
1824 	if (conn_info.exit_condition)
1825 		goto pdev_release;
1826 
1827 	if ((conn_info.sap_5ghz_cnt && conn_info.sap_6ghz_cnt) ||
1828 	    (!conn_info.sap_5ghz_cnt && !conn_info.sap_6ghz_cnt)) {
1829 		dcs_debug("NA for %d 5 GHz SAP, %d 6 GHz SAP",
1830 			  conn_info.sap_5ghz_cnt, conn_info.sap_6ghz_cnt);
1831 		goto pdev_release;
1832 	}
1833 
1834 	if (conn_info.sta_cnt &&
1835 	    !WLAN_REG_IS_24GHZ_CH_FREQ(conn_info.sta[0].freq))
1836 		wlan_dcs_afc_sap_dcs_with_sta(pdev, &conn_info);
1837 	else
1838 		wlan_dcs_afc_5ghz6ghz_sap_dcs(pdev, &conn_info);
1839 
1840 pdev_release:
1841 	wlan_objmgr_pdev_release_ref(pdev, WLAN_DCS_ID);
1842 }
1843 #else
1844 static inline void
1845 wlan_dcs_afc_process(struct wlan_objmgr_psoc *psoc, uint8_t pdev_id) {}
1846 #endif
1847 
1848 QDF_STATUS
1849 wlan_dcs_process(struct wlan_objmgr_psoc *psoc,
1850 		 struct wlan_host_dcs_event *event)
1851 {
1852 	struct dcs_pdev_priv_obj *dcs_pdev_priv;
1853 	bool start_dcs_cbk_handler = false;
1854 
1855 	if (!psoc || !event) {
1856 		dcs_err("psoc or event is NULL");
1857 		return QDF_STATUS_E_INVAL;
1858 	}
1859 
1860 	dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc,
1861 						      event->dcs_param.pdev_id);
1862 	if (!dcs_pdev_priv) {
1863 		dcs_err("dcs pdev private object is null");
1864 		return QDF_STATUS_E_INVAL;
1865 	}
1866 
1867 	if (unlikely(dcs_pdev_priv->dcs_host_params.dcs_debug
1868 			>= DCS_DEBUG_VERBOSE))
1869 		dcs_debug("dcs_enable: %u, interference_type: %u, pdev_id: %u",
1870 			  dcs_pdev_priv->dcs_host_params.dcs_enable,
1871 			  event->dcs_param.interference_type,
1872 			  event->dcs_param.pdev_id);
1873 
1874 	switch (event->dcs_param.interference_type) {
1875 	case WLAN_HOST_DCS_CWIM:
1876 		break;
1877 	case WLAN_HOST_DCS_WLANIM:
1878 		if (!dcs_pdev_priv->dcs_host_params.dcs_enable)
1879 			break;
1880 
1881 		if (dcs_pdev_priv->dcs_host_params.dcs_enable &
1882 		    WLAN_HOST_DCS_WLANIM)
1883 			start_dcs_cbk_handler =
1884 				wlan_dcs_wlan_interference_process(
1885 							&event->wlan_stat,
1886 							dcs_pdev_priv);
1887 		if (dcs_pdev_priv->user_cb &&
1888 		    dcs_pdev_priv->dcs_host_params.notify_user) {
1889 			dcs_pdev_priv->dcs_host_params.notify_user = 0;
1890 			dcs_pdev_priv->user_cb(dcs_pdev_priv->requestor_vdev_id,
1891 				 &dcs_pdev_priv->dcs_im_stats.user_dcs_im_stats,
1892 				 0);
1893 		}
1894 		if (start_dcs_cbk_handler)
1895 			wlan_dcs_frequency_control(psoc,
1896 						   dcs_pdev_priv,
1897 						   event);
1898 		break;
1899 	case WLAN_HOST_DCS_AWGNIM:
1900 		/* Skip frequency control for AWGNIM */
1901 		wlan_dcs_awgn_process(psoc, event->dcs_param.pdev_id,
1902 				      &event->awgn_info);
1903 		break;
1904 	case WLAN_HOST_DCS_AFC:
1905 		wlan_dcs_afc_process(psoc, event->dcs_param.pdev_id);
1906 		break;
1907 	default:
1908 		dcs_err("unidentified interference type reported");
1909 		break;
1910 	}
1911 
1912 	return QDF_STATUS_SUCCESS;
1913 }
1914 
1915 void wlan_dcs_clear(struct wlan_objmgr_psoc *psoc, uint32_t pdev_id)
1916 {
1917 	struct dcs_pdev_priv_obj *dcs_pdev_priv;
1918 
1919 	if (!psoc) {
1920 		dcs_err("psoc is null");
1921 		return;
1922 	}
1923 
1924 	dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc, pdev_id);
1925 	if (!dcs_pdev_priv) {
1926 		dcs_err("dcs pdev private object is null");
1927 		return;
1928 	}
1929 
1930 	qdf_timer_stop(&dcs_pdev_priv->dcs_disable_timer);
1931 	qdf_mem_set(&dcs_pdev_priv->dcs_im_stats,
1932 		    sizeof(dcs_pdev_priv->dcs_im_stats), 0);
1933 	qdf_mem_set(dcs_pdev_priv->dcs_freq_ctrl_params.timestamp,
1934 		    MAX_DCS_TIME_RECORD * sizeof(unsigned long), 0);
1935 	dcs_pdev_priv->dcs_freq_ctrl_params.dcs_happened_count = 0;
1936 	dcs_pdev_priv->dcs_freq_ctrl_params.disable_delay_process = false;
1937 	wlan_dcs_set_algorithm_process(psoc, pdev_id, false);
1938 }
1939 
1940 void wlan_dcs_set_algorithm_process(struct wlan_objmgr_psoc *psoc,
1941 				    uint32_t pdev_id,
1942 				    bool dcs_algorithm_process)
1943 {
1944 	struct dcs_pdev_priv_obj *dcs_pdev_priv;
1945 
1946 	dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc, pdev_id);
1947 	if (!dcs_pdev_priv) {
1948 		dcs_err("dcs pdev private object is null");
1949 		return;
1950 	}
1951 
1952 	if (dcs_pdev_priv->dcs_host_params.force_disable_algorithm) {
1953 		dcs_debug("dcs algorithm is disabled forcely");
1954 		dcs_pdev_priv->dcs_host_params.dcs_algorithm_process = false;
1955 		return;
1956 	}
1957 
1958 	dcs_pdev_priv->dcs_host_params.dcs_algorithm_process =
1959 							dcs_algorithm_process;
1960 }
1961