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