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