xref: /wlan-driver/qcacld-3.0/core/hdd/src/wlan_hdd_dcs.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 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