1 /*
2  * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include "wlan_ll_lt_sap_main.h"
18 #include "wlan_reg_services_api.h"
19 #include "wlan_ll_sap_public_structs.h"
20 #include "wlan_policy_mgr_i.h"
21 #include "wlan_mlme_vdev_mgr_interface.h"
22 #include "wlan_ll_sap_main.h"
23 #include "wlan_ll_lt_sap_bearer_switch.h"
24 #include "wlan_scan_api.h"
25 #include "target_if.h"
26 
ll_lt_sap_is_supported(struct wlan_objmgr_psoc * psoc)27 bool ll_lt_sap_is_supported(struct wlan_objmgr_psoc *psoc)
28 {
29 	struct wmi_unified *wmi_handle;
30 
31 	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
32 	if (!wmi_handle) {
33 		ll_sap_err("Invalid WMI handle");
34 		return false;
35 	}
36 
37 	return wmi_service_enabled(wmi_handle, wmi_service_xpan_support);
38 }
39 
40 /**
41  * ll_lt_sap_get_sorted_user_config_acs_ch_list() - API to get sorted user
42  * configured ACS channel list
43  * @psoc: Pointer to psoc object
44  * @vdev_id: Vdev Id
45  * @ch_info: Pointer to ch_info
46  *
47  * Return: None
48  */
49 static
ll_lt_sap_get_sorted_user_config_acs_ch_list(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,struct sap_sel_ch_info * ch_info)50 QDF_STATUS ll_lt_sap_get_sorted_user_config_acs_ch_list(
51 					struct wlan_objmgr_psoc *psoc,
52 					uint8_t vdev_id,
53 					struct sap_sel_ch_info *ch_info)
54 {
55 	struct scan_filter *filter;
56 	qdf_list_t *list = NULL;
57 	struct wlan_objmgr_pdev *pdev;
58 	struct wlan_objmgr_vdev *vdev;
59 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
60 
61 	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id,
62 						    WLAN_LL_SAP_ID);
63 
64 	if (!vdev) {
65 		ll_sap_err("Invalid vdev for vdev_id %d", vdev_id);
66 		return QDF_STATUS_E_FAILURE;
67 	}
68 
69 	pdev = wlan_vdev_get_pdev(vdev);
70 
71 	filter = qdf_mem_malloc(sizeof(*filter));
72 	if (!filter)
73 		goto rel_ref;
74 
75 	wlan_sap_get_user_config_acs_ch_list(vdev_id, filter);
76 
77 	list = wlan_scan_get_result(pdev, filter);
78 
79 	qdf_mem_free(filter);
80 
81 	if (!list)
82 		goto rel_ref;
83 
84 	status = wlan_ll_sap_sort_channel_list(vdev_id, list, ch_info);
85 
86 	wlan_scan_purge_results(list);
87 
88 rel_ref:
89 	wlan_objmgr_vdev_release_ref(vdev, WLAN_LL_SAP_ID);
90 
91 	return status;
92 }
93 
ll_lt_sap_init(struct wlan_objmgr_vdev * vdev)94 QDF_STATUS ll_lt_sap_init(struct wlan_objmgr_vdev *vdev)
95 {
96 	struct ll_sap_vdev_priv_obj *ll_sap_obj;
97 	QDF_STATUS status;
98 	uint8_t i, j;
99 	struct bearer_switch_info *bs_ctx;
100 
101 	ll_sap_obj = ll_sap_get_vdev_priv_obj(vdev);
102 
103 	if (!ll_sap_obj) {
104 		ll_sap_err("vdev %d ll_sap obj null",
105 			   wlan_vdev_get_id(vdev));
106 		return QDF_STATUS_E_INVAL;
107 	}
108 
109 	bs_ctx = qdf_mem_malloc(sizeof(struct bearer_switch_info));
110 	if (!bs_ctx)
111 		return QDF_STATUS_E_NOMEM;
112 
113 	ll_sap_obj->bearer_switch_ctx = bs_ctx;
114 
115 	qdf_atomic_init(&bs_ctx->request_id);
116 
117 	for (i = 0; i < WLAN_UMAC_PSOC_MAX_VDEVS; i++)
118 		for (j = 0; j < BEARER_SWITCH_REQ_MAX; j++)
119 			qdf_atomic_init(&bs_ctx->ref_count[i][j]);
120 
121 	qdf_atomic_init(&bs_ctx->fw_ref_count);
122 	qdf_atomic_init(&bs_ctx->total_ref_count);
123 
124 	bs_ctx->vdev = vdev;
125 
126 	status = bs_sm_create(bs_ctx);
127 
128 	if (QDF_IS_STATUS_ERROR(status))
129 		goto bs_sm_failed;
130 
131 	ll_sap_debug("vdev %d", wlan_vdev_get_id(vdev));
132 
133 	return QDF_STATUS_SUCCESS;
134 
135 bs_sm_failed:
136 	qdf_mem_free(ll_sap_obj->bearer_switch_ctx);
137 	ll_sap_obj->bearer_switch_ctx = NULL;
138 	return status;
139 }
140 
ll_lt_sap_deinit(struct wlan_objmgr_vdev * vdev)141 QDF_STATUS ll_lt_sap_deinit(struct wlan_objmgr_vdev *vdev)
142 {
143 	struct ll_sap_vdev_priv_obj *ll_sap_obj;
144 
145 	ll_sap_obj = ll_sap_get_vdev_priv_obj(vdev);
146 
147 	if (!ll_sap_obj) {
148 		ll_sap_err("vdev %d ll_sap obj null",
149 			   wlan_vdev_get_id(vdev));
150 		return QDF_STATUS_E_INVAL;
151 	}
152 
153 	if (!ll_sap_obj->bearer_switch_ctx) {
154 		ll_sap_debug("vdev %d Bearer switch context is NULL",
155 			     wlan_vdev_get_id(vdev));
156 		return QDF_STATUS_E_INVAL;
157 	}
158 
159 	bs_sm_destroy(ll_sap_obj->bearer_switch_ctx);
160 	qdf_mem_free(ll_sap_obj->bearer_switch_ctx);
161 	ll_sap_obj->bearer_switch_ctx = NULL;
162 
163 	ll_sap_debug("vdev %d", wlan_vdev_get_id(vdev));
164 
165 	return QDF_STATUS_SUCCESS;
166 }
167 
168 static
ll_lt_sap_update_mac_freq(struct wlan_ll_lt_sap_mac_freq * freq_list,qdf_freq_t sbs_cut_off_freq,qdf_freq_t given_freq,uint32_t given_weight)169 void ll_lt_sap_update_mac_freq(struct wlan_ll_lt_sap_mac_freq *freq_list,
170 			       qdf_freq_t sbs_cut_off_freq,
171 			       qdf_freq_t given_freq, uint32_t given_weight)
172 {
173 	if (WLAN_REG_IS_5GHZ_CH_FREQ(given_freq) &&
174 	    ((sbs_cut_off_freq && given_freq < sbs_cut_off_freq) ||
175 	    !sbs_cut_off_freq) && !freq_list->freq_5GHz_low) {
176 		freq_list->freq_5GHz_low = given_freq;
177 		freq_list->weight_5GHz_low = given_weight;
178 
179 		/*
180 		 * Update same freq in 5GHz high freq if sbs_cut_off_freq
181 		 * is not present
182 		 */
183 		if (!sbs_cut_off_freq) {
184 			freq_list->freq_5GHz_high = given_freq;
185 			freq_list->weight_5GHz_high = given_weight;
186 		}
187 	} else if (WLAN_REG_IS_5GHZ_CH_FREQ(given_freq) &&
188 		   ((sbs_cut_off_freq && given_freq > sbs_cut_off_freq) ||
189 		   !sbs_cut_off_freq) && !freq_list->freq_5GHz_high) {
190 			freq_list->freq_5GHz_high = given_freq;
191 			freq_list->weight_5GHz_high = given_weight;
192 
193 		/*
194 		 * Update same freq for 5GHz low freq if sbs_cut_off_freq
195 		 * is not present
196 		 */
197 		if (!sbs_cut_off_freq) {
198 			freq_list->freq_5GHz_low = given_freq;
199 			freq_list->weight_5GHz_low = given_weight;
200 		}
201 	} else if (WLAN_REG_IS_6GHZ_CHAN_FREQ(given_freq) &&
202 		   !freq_list->freq_6GHz) {
203 		freq_list->freq_6GHz = given_freq;
204 		freq_list->weight_6GHz = given_weight;
205 	}
206 }
207 
208 /* Threshold value of channel weight */
209 #define CHANNEL_WEIGHT_THRESHOLD_VALUE 20000
210 static
ll_lt_sap_update_freq_list(struct wlan_objmgr_psoc * psoc,struct sap_sel_ch_info * ch_param,struct wlan_ll_lt_sap_freq_list * freq_list,struct policy_mgr_pcl_list * pcl,struct connection_info * info,uint8_t connection_count,uint8_t vdev_id)211 void ll_lt_sap_update_freq_list(struct wlan_objmgr_psoc *psoc,
212 				struct sap_sel_ch_info *ch_param,
213 				struct wlan_ll_lt_sap_freq_list *freq_list,
214 				struct policy_mgr_pcl_list *pcl,
215 				struct connection_info *info,
216 				uint8_t connection_count,
217 				uint8_t vdev_id)
218 {
219 	qdf_freq_t freq, sbs_cut_off_freq;
220 	qdf_freq_t same_mac_freq, standalone_mac_freq;
221 	uint8_t i = 0, count;
222 	uint32_t weight;
223 	enum policy_mgr_con_mode con_mode = PM_MAX_NUM_OF_MODE;
224 
225 	sbs_cut_off_freq = policy_mgr_get_sbs_cut_off_freq(psoc);
226 
227 	for (i = 0; i < ch_param->num_ch; i++) {
228 		if (!ch_param->ch_info[i].valid)
229 			continue;
230 
231 		freq = ch_param->ch_info[i].chan_freq;
232 		weight = ch_param->ch_info[i].weight;
233 
234 		/*
235 		 * Do not select same channel where LL_LT_SAP was
236 		 * present earlier
237 		 */
238 		if (freq_list->prev_freq == freq)
239 			continue;
240 
241 		/* Check if channel is present in PCL or not */
242 		if (!wlan_ll_sap_freq_present_in_pcl(pcl, freq))
243 			continue;
244 
245 		/*
246 		 * Store first valid best channel from ACS final list
247 		 * This will be used if there is no valid freq present
248 		 * within threshold value or no concurrency present
249 		 */
250 		if (!freq_list->best_freq) {
251 			freq_list->best_freq = freq;
252 			freq_list->weight_best_freq = weight;
253 		}
254 
255 		if (!connection_count)
256 			break;
257 
258 		/*
259 		 * Instead of selecting random channel, select those
260 		 * channel whose weight is less than
261 		 * CHANNEL_WEIGHT_THRESHOLD_VALUE value. This will help
262 		 * to get the best channel compartively and avoid multiple
263 		 * times of channel switch.
264 		 */
265 		if (weight > CHANNEL_WEIGHT_THRESHOLD_VALUE)
266 			continue;
267 
268 		same_mac_freq = 0;
269 		standalone_mac_freq = 0;
270 
271 		/*
272 		 * Loop through all existing connections before updating
273 		 * channels for LL_LT_SAP.
274 		 */
275 		for (count = 0; count < connection_count; count++) {
276 			/* Do not select SCC channel to update freq_list */
277 			if (freq == info[count].ch_freq) {
278 				same_mac_freq = 0;
279 				standalone_mac_freq = 0;
280 				break;
281 			}
282 			/*
283 			 * Check whether ch_param frequency is in same mac
284 			 * or not.
285 			 */
286 			if (policy_mgr_2_freq_always_on_same_mac(
287 							psoc, freq,
288 							info[count].ch_freq)) {
289 				con_mode = policy_mgr_get_mode_by_vdev_id(
290 						psoc, info[count].vdev_id);
291 				/*
292 				 * Check whether SAP is present in same mac or
293 				 * not. If yes then do not select that frequency
294 				 * because two beacon entity can't be in same
295 				 * mac.
296 				 * Also, do not fill same_mac_freq if it's
297 				 * already filled i.e two existing connection
298 				 * are present on same mac.
299 				 */
300 				if (con_mode == PM_SAP_MODE || same_mac_freq) {
301 					same_mac_freq = 0;
302 					standalone_mac_freq = 0;
303 					break;
304 				}
305 				same_mac_freq = freq;
306 			} else if (!standalone_mac_freq) {
307 				/*
308 				 * Fill standalone_mac_freq only if it's not
309 				 * filled
310 				 */
311 				standalone_mac_freq = freq;
312 			}
313 		}
314 
315 		/*
316 		 * Scenario: Let say two concurrent connection(other than
317 		 * LL_LT_SAP) are present in both mac and one channel from
318 		 * ch_param structure needs to select to fill in freq_list for
319 		 * LL_LT_SAP.
320 		 * Since, there is an existing connection present in both mac
321 		 * then there is chance that channel from ch_param structure
322 		 * may get select for both same_mac_freq and standalone_mac_freq
323 		 *
324 		 * But ideally standalone_mac_freq is not free, some existing
325 		 * connection is already present in it.
326 		 * So, instead of giving priority to fill standalone_mac_freq
327 		 * first, fill same_mac_freq first.
328 		 *
329 		 * Example: Let say 2 concurrent interface present in channel
330 		 * 36 and 149. Now channel 48 from ch_param structure needs to
331 		 * be validate and fill based on existing interface.
332 		 * With respect to channel 36, it will fit to same_mac_freq
333 		 * and with respect to channel 149, it will fit to
334 		 * standalone_mac_freq. But in standalone_mac_freq, there is
335 		 * already existing interface present. So, give priority to
336 		 * same_mac_freq to fill the freq list.
337 		 */
338 		if (same_mac_freq)
339 			ll_lt_sap_update_mac_freq(&freq_list->shared_mac,
340 						  sbs_cut_off_freq,
341 						  same_mac_freq,
342 						  weight);
343 		else if (standalone_mac_freq)
344 			ll_lt_sap_update_mac_freq(&freq_list->standalone_mac,
345 						  sbs_cut_off_freq,
346 						  standalone_mac_freq,
347 						  weight);
348 
349 		if (freq_list->shared_mac.freq_5GHz_low &&
350 		    freq_list->shared_mac.freq_5GHz_high &&
351 		    freq_list->shared_mac.freq_6GHz &&
352 		    freq_list->standalone_mac.freq_5GHz_low &&
353 		    freq_list->standalone_mac.freq_5GHz_high &&
354 		    freq_list->standalone_mac.freq_6GHz)
355 			break;
356 	}
357 
358 	ll_sap_debug("vdev %d, best %d[%d] Shared: low %d[%d] high %d[%d] 6Ghz %d[%d], Standalone: low %d[%d] high %d[%d] 6Ghz %d[%d], prev %d, existing connection cnt %d",
359 		     vdev_id, freq_list->best_freq,
360 		     freq_list->weight_best_freq,
361 		     freq_list->shared_mac.freq_5GHz_low,
362 		     freq_list->shared_mac.weight_5GHz_low,
363 		     freq_list->shared_mac.freq_5GHz_high,
364 		     freq_list->shared_mac.weight_5GHz_high,
365 		     freq_list->shared_mac.freq_6GHz,
366 		     freq_list->shared_mac.weight_6GHz,
367 		     freq_list->standalone_mac.freq_5GHz_low,
368 		     freq_list->standalone_mac.weight_5GHz_low,
369 		     freq_list->standalone_mac.freq_5GHz_high,
370 		     freq_list->standalone_mac.weight_5GHz_high,
371 		     freq_list->standalone_mac.freq_6GHz,
372 		     freq_list->standalone_mac.weight_6GHz,
373 		     freq_list->prev_freq, connection_count);
374 }
375 
376 static
ll_lt_sap_get_allowed_freq_list(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id,struct sap_sel_ch_info * ch_param,struct wlan_ll_lt_sap_freq_list * freq_list)377 QDF_STATUS ll_lt_sap_get_allowed_freq_list(
378 				struct wlan_objmgr_psoc *psoc,
379 				uint8_t vdev_id,
380 				struct sap_sel_ch_info *ch_param,
381 				struct wlan_ll_lt_sap_freq_list *freq_list)
382 {
383 	struct connection_info conn_info[MAX_NUMBER_OF_CONC_CONNECTIONS];
384 	uint8_t count;
385 	struct policy_mgr_pcl_list *pcl;
386 	QDF_STATUS status;
387 
388 	pcl = qdf_mem_malloc(sizeof(*pcl));
389 	if (!pcl)
390 		return QDF_STATUS_E_FAILURE;
391 
392 	status = policy_mgr_get_pcl_ch_list_for_ll_sap(psoc, pcl, vdev_id,
393 						       conn_info, &count);
394 	if (QDF_IS_STATUS_ERROR(status))
395 		goto end;
396 
397 	ll_lt_sap_update_freq_list(psoc, ch_param, freq_list, pcl,
398 				   conn_info, count, vdev_id);
399 
400 	status = QDF_STATUS_SUCCESS;
401 end:
402 	qdf_mem_free(pcl);
403 	return status;
404 }
405 
ll_lt_sap_get_freq_list(struct wlan_objmgr_psoc * psoc,struct wlan_ll_lt_sap_freq_list * freq_list,uint8_t vdev_id)406 QDF_STATUS ll_lt_sap_get_freq_list(struct wlan_objmgr_psoc *psoc,
407 				   struct wlan_ll_lt_sap_freq_list *freq_list,
408 				   uint8_t vdev_id)
409 {
410 	struct sap_sel_ch_info ch_param = { NULL, 0 };
411 	QDF_STATUS status;
412 
413 	/*
414 	 * This memory will be allocated in sap_chan_sel_init() as part
415 	 * of sap_sort_channel_list(). But the caller has to free up the
416 	 * allocated memory
417 	 */
418 
419 	status = ll_lt_sap_get_sorted_user_config_acs_ch_list(psoc, vdev_id,
420 							      &ch_param);
421 
422 	if (!ch_param.num_ch || QDF_IS_STATUS_ERROR(status))
423 		goto release_mem;
424 
425 	status = ll_lt_sap_get_allowed_freq_list(psoc, vdev_id, &ch_param,
426 						 freq_list);
427 
428 release_mem:
429 	wlan_ll_sap_free_chan_info(&ch_param);
430 	return status;
431 }
432 
ll_lt_sap_get_valid_freq(struct wlan_objmgr_psoc * psoc,uint8_t vdev_id)433 qdf_freq_t ll_lt_sap_get_valid_freq(struct wlan_objmgr_psoc *psoc,
434 				    uint8_t vdev_id)
435 {
436 	struct wlan_ll_lt_sap_freq_list freq_list;
437 
438 	qdf_mem_zero(&freq_list, sizeof(freq_list));
439 
440 	ll_lt_sap_get_freq_list(psoc, &freq_list, vdev_id);
441 
442 	if (freq_list.standalone_mac.freq_5GHz_low)
443 		return freq_list.standalone_mac.freq_5GHz_low;
444 	if (freq_list.shared_mac.freq_5GHz_low)
445 		return freq_list.shared_mac.freq_5GHz_low;
446 	if (freq_list.standalone_mac.freq_6GHz)
447 		return freq_list.standalone_mac.freq_6GHz;
448 	if (freq_list.standalone_mac.freq_5GHz_high)
449 		return freq_list.standalone_mac.freq_5GHz_high;
450 	if (freq_list.shared_mac.freq_6GHz)
451 		return freq_list.shared_mac.freq_6GHz;
452 	if (freq_list.shared_mac.freq_5GHz_high)
453 		return freq_list.shared_mac.freq_5GHz_high;
454 
455 	return freq_list.best_freq;
456 }
457