1*5113495bSYour Name /*
2*5113495bSYour Name * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
3*5113495bSYour Name * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name *
5*5113495bSYour Name * Permission to use, copy, modify, and/or distribute this software for any
6*5113495bSYour Name * purpose with or without fee is hereby granted, provided that the above
7*5113495bSYour Name * copyright notice and this permission notice appear in all copies.
8*5113495bSYour Name *
9*5113495bSYour Name * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10*5113495bSYour Name * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*5113495bSYour Name * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12*5113495bSYour Name * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*5113495bSYour Name * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14*5113495bSYour Name * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15*5113495bSYour Name * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16*5113495bSYour Name */
17*5113495bSYour Name
18*5113495bSYour Name /**
19*5113495bSYour Name * DOC: wlan_hdd_dcs.c
20*5113495bSYour Name *
21*5113495bSYour Name * DCS implementation.
22*5113495bSYour Name *
23*5113495bSYour Name */
24*5113495bSYour Name
25*5113495bSYour Name #include <wlan_hdd_hostapd.h>
26*5113495bSYour Name #include <wlan_hdd_dcs.h>
27*5113495bSYour Name #include <wlan_hdd_includes.h>
28*5113495bSYour Name #include <wlan_dcs_ucfg_api.h>
29*5113495bSYour Name #include <wlan_dlm_ucfg_api.h>
30*5113495bSYour Name #include <wlan_osif_priv.h>
31*5113495bSYour Name #include <wlan_objmgr_vdev_obj.h>
32*5113495bSYour Name #include <wlan_dcs_ucfg_api.h>
33*5113495bSYour Name
34*5113495bSYour Name /* Time(in milliseconds) before which the AP doesn't expect a connection */
35*5113495bSYour Name #define HDD_DCS_AWGN_BSS_RETRY_DELAY (5 * 60 * 1000)
36*5113495bSYour Name
37*5113495bSYour Name /**
38*5113495bSYour Name * hdd_dcs_add_bssid_to_reject_list() - add bssid to reject list
39*5113495bSYour Name * @pdev: pdev ptr
40*5113495bSYour Name * @bssid: bssid to be added
41*5113495bSYour Name *
42*5113495bSYour Name * Return: QDF_STATUS
43*5113495bSYour Name */
44*5113495bSYour Name static QDF_STATUS
hdd_dcs_add_bssid_to_reject_list(struct wlan_objmgr_pdev * pdev,struct qdf_mac_addr * bssid)45*5113495bSYour Name hdd_dcs_add_bssid_to_reject_list(struct wlan_objmgr_pdev *pdev,
46*5113495bSYour Name struct qdf_mac_addr *bssid)
47*5113495bSYour Name {
48*5113495bSYour Name struct reject_ap_info ap_info;
49*5113495bSYour Name
50*5113495bSYour Name qdf_mem_zero(&ap_info, sizeof(struct reject_ap_info));
51*5113495bSYour Name qdf_copy_macaddr(&ap_info.bssid, bssid);
52*5113495bSYour Name /* set retry_delay to reject new connect requests */
53*5113495bSYour Name ap_info.rssi_reject_params.retry_delay =
54*5113495bSYour Name HDD_DCS_AWGN_BSS_RETRY_DELAY;
55*5113495bSYour Name ap_info.reject_ap_type = DRIVER_RSSI_REJECT_TYPE;
56*5113495bSYour Name ap_info.reject_reason = REASON_STA_KICKOUT;
57*5113495bSYour Name ap_info.source = ADDED_BY_DRIVER;
58*5113495bSYour Name return ucfg_dlm_add_bssid_to_reject_list(pdev, &ap_info);
59*5113495bSYour Name }
60*5113495bSYour Name
61*5113495bSYour Name /**
62*5113495bSYour Name * hdd_dcs_switch_chan_cb() - hdd dcs switch channel callback
63*5113495bSYour Name * @vdev: vdev ptr
64*5113495bSYour Name * @tgt_freq: target channel frequency
65*5113495bSYour Name * @tgt_width: target channel width
66*5113495bSYour Name *
67*5113495bSYour Name * This callback is registered with dcs component to trigger channel switch.
68*5113495bSYour Name *
69*5113495bSYour Name * Return: QDF_STATUS
70*5113495bSYour Name */
hdd_dcs_switch_chan_cb(struct wlan_objmgr_vdev * vdev,qdf_freq_t tgt_freq,enum phy_ch_width tgt_width)71*5113495bSYour Name static QDF_STATUS hdd_dcs_switch_chan_cb(struct wlan_objmgr_vdev *vdev,
72*5113495bSYour Name qdf_freq_t tgt_freq,
73*5113495bSYour Name enum phy_ch_width tgt_width)
74*5113495bSYour Name {
75*5113495bSYour Name struct hdd_adapter *adapter;
76*5113495bSYour Name struct wlan_hdd_link_info *link_info;
77*5113495bSYour Name mac_handle_t mac_handle;
78*5113495bSYour Name struct qdf_mac_addr *bssid;
79*5113495bSYour Name int ret;
80*5113495bSYour Name QDF_STATUS status = QDF_STATUS_SUCCESS;
81*5113495bSYour Name struct wlan_objmgr_pdev *pdev;
82*5113495bSYour Name struct wlan_objmgr_psoc *psoc;
83*5113495bSYour Name
84*5113495bSYour Name link_info = wlan_hdd_get_link_info_from_objmgr(vdev);
85*5113495bSYour Name if (!link_info) {
86*5113495bSYour Name hdd_err("Invalid vdev %d", wlan_vdev_get_id(vdev));
87*5113495bSYour Name return QDF_STATUS_E_INVAL;
88*5113495bSYour Name }
89*5113495bSYour Name
90*5113495bSYour Name adapter = link_info->adapter;
91*5113495bSYour Name switch (adapter->device_mode) {
92*5113495bSYour Name case QDF_STA_MODE:
93*5113495bSYour Name if (!hdd_cm_is_vdev_associated(link_info))
94*5113495bSYour Name return QDF_STATUS_E_INVAL;
95*5113495bSYour Name
96*5113495bSYour Name bssid = &link_info->session.station.conn_info.bssid;
97*5113495bSYour Name
98*5113495bSYour Name /* disconnect if got invalid freq or width */
99*5113495bSYour Name if (tgt_freq == 0 || tgt_width == CH_WIDTH_INVALID) {
100*5113495bSYour Name pdev = wlan_vdev_get_pdev(vdev);
101*5113495bSYour Name if (!pdev)
102*5113495bSYour Name return QDF_STATUS_E_INVAL;
103*5113495bSYour Name
104*5113495bSYour Name hdd_dcs_add_bssid_to_reject_list(pdev, bssid);
105*5113495bSYour Name wlan_hdd_cm_issue_disconnect(link_info,
106*5113495bSYour Name REASON_UNSPEC_FAILURE,
107*5113495bSYour Name true);
108*5113495bSYour Name return QDF_STATUS_SUCCESS;
109*5113495bSYour Name }
110*5113495bSYour Name
111*5113495bSYour Name mac_handle = hdd_context_get_mac_handle(adapter->hdd_ctx);
112*5113495bSYour Name if (!mac_handle)
113*5113495bSYour Name return QDF_STATUS_E_INVAL;
114*5113495bSYour Name
115*5113495bSYour Name status = sme_switch_channel(mac_handle, bssid,
116*5113495bSYour Name tgt_freq, tgt_width);
117*5113495bSYour Name break;
118*5113495bSYour Name case QDF_SAP_MODE:
119*5113495bSYour Name if (!test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags))
120*5113495bSYour Name return QDF_STATUS_E_INVAL;
121*5113495bSYour Name
122*5113495bSYour Name /* stop sap if got invalid freq or width */
123*5113495bSYour Name if (tgt_freq == 0 || tgt_width == CH_WIDTH_INVALID) {
124*5113495bSYour Name schedule_work(&adapter->sap_stop_bss_work);
125*5113495bSYour Name return QDF_STATUS_SUCCESS;
126*5113495bSYour Name }
127*5113495bSYour Name
128*5113495bSYour Name psoc = wlan_vdev_get_psoc(vdev);
129*5113495bSYour Name if (!psoc)
130*5113495bSYour Name return QDF_STATUS_E_INVAL;
131*5113495bSYour Name
132*5113495bSYour Name wlan_hdd_set_sap_csa_reason(psoc, link_info->vdev_id,
133*5113495bSYour Name CSA_REASON_DCS);
134*5113495bSYour Name ret = hdd_softap_set_channel_change(adapter->dev, tgt_freq,
135*5113495bSYour Name tgt_width, true);
136*5113495bSYour Name status = qdf_status_from_os_return(ret);
137*5113495bSYour Name break;
138*5113495bSYour Name default:
139*5113495bSYour Name hdd_err("OP mode %d not supported", adapter->device_mode);
140*5113495bSYour Name break;
141*5113495bSYour Name }
142*5113495bSYour Name
143*5113495bSYour Name return status;
144*5113495bSYour Name }
145*5113495bSYour Name
146*5113495bSYour Name #ifdef WLAN_FEATURE_SAP_ACS_OPTIMIZE
147*5113495bSYour Name /**
148*5113495bSYour Name * hdd_get_bw_for_freq - get BW for provided freq
149*5113495bSYour Name * @res_msg: resp msg with freq info
150*5113495bSYour Name * @freq: freq for which BW is required
151*5113495bSYour Name * @total_chan: total no of channels
152*5113495bSYour Name *
153*5113495bSYour Name * Return: bandwidth
154*5113495bSYour Name */
155*5113495bSYour Name static enum phy_ch_width
hdd_get_bw_for_freq(struct get_usable_chan_res_params * res_msg,uint16_t freq,uint16_t total_chan)156*5113495bSYour Name hdd_get_bw_for_freq(struct get_usable_chan_res_params *res_msg,
157*5113495bSYour Name uint16_t freq, uint16_t total_chan)
158*5113495bSYour Name {
159*5113495bSYour Name uint16_t i;
160*5113495bSYour Name
161*5113495bSYour Name for (i = 0; i < total_chan; i++) {
162*5113495bSYour Name if (res_msg[i].freq == freq)
163*5113495bSYour Name return res_msg[i].bw;
164*5113495bSYour Name }
165*5113495bSYour Name return CH_WIDTH_INVALID;
166*5113495bSYour Name }
167*5113495bSYour Name
168*5113495bSYour Name /**
169*5113495bSYour Name * hdd_dcs_select_random_chan: To select random 6G channel
170*5113495bSYour Name * for CSA
171*5113495bSYour Name * @pdev: pdev object
172*5113495bSYour Name * @vdev: vdevobject
173*5113495bSYour Name *
174*5113495bSYour Name * Return: success/failure
175*5113495bSYour Name */
176*5113495bSYour Name static QDF_STATUS
hdd_dcs_select_random_chan(struct wlan_objmgr_pdev * pdev,struct wlan_objmgr_vdev * vdev)177*5113495bSYour Name hdd_dcs_select_random_chan(struct wlan_objmgr_pdev *pdev,
178*5113495bSYour Name struct wlan_objmgr_vdev *vdev)
179*5113495bSYour Name {
180*5113495bSYour Name struct get_usable_chan_req_params req_msg;
181*5113495bSYour Name struct get_usable_chan_res_params *res_msg;
182*5113495bSYour Name enum phy_ch_width tgt_width;
183*5113495bSYour Name uint16_t final_lst[NUM_CHANNELS] = {0};
184*5113495bSYour Name uint16_t intf_ch_freq = 0;
185*5113495bSYour Name uint32_t count;
186*5113495bSYour Name uint32_t i;
187*5113495bSYour Name QDF_STATUS status = QDF_STATUS_E_EMPTY;
188*5113495bSYour Name
189*5113495bSYour Name res_msg = qdf_mem_malloc(NUM_CHANNELS *
190*5113495bSYour Name sizeof(*res_msg));
191*5113495bSYour Name
192*5113495bSYour Name if (!res_msg) {
193*5113495bSYour Name hdd_err("res_msg invalid");
194*5113495bSYour Name return QDF_STATUS_E_NOMEM;
195*5113495bSYour Name }
196*5113495bSYour Name req_msg.band_mask = BIT(REG_BAND_6G);
197*5113495bSYour Name req_msg.iface_mode_mask = BIT(NL80211_IFTYPE_AP);
198*5113495bSYour Name req_msg.filter_mask = 0;
199*5113495bSYour Name status = wlan_reg_get_usable_channel(pdev, req_msg, res_msg, &count,
200*5113495bSYour Name REG_CURRENT_PWR_MODE);
201*5113495bSYour Name if (QDF_STATUS_SUCCESS != status) {
202*5113495bSYour Name hdd_err("get usable channel failed %d", status);
203*5113495bSYour Name qdf_mem_free(res_msg);
204*5113495bSYour Name return QDF_STATUS_E_INVAL;
205*5113495bSYour Name }
206*5113495bSYour Name hdd_debug("channel count %d for band %d", count, REG_BAND_6G);
207*5113495bSYour Name for (i = 0; i < count; i++)
208*5113495bSYour Name final_lst[i] = res_msg[i].freq;
209*5113495bSYour Name
210*5113495bSYour Name intf_ch_freq = wlan_get_rand_from_lst_for_freq(final_lst, count);
211*5113495bSYour Name if (!intf_ch_freq || intf_ch_freq > wlan_reg_max_6ghz_chan_freq()) {
212*5113495bSYour Name hdd_debug("ch freq gt max 6g freq %d",
213*5113495bSYour Name wlan_reg_max_6ghz_chan_freq());
214*5113495bSYour Name qdf_mem_free(res_msg);
215*5113495bSYour Name return QDF_STATUS_E_INVAL;
216*5113495bSYour Name }
217*5113495bSYour Name tgt_width = hdd_get_bw_for_freq(res_msg, intf_ch_freq, count);
218*5113495bSYour Name if (tgt_width >= CH_WIDTH_INVALID) {
219*5113495bSYour Name qdf_mem_free(res_msg);
220*5113495bSYour Name return QDF_STATUS_E_INVAL;
221*5113495bSYour Name }
222*5113495bSYour Name if (tgt_width > CH_WIDTH_160MHZ) {
223*5113495bSYour Name hdd_debug("restrict max bw to 160");
224*5113495bSYour Name tgt_width = CH_WIDTH_160MHZ;
225*5113495bSYour Name }
226*5113495bSYour Name qdf_mem_free(res_msg);
227*5113495bSYour Name return ucfg_dcs_switch_chan(vdev, intf_ch_freq,
228*5113495bSYour Name tgt_width);
229*5113495bSYour Name }
230*5113495bSYour Name #else
231*5113495bSYour Name static inline QDF_STATUS
hdd_dcs_select_random_chan(struct wlan_objmgr_pdev * pdev,struct wlan_objmgr_vdev * vdev)232*5113495bSYour Name hdd_dcs_select_random_chan(struct wlan_objmgr_pdev *pdev,
233*5113495bSYour Name struct wlan_objmgr_vdev *vdev)
234*5113495bSYour Name {
235*5113495bSYour Name return QDF_STATUS_E_NOSUPPORT;
236*5113495bSYour Name }
237*5113495bSYour Name #endif
238*5113495bSYour Name
239*5113495bSYour Name /**
240*5113495bSYour Name * hdd_dcs_cb() - hdd dcs specific callback
241*5113495bSYour Name * @psoc: psoc
242*5113495bSYour Name * @mac_id: mac_id
243*5113495bSYour Name * @interference_type: wlan or continuous wave interference type
244*5113495bSYour Name * @arg: List of arguments
245*5113495bSYour Name *
246*5113495bSYour Name * This callback is registered with dcs component to start acs operation
247*5113495bSYour Name *
248*5113495bSYour Name * Return: None
249*5113495bSYour Name */
hdd_dcs_cb(struct wlan_objmgr_psoc * psoc,uint8_t mac_id,uint8_t interference_type,void * arg)250*5113495bSYour Name static void hdd_dcs_cb(struct wlan_objmgr_psoc *psoc, uint8_t mac_id,
251*5113495bSYour Name uint8_t interference_type, void *arg)
252*5113495bSYour Name {
253*5113495bSYour Name struct hdd_context *hdd_ctx = (struct hdd_context *)arg;
254*5113495bSYour Name struct wlan_hdd_link_info *link_info;
255*5113495bSYour Name struct sap_context *sap_ctx;
256*5113495bSYour Name uint32_t count;
257*5113495bSYour Name uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS];
258*5113495bSYour Name uint32_t index;
259*5113495bSYour Name QDF_STATUS status;
260*5113495bSYour Name
261*5113495bSYour Name /*
262*5113495bSYour Name * so far CAP_DCS_CWIM interference mitigation is not supported
263*5113495bSYour Name */
264*5113495bSYour Name if (interference_type == WLAN_HOST_DCS_CWIM) {
265*5113495bSYour Name hdd_debug("CW interference mitigation is not supported");
266*5113495bSYour Name return;
267*5113495bSYour Name }
268*5113495bSYour Name
269*5113495bSYour Name if (policy_mgr_is_force_scc(psoc) &&
270*5113495bSYour Name policy_mgr_is_sta_gc_active_on_mac(psoc, mac_id)) {
271*5113495bSYour Name ucfg_config_dcs_event_data(psoc, mac_id, true);
272*5113495bSYour Name
273*5113495bSYour Name hdd_debug("force scc %d, mac id %d sta gc count %d",
274*5113495bSYour Name policy_mgr_is_force_scc(psoc), mac_id,
275*5113495bSYour Name policy_mgr_is_sta_gc_active_on_mac(psoc, mac_id));
276*5113495bSYour Name return;
277*5113495bSYour Name }
278*5113495bSYour Name
279*5113495bSYour Name count = policy_mgr_get_sap_go_count_on_mac(psoc, list, mac_id);
280*5113495bSYour Name for (index = 0; index < count; index++) {
281*5113495bSYour Name link_info = hdd_get_link_info_by_vdev(hdd_ctx, list[index]);
282*5113495bSYour Name if (!link_info) {
283*5113495bSYour Name hdd_err("vdev_id %u does not exist with host",
284*5113495bSYour Name list[index]);
285*5113495bSYour Name return;
286*5113495bSYour Name }
287*5113495bSYour Name
288*5113495bSYour Name sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(link_info);
289*5113495bSYour Name if (!wlansap_dcs_is_wlan_interference_mitigation_enabled(sap_ctx))
290*5113495bSYour Name continue;
291*5113495bSYour Name
292*5113495bSYour Name hdd_debug("DCS triggers ACS on vdev_id=%u, mac_id=%u",
293*5113495bSYour Name list[index], mac_id);
294*5113495bSYour Name /*
295*5113495bSYour Name * Select Random channel for low latency sap as
296*5113495bSYour Name * ACS can't select channel of same MAC from which
297*5113495bSYour Name * CSA is triggered because same MAC frequencies
298*5113495bSYour Name * will not be present in scan list and results and
299*5113495bSYour Name * selecting freq of other MAC may cause MCC with
300*5113495bSYour Name * other modes if present.
301*5113495bSYour Name */
302*5113495bSYour Name if (wlan_mlme_get_ap_policy(link_info->vdev) !=
303*5113495bSYour Name HOST_CONCURRENT_AP_POLICY_UNSPECIFIED) {
304*5113495bSYour Name status = hdd_dcs_select_random_chan(hdd_ctx->pdev,
305*5113495bSYour Name link_info->vdev);
306*5113495bSYour Name if (QDF_IS_STATUS_SUCCESS(status))
307*5113495bSYour Name return;
308*5113495bSYour Name }
309*5113495bSYour Name wlan_hdd_cfg80211_start_acs(link_info);
310*5113495bSYour Name return;
311*5113495bSYour Name }
312*5113495bSYour Name }
313*5113495bSYour Name
314*5113495bSYour Name #ifdef CONFIG_AFC_SUPPORT
315*5113495bSYour Name /**
316*5113495bSYour Name * hdd_dcs_afc_sel_chan_cb() - Callback to select best SAP channel/bandwidth
317*5113495bSYour Name * after channel state update by AFC
318*5113495bSYour Name * @arg: argument
319*5113495bSYour Name * @vdev_id: vdev id of SAP
320*5113495bSYour Name * @cur_freq: SAP current channel frequency
321*5113495bSYour Name * @cur_bw: SAP current channel bandwidth
322*5113495bSYour Name * @pref_bw: pointer to channel bandwidth prefer to set as input and output
323*5113495bSYour Name * as target bandwidth can set
324*5113495bSYour Name *
325*5113495bSYour Name * Return: Target home channel frequency selected
326*5113495bSYour Name */
hdd_dcs_afc_sel_chan_cb(void * arg,uint32_t vdev_id,qdf_freq_t cur_freq,enum phy_ch_width cur_bw,enum phy_ch_width * pref_bw)327*5113495bSYour Name static qdf_freq_t hdd_dcs_afc_sel_chan_cb(void *arg,
328*5113495bSYour Name uint32_t vdev_id,
329*5113495bSYour Name qdf_freq_t cur_freq,
330*5113495bSYour Name enum phy_ch_width cur_bw,
331*5113495bSYour Name enum phy_ch_width *pref_bw)
332*5113495bSYour Name {
333*5113495bSYour Name struct hdd_context *hdd_ctx = (struct hdd_context *)arg;
334*5113495bSYour Name struct wlan_hdd_link_info *link_info;
335*5113495bSYour Name struct sap_context *sap_ctx;
336*5113495bSYour Name qdf_freq_t target_freq;
337*5113495bSYour Name
338*5113495bSYour Name if (!hdd_ctx)
339*5113495bSYour Name return 0;
340*5113495bSYour Name
341*5113495bSYour Name link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id);
342*5113495bSYour Name if (!link_info)
343*5113495bSYour Name return 0;
344*5113495bSYour Name
345*5113495bSYour Name sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(link_info);
346*5113495bSYour Name if (!sap_ctx)
347*5113495bSYour Name return 0;
348*5113495bSYour Name
349*5113495bSYour Name target_freq = sap_afc_dcs_sel_chan(sap_ctx, cur_freq, cur_bw, pref_bw);
350*5113495bSYour Name
351*5113495bSYour Name return target_freq;
352*5113495bSYour Name }
353*5113495bSYour Name #else
hdd_dcs_afc_sel_chan_cb(void * arg,uint32_t vdev_id,qdf_freq_t cur_freq,enum phy_ch_width cur_bw,enum phy_ch_width * pref_bw)354*5113495bSYour Name static inline qdf_freq_t hdd_dcs_afc_sel_chan_cb(void *arg,
355*5113495bSYour Name uint32_t vdev_id,
356*5113495bSYour Name qdf_freq_t cur_freq,
357*5113495bSYour Name enum phy_ch_width cur_bw,
358*5113495bSYour Name enum phy_ch_width *pref_bw)
359*5113495bSYour Name {
360*5113495bSYour Name return 0;
361*5113495bSYour Name }
362*5113495bSYour Name #endif
363*5113495bSYour Name
hdd_dcs_register_cb(struct hdd_context * hdd_ctx)364*5113495bSYour Name void hdd_dcs_register_cb(struct hdd_context *hdd_ctx)
365*5113495bSYour Name {
366*5113495bSYour Name ucfg_dcs_register_cb(hdd_ctx->psoc, hdd_dcs_cb, hdd_ctx);
367*5113495bSYour Name ucfg_dcs_register_awgn_cb(hdd_ctx->psoc, hdd_dcs_switch_chan_cb);
368*5113495bSYour Name ucfg_dcs_register_afc_sel_chan_cb(hdd_ctx->psoc,
369*5113495bSYour Name hdd_dcs_afc_sel_chan_cb,
370*5113495bSYour Name hdd_ctx);
371*5113495bSYour Name }
372*5113495bSYour Name
hdd_dcs_hostapd_set_chan(struct hdd_context * hdd_ctx,uint8_t vdev_id,qdf_freq_t dcs_ch_freq)373*5113495bSYour Name QDF_STATUS hdd_dcs_hostapd_set_chan(struct hdd_context *hdd_ctx,
374*5113495bSYour Name uint8_t vdev_id,
375*5113495bSYour Name qdf_freq_t dcs_ch_freq)
376*5113495bSYour Name {
377*5113495bSYour Name struct hdd_ap_ctx *ap_ctx;
378*5113495bSYour Name struct sap_context *sap_ctx;
379*5113495bSYour Name QDF_STATUS status;
380*5113495bSYour Name uint8_t mac_id;
381*5113495bSYour Name uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS];
382*5113495bSYour Name uint32_t conn_idx, count;
383*5113495bSYour Name struct wlan_hdd_link_info *link_info;
384*5113495bSYour Name uint32_t dcs_ch = wlan_reg_freq_to_chan(hdd_ctx->pdev, dcs_ch_freq);
385*5113495bSYour Name
386*5113495bSYour Name status = policy_mgr_get_mac_id_by_session_id(hdd_ctx->psoc, vdev_id,
387*5113495bSYour Name &mac_id);
388*5113495bSYour Name
389*5113495bSYour Name if (QDF_IS_STATUS_ERROR(status)) {
390*5113495bSYour Name hdd_err("get mac id failed");
391*5113495bSYour Name return QDF_STATUS_E_INVAL;
392*5113495bSYour Name }
393*5113495bSYour Name count = policy_mgr_get_sap_go_count_on_mac(hdd_ctx->psoc, list, mac_id);
394*5113495bSYour Name
395*5113495bSYour Name /*
396*5113495bSYour Name * Dcs can only be enabled after all vdev finish csa.
397*5113495bSYour Name * Set vdev starting for every vdev before doing csa.
398*5113495bSYour Name * The CSA triggered by DCS will be done in serial.
399*5113495bSYour Name */
400*5113495bSYour Name for (conn_idx = 0; conn_idx < count; conn_idx++) {
401*5113495bSYour Name link_info = hdd_get_link_info_by_vdev(hdd_ctx, list[conn_idx]);
402*5113495bSYour Name if (!link_info) {
403*5113495bSYour Name hdd_err("vdev_id %u does not exist with host",
404*5113495bSYour Name list[conn_idx]);
405*5113495bSYour Name return QDF_STATUS_E_INVAL;
406*5113495bSYour Name }
407*5113495bSYour Name
408*5113495bSYour Name ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info);
409*5113495bSYour Name sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(link_info);
410*5113495bSYour Name if (ap_ctx->operating_chan_freq != dcs_ch_freq)
411*5113495bSYour Name wlansap_dcs_set_vdev_starting(sap_ctx, true);
412*5113495bSYour Name else
413*5113495bSYour Name wlansap_dcs_set_vdev_starting(sap_ctx, false);
414*5113495bSYour Name }
415*5113495bSYour Name for (conn_idx = 0; conn_idx < count; conn_idx++) {
416*5113495bSYour Name link_info = hdd_get_link_info_by_vdev(hdd_ctx, list[conn_idx]);
417*5113495bSYour Name if (!link_info) {
418*5113495bSYour Name hdd_err("vdev_id %u does not exist with host",
419*5113495bSYour Name list[conn_idx]);
420*5113495bSYour Name return QDF_STATUS_E_INVAL;
421*5113495bSYour Name }
422*5113495bSYour Name
423*5113495bSYour Name ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info);
424*5113495bSYour Name if (ap_ctx->operating_chan_freq == dcs_ch_freq)
425*5113495bSYour Name continue;
426*5113495bSYour Name
427*5113495bSYour Name hdd_ctx->acs_policy.acs_chan_freq = AUTO_CHANNEL_SELECT;
428*5113495bSYour Name hdd_debug("dcs triggers old ch:%d new ch:%d",
429*5113495bSYour Name ap_ctx->operating_chan_freq, dcs_ch_freq);
430*5113495bSYour Name wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc,
431*5113495bSYour Name link_info->vdev_id, CSA_REASON_DCS);
432*5113495bSYour Name status = hdd_switch_sap_channel(link_info, dcs_ch, true);
433*5113495bSYour Name if (status == QDF_STATUS_SUCCESS)
434*5113495bSYour Name status = QDF_STATUS_E_PENDING;
435*5113495bSYour Name return status;
436*5113495bSYour Name }
437*5113495bSYour Name
438*5113495bSYour Name return QDF_STATUS_SUCCESS;
439*5113495bSYour Name }
440*5113495bSYour Name
441*5113495bSYour Name /**
442*5113495bSYour Name * hdd_dcs_hostapd_enable_wlan_interference_mitigation() - enable wlan
443*5113495bSYour Name * interference mitigation
444*5113495bSYour Name * @hdd_ctx: hdd ctx
445*5113495bSYour Name * @vdev_id: vdev id
446*5113495bSYour Name *
447*5113495bSYour Name * This function is used to enable wlan interference mitigation through
448*5113495bSYour Name * send dcs command.
449*5113495bSYour Name *
450*5113495bSYour Name * Return: None
451*5113495bSYour Name */
hdd_dcs_hostapd_enable_wlan_interference_mitigation(struct hdd_context * hdd_ctx,uint8_t vdev_id)452*5113495bSYour Name static void hdd_dcs_hostapd_enable_wlan_interference_mitigation(
453*5113495bSYour Name struct hdd_context *hdd_ctx,
454*5113495bSYour Name uint8_t vdev_id)
455*5113495bSYour Name {
456*5113495bSYour Name QDF_STATUS status;
457*5113495bSYour Name uint8_t mac_id;
458*5113495bSYour Name struct wlan_hdd_link_info *link_info;
459*5113495bSYour Name struct hdd_ap_ctx *ap_ctx;
460*5113495bSYour Name struct sap_context *sap_ctx;
461*5113495bSYour Name
462*5113495bSYour Name status = policy_mgr_get_mac_id_by_session_id(hdd_ctx->psoc, vdev_id,
463*5113495bSYour Name &mac_id);
464*5113495bSYour Name if (QDF_IS_STATUS_ERROR(status)) {
465*5113495bSYour Name hdd_err("get mac id failed");
466*5113495bSYour Name return;
467*5113495bSYour Name }
468*5113495bSYour Name
469*5113495bSYour Name link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id);
470*5113495bSYour Name if (!link_info) {
471*5113495bSYour Name hdd_err("vdev_id %u does not exist with host", vdev_id);
472*5113495bSYour Name return;
473*5113495bSYour Name }
474*5113495bSYour Name
475*5113495bSYour Name ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info);
476*5113495bSYour Name sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(link_info);
477*5113495bSYour Name if (wlansap_dcs_is_wlan_interference_mitigation_enabled(sap_ctx) &&
478*5113495bSYour Name !WLAN_REG_IS_24GHZ_CH_FREQ(ap_ctx->operating_chan_freq))
479*5113495bSYour Name ucfg_config_dcs_event_data(hdd_ctx->psoc, mac_id, true);
480*5113495bSYour Name }
481*5113495bSYour Name
hdd_dcs_chan_select_complete(struct hdd_adapter * adapter)482*5113495bSYour Name void hdd_dcs_chan_select_complete(struct hdd_adapter *adapter)
483*5113495bSYour Name {
484*5113495bSYour Name qdf_freq_t dcs_freq;
485*5113495bSYour Name struct hdd_context *hdd_ctx;
486*5113495bSYour Name uint32_t chan_freq;
487*5113495bSYour Name struct hdd_ap_ctx *ap_ctx;
488*5113495bSYour Name
489*5113495bSYour Name hdd_ctx = WLAN_HDD_GET_CTX(adapter);
490*5113495bSYour Name if (!hdd_ctx) {
491*5113495bSYour Name hdd_err("Invalid HDD context pointer");
492*5113495bSYour Name return;
493*5113495bSYour Name }
494*5113495bSYour Name
495*5113495bSYour Name ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink);
496*5113495bSYour Name dcs_freq = wlansap_dcs_get_freq(ap_ctx->sap_context);
497*5113495bSYour Name chan_freq = ap_ctx->operating_chan_freq;
498*5113495bSYour Name if (dcs_freq && dcs_freq != chan_freq)
499*5113495bSYour Name hdd_dcs_hostapd_set_chan(hdd_ctx, adapter->deflink->vdev_id,
500*5113495bSYour Name dcs_freq);
501*5113495bSYour Name else
502*5113495bSYour Name hdd_dcs_hostapd_enable_wlan_interference_mitigation(
503*5113495bSYour Name hdd_ctx, adapter->deflink->vdev_id);
504*5113495bSYour Name
505*5113495bSYour Name qdf_atomic_set(&ap_ctx->acs_in_progress, 0);
506*5113495bSYour Name }
507*5113495bSYour Name
hdd_dcs_clear(struct hdd_adapter * adapter)508*5113495bSYour Name void hdd_dcs_clear(struct hdd_adapter *adapter)
509*5113495bSYour Name {
510*5113495bSYour Name QDF_STATUS status;
511*5113495bSYour Name uint8_t mac_id;
512*5113495bSYour Name struct hdd_context *hdd_ctx;
513*5113495bSYour Name struct wlan_objmgr_psoc *psoc;
514*5113495bSYour Name uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS];
515*5113495bSYour Name struct sap_context *sap_ctx;
516*5113495bSYour Name
517*5113495bSYour Name hdd_ctx = WLAN_HDD_GET_CTX(adapter);
518*5113495bSYour Name if (!hdd_ctx) {
519*5113495bSYour Name hdd_err("Invalid HDD context pointer");
520*5113495bSYour Name return;
521*5113495bSYour Name }
522*5113495bSYour Name
523*5113495bSYour Name psoc = hdd_ctx->psoc;
524*5113495bSYour Name
525*5113495bSYour Name status = policy_mgr_get_mac_id_by_session_id(psoc,
526*5113495bSYour Name adapter->deflink->vdev_id,
527*5113495bSYour Name &mac_id);
528*5113495bSYour Name if (QDF_IS_STATUS_ERROR(status)) {
529*5113495bSYour Name hdd_err("get mac id failed");
530*5113495bSYour Name return;
531*5113495bSYour Name }
532*5113495bSYour Name
533*5113495bSYour Name sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(adapter->deflink);
534*5113495bSYour Name if (policy_mgr_get_sap_go_count_on_mac(psoc, list, mac_id) <= 1) {
535*5113495bSYour Name ucfg_config_dcs_disable(psoc, mac_id, WLAN_HOST_DCS_WLANIM);
536*5113495bSYour Name ucfg_wlan_dcs_cmd(psoc, mac_id, true);
537*5113495bSYour Name if (wlansap_dcs_is_wlan_interference_mitigation_enabled(sap_ctx))
538*5113495bSYour Name ucfg_dcs_clear(psoc, mac_id);
539*5113495bSYour Name }
540*5113495bSYour Name
541*5113495bSYour Name wlansap_dcs_set_vdev_wlan_interference_mitigation(sap_ctx, false);
542*5113495bSYour Name wlansap_dcs_set_vdev_starting(sap_ctx, false);
543*5113495bSYour Name }
544