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