xref: /wlan-dirver/qca-wifi-host-cmn/target_if/init_deinit/src/init_cmd_api.c (revision 901120c066e139c7f8a2c8e4820561fdd83c67ef)
1 /*
2  * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /**
21  * DOC: init_cmd_api.c
22  *
23  * WMI Init command prepare & send APIs
24  */
25 #include <qdf_status.h>
26 #include <qdf_types.h>
27 #include <wlan_objmgr_psoc_obj.h>
28 #include <wlan_objmgr_pdev_obj.h>
29 #include <target_if.h>
30 #include <service_ready_util.h>
31 #include <wlan_tgt_def_config.h>
32 #include <wlan_reg_ucfg_api.h>
33 #include <init_cmd_api.h>
34 #include <target_if_scan.h>
35 #include <target_if_reg.h>
36 #include <target_if_twt.h>
37 
38 /**
39  *  init_deinit_alloc_host_mem_chunk() - allocates chunk of memory requested
40  *                                       by FW.
41  *  @psoc: PSOC object
42  *  @tgt_hdl: Target PSOC info
43  *  @req_id: request id
44  *  @idx: chunk id
45  *  @num_units: Number of units
46  *  @unit_len: Unit length
47  *  @num_unit_info: Num unit info
48  *
49  *  API to allocate host memory chunk requested by FW
50  *
51  *  Return: num_units on successful allocation
52  *          0 on failure
53  */
54 static uint32_t init_deinit_alloc_host_mem_chunk(struct wlan_objmgr_psoc *psoc,
55 			struct target_psoc_info *tgt_hdl,
56 			u_int32_t req_id, u_int32_t idx, u_int32_t num_units,
57 			u_int32_t unit_len, u_int32_t num_unit_info)
58 {
59 	qdf_dma_addr_t paddr;
60 	uint32_t ichunk = 0;
61 	struct tgt_info *info;
62 	qdf_device_t qdf_dev;
63 
64 	info = (&tgt_hdl->info);
65 
66 	if (!num_units  || !unit_len)
67 		return 0;
68 
69 	qdf_dev = wlan_psoc_get_qdf_dev(psoc);
70 	if (!qdf_dev)
71 		return 0;
72 
73 	/*
74 	 * We have skip smaller chunks memory allocation for TXBF_CV and
75 	 * CFR_CAPTURE buffer as Firmware is expecting continuous memory
76 	 */
77 	if (!((num_unit_info & HOST_CONTIGUOUS_MEM_CHUNK_REQUIRED) &&
78 	      (req_id == TXBF_CV_POOL0 || req_id == TXBF_CV_POOL1 ||
79 	      req_id == TXBF_CV_POOL2 ||
80 	      req_id == CFR_CAPTURE_HOST_MEM_REQ_ID))) {
81 		ichunk = ((num_units * unit_len) >>
82 			HOST_MEM_CHUNK_MAX_SIZE_POWER2);
83 		if (ichunk)
84 			num_units = num_units / (ichunk + 1);
85 	}
86 
87 	info->mem_chunks[idx].vaddr = NULL;
88 	/* reduce the requested allocation by half until allocation succeeds */
89 	while (!info->mem_chunks[idx].vaddr && num_units) {
90 		info->mem_chunks[idx].vaddr = qdf_mem_alloc_consistent(qdf_dev,
91 				qdf_dev->dev, num_units * unit_len, &paddr);
92 		if (!info->mem_chunks[idx].vaddr) {
93 			if (num_unit_info &
94 					HOST_CONTIGUOUS_MEM_CHUNK_REQUIRED) {
95 				num_units = 0;
96 				target_if_err("mem chink alloc failed for %d",
97 					      idx);
98 				break;
99 			}
100 			/* reduce length by half */
101 			num_units = (num_units >> 1);
102 		} else {
103 			info->mem_chunks[idx].paddr = paddr;
104 			info->mem_chunks[idx].len = num_units*unit_len;
105 			info->mem_chunks[idx].req_id =  req_id;
106 		}
107 	}
108 	target_if_debug("req_id %d idx %d num_units %d unit_len %d",
109 			req_id, idx, num_units, unit_len);
110 
111 	return num_units;
112 }
113 
114 /* Host mem size units, it is used for round-off */
115 #define HOST_MEM_SIZE_UNIT 4
116 
117 /**
118  *  init_deinit_alloc_host_mem() - allocates amount of memory requested by FW.
119  *  @psoc: PSOC object
120  *  @tgt_hdl: Target PSOC info
121  *  @req_id: request id
122  *  @num_units: Number of units
123  *  @unit_len: Unit length
124  *  @num_unit_info: Num unit info
125  *
126  *  API to allocate host memory requested by FW
127  *
128  *  Return: QDF_STATUS_SUCCESS on successful allocation
129  *          QDF_STATUS_E_FAILURE on failure
130  */
131 static QDF_STATUS init_deinit_alloc_host_mem(struct wlan_objmgr_psoc *psoc,
132 		struct target_psoc_info *tgt_hdl, u_int32_t req_id,
133 		u_int32_t num_units, u_int32_t unit_len,
134 		u_int32_t num_unit_info)
135 {
136 	struct tgt_info *info;
137 	uint32_t remaining_units;
138 	uint32_t allocated_units = 0;
139 	uint32_t idx;
140 
141 	info = (&tgt_hdl->info);
142 	/* adjust the length to nearest multiple of unit size */
143 	unit_len = (unit_len + (HOST_MEM_SIZE_UNIT - 1)) &
144 				(~(HOST_MEM_SIZE_UNIT - 1));
145 	idx = info->num_mem_chunks;
146 	remaining_units = num_units;
147 
148 	while (remaining_units) {
149 		if (idx == MAX_MEM_CHUNKS) {
150 			target_if_err(
151 				"REACHED MAX CHUNK LIMIT for mem units %d",
152 					num_units);
153 			target_if_err(
154 			"unit len %d requested by FW, only allocated %d",
155 				unit_len, (num_units - remaining_units));
156 			info->num_mem_chunks = idx;
157 			return QDF_STATUS_E_FAILURE;
158 		}
159 
160 		if ((tgt_hdl->tif_ops) &&
161 		    (tgt_hdl->tif_ops->mem_mgr_alloc_chunk))
162 			allocated_units = tgt_hdl->tif_ops->mem_mgr_alloc_chunk(
163 						psoc, tgt_hdl, req_id, idx,
164 						remaining_units,
165 						unit_len, num_unit_info);
166 		else
167 			allocated_units = init_deinit_alloc_host_mem_chunk(
168 						psoc, tgt_hdl, req_id, idx,
169 						remaining_units,
170 						unit_len, num_unit_info);
171 		if (allocated_units == 0) {
172 			target_if_err("FAILED TO ALLOC mem unit len %d",
173 				      unit_len);
174 			target_if_err("units requested %d units allocated %d",
175 				      num_units, (num_units - remaining_units));
176 			info->num_mem_chunks = idx;
177 			return QDF_STATUS_E_NOMEM;
178 		}
179 		remaining_units -= allocated_units;
180 		++idx;
181 	}
182 	info->num_mem_chunks = idx;
183 
184 	return QDF_STATUS_SUCCESS;
185 }
186 
187 QDF_STATUS init_deinit_free_num_units(struct wlan_objmgr_psoc *psoc,
188 			struct target_psoc_info *tgt_hdl)
189 {
190 	struct tgt_info *info;
191 	qdf_device_t qdf_dev;
192 	uint32_t idx;
193 	QDF_STATUS status;
194 
195 	if (!tgt_hdl) {
196 		target_if_err("target_psoc_info is null");
197 		return QDF_STATUS_E_INVAL;
198 	}
199 
200 	if ((tgt_hdl->tif_ops) &&
201 	    (tgt_hdl->tif_ops->mem_mgr_free_chunks)) {
202 		status = tgt_hdl->tif_ops->mem_mgr_free_chunks(psoc, tgt_hdl);
203 	} else {
204 		qdf_dev = wlan_psoc_get_qdf_dev(psoc);
205 		if (!qdf_dev) {
206 			target_if_err("qdf_dev is null");
207 			QDF_BUG(0);
208 			return QDF_STATUS_E_INVAL;
209 		}
210 		info = (&tgt_hdl->info);
211 		for (idx = 0; idx < info->num_mem_chunks; idx++) {
212 			qdf_mem_free_consistent(
213 					qdf_dev, qdf_dev->dev,
214 					info->mem_chunks[idx].len,
215 					info->mem_chunks[idx].vaddr,
216 					info->mem_chunks[idx].paddr,
217 					qdf_get_dma_mem_context(
218 					(&info->mem_chunks[idx]), memctx));
219 
220 			info->mem_chunks[idx].vaddr = NULL;
221 			info->mem_chunks[idx].paddr = 0;
222 			info->mem_chunks[idx].len = 0;
223 		}
224 		info->num_mem_chunks = 0;
225 		status = QDF_STATUS_SUCCESS;
226 	}
227 
228 	return status;
229 }
230 
231 QDF_STATUS init_deinit_handle_host_mem_req(
232 		struct wlan_objmgr_psoc *psoc,
233 		struct target_psoc_info *tgt_hdl, uint8_t *event)
234 {
235 	uint32_t num_mem_reqs;
236 	host_mem_req mem_reqs;
237 	uint32_t i;
238 	uint32_t idx;
239 	QDF_STATUS status = QDF_STATUS_SUCCESS;
240 	struct wmi_unified *wmi_handle;
241 	struct tgt_info *info;
242 
243 	if (!tgt_hdl) {
244 		target_if_err("target_psoc_info is null");
245 		return QDF_STATUS_E_INVAL;
246 	}
247 
248 	wmi_handle = target_psoc_get_wmi_hdl(tgt_hdl);
249 	info = (&tgt_hdl->info);
250 
251 	num_mem_reqs = wmi_extract_num_mem_reqs_from_service_ready(
252 							wmi_handle, event);
253 	if (!num_mem_reqs)
254 		return QDF_STATUS_SUCCESS;
255 
256 	if (num_mem_reqs > MAX_MEM_CHUNKS) {
257 		target_if_err_rl("num_mem_reqs:%u is out of bounds",
258 				num_mem_reqs);
259 		return QDF_STATUS_E_FAILURE;
260 	}
261 
262 	for (i = 0; i < WMI_FW_PRIORITY_MAX; i++) {
263 		for (idx = 0; idx < num_mem_reqs; idx++) {
264 			status = wmi_extract_host_mem_req_from_service_ready(
265 					wmi_handle, event, &mem_reqs,
266 					info->wlan_res_cfg.num_active_peers,
267 					info->wlan_res_cfg.num_peers, i, idx);
268 			if (mem_reqs.tgt_num_units) {
269 				status = init_deinit_alloc_host_mem(
270 						psoc,
271 						tgt_hdl,
272 						mem_reqs.req_id,
273 						mem_reqs.tgt_num_units,
274 						mem_reqs.unit_size,
275 						mem_reqs.num_unit_info);
276 				if (status == QDF_STATUS_E_FAILURE) {
277 					target_if_err("num_mem_chunk exceeds supp number");
278 				} else if (status == QDF_STATUS_E_NOMEM) {
279 					target_if_err("mem alloc failure");
280 				}
281 			}
282 
283 			if (status != QDF_STATUS_SUCCESS)
284 				return status;
285 		}
286 	}
287 
288 	return status;
289 }
290 
291 #ifdef FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT
292 /**
293  * is_num_band_to_mac_required() - host needs to configure MACs or not.
294  * @tgt_hdl: Pointer to target handle
295  *
296  * if num of mac per band is sent by host then FW will not initialize
297  * its data structure with its default value. Host either have to set
298  * these value as per current HW mode or else these variable should be
299  * initialized to 0.
300  * Ex - If host is sending default HW mode as DBS in INIT_CMDID and FW
301  * doesn't advertise wmi_service_dual_band_simultaneous_support then host
302  * must not configure MACs and FW should configure with default values.
303  *
304  * @return: true if host needs to configure MACs else false
305  */
306 static bool is_num_band_to_mac_required(struct target_psoc_info *tgt_hdl)
307 {
308 	struct tgt_info *info;
309 	struct wmi_unified *wmi_handle;
310 
311 	if (!tgt_hdl)
312 		return true;
313 
314 	wmi_handle = target_psoc_get_wmi_hdl(tgt_hdl);
315 	info = (&tgt_hdl->info);
316 
317 	if ((info->hw_modes.num_modes == 1) &&
318 	    (info->hw_modes.hw_mode_ids[0] == WMI_HOST_HW_MODE_DBS) &&
319 	    !wmi_service_enabled(wmi_handle,
320 				 wmi_service_dual_band_simultaneous_support))
321 		return false;
322 
323 	return true;
324 }
325 #else
326 static bool is_num_band_to_mac_required(struct target_psoc_info *tgt_hdl)
327 {
328 	return true;
329 }
330 #endif
331 
332 void init_deinit_derive_band_to_mac_param(
333 		struct wlan_objmgr_psoc *psoc,
334 		struct target_psoc_info *tgt_hdl,
335 		struct wmi_init_cmd_param *init_param)
336 {
337 	uint8_t i;
338 	struct wlan_psoc_host_mac_phy_caps *mac_phy_cap;
339 	struct wlan_psoc_host_hal_reg_capabilities_ext *reg_cap;
340 	struct wmi_host_pdev_band_to_mac *band_to_mac = init_param->band_to_mac;
341 
342 	if (!tgt_hdl) {
343 		target_if_err("target_psoc_info is null ");
344 		return;
345 	}
346 
347 	reg_cap = ucfg_reg_get_hal_reg_cap(psoc);
348 	if (!reg_cap) {
349 		target_if_err("reg cap is NULL");
350 		return;
351 	}
352 
353 	mac_phy_cap = target_psoc_get_mac_phy_cap(tgt_hdl);
354 	if (!mac_phy_cap) {
355 		target_if_err("mac_phy_cap is NULL");
356 		return;
357 	}
358 	if (is_num_band_to_mac_required(tgt_hdl))
359 		init_param->num_band_to_mac =
360 			target_psoc_get_num_radios(tgt_hdl);
361 
362 	for (i = 0; i < target_psoc_get_num_radios(tgt_hdl); i++) {
363 		if (mac_phy_cap->supported_bands ==
364 			(WMI_HOST_WLAN_5G_CAPABILITY |
365 					WMI_HOST_WLAN_2G_CAPABILITY)) {
366 			/*Supports both 5G and 2G. Use freq from both radios*/
367 			target_if_debug("Supports both 2G and 5G");
368 			band_to_mac[i].pdev_id = mac_phy_cap->pdev_id;
369 			band_to_mac[i].start_freq =
370 					reg_cap[i].low_2ghz_chan;
371 			band_to_mac[i].end_freq =
372 					reg_cap[i].high_5ghz_chan;
373 
374 		} else if (mac_phy_cap->supported_bands ==
375 				WMI_HOST_WLAN_2G_CAPABILITY) {
376 			reg_cap[mac_phy_cap->phy_id].low_5ghz_chan = 0;
377 			reg_cap[mac_phy_cap->phy_id].high_5ghz_chan = 0;
378 
379 			if (!init_param->num_band_to_mac)
380 				goto next_mac_phy_cap;
381 
382 			band_to_mac[i].pdev_id = mac_phy_cap->pdev_id;
383 			band_to_mac[i].start_freq =
384 					reg_cap[i].low_2ghz_chan;
385 			band_to_mac[i].end_freq =
386 					reg_cap[i].high_2ghz_chan;
387 			target_if_debug("2G radio - pdev_id = %d start_freq = %d end_freq= %d",
388 				       band_to_mac[i].pdev_id,
389 				       band_to_mac[i].start_freq,
390 				       band_to_mac[i].end_freq);
391 
392 		} else if (mac_phy_cap->supported_bands ==
393 					WMI_HOST_WLAN_5G_CAPABILITY) {
394 			reg_cap[mac_phy_cap->phy_id].low_2ghz_chan = 0;
395 			reg_cap[mac_phy_cap->phy_id].high_2ghz_chan = 0;
396 
397 			if (!init_param->num_band_to_mac)
398 				goto next_mac_phy_cap;
399 
400 			band_to_mac[i].pdev_id = mac_phy_cap->pdev_id;
401 			band_to_mac[i].start_freq =
402 						reg_cap[i].low_5ghz_chan;
403 			band_to_mac[i].end_freq =
404 						reg_cap[i].high_5ghz_chan;
405 
406 			target_if_debug("5G radio -pdev_id = %d start_freq = %d end_freq =%d\n",
407 				       band_to_mac[i].pdev_id,
408 				       band_to_mac[i].start_freq,
409 				       band_to_mac[i].end_freq);
410 		}
411 
412 next_mac_phy_cap:
413 		mac_phy_cap++;
414 	}
415 }
416 
417 #if defined(CONFIG_AFC_SUPPORT)
418 /**
419  * init_deinit_derive_afc_dev_type_param() - Derive AFC init deployment param
420  *
421  * @psoc: PSOC object
422  * @init_param: Pointer to init param
423  *
424  * Return: void
425  */
426 static void init_deinit_derive_afc_dev_type_param(
427 		struct wlan_objmgr_psoc *psoc,
428 		struct wmi_init_cmd_param *init_param)
429 {
430 	enum reg_afc_dev_deploy_type reg_afc_dev_type;
431 	target_resource_config *tgt_cfg;
432 	QDF_STATUS ret_val;
433 
434 	tgt_cfg = init_param->res_cfg;
435 
436 	ret_val = target_if_reg_get_afc_dev_type(psoc,
437 						 &reg_afc_dev_type);
438 
439 	if (QDF_IS_STATUS_ERROR(ret_val)) {
440 		target_if_err("get afc dev type failed");
441 		return;
442 	}
443 	tgt_cfg->afc_indoor_support = false;
444 	tgt_cfg->afc_outdoor_support = false;
445 	if (reg_afc_dev_type == AFC_DEPLOYMENT_INDOOR)
446 		tgt_cfg->afc_indoor_support = true;
447 	else if (reg_afc_dev_type == AFC_DEPLOYMENT_OUTDOOR)
448 		tgt_cfg->afc_outdoor_support = true;
449 }
450 #else
451 static inline void init_deinit_derive_afc_dev_type_param(
452 		struct wlan_objmgr_psoc *psoc,
453 		struct wmi_init_cmd_param *init_param)
454 {
455 }
456 #endif
457 
458 void init_deinit_prepare_send_init_cmd(
459 		 struct wlan_objmgr_psoc *psoc,
460 		 struct target_psoc_info *tgt_hdl)
461 {
462 	struct wmi_init_cmd_param init_param = {0};
463 	struct tgt_info *info;
464 	struct wmi_unified *wmi_handle;
465 	QDF_STATUS ret_val;
466 	uint32_t fw_build_vers_ext;
467 
468 	if (!tgt_hdl) {
469 		target_if_err("target_psoc_info is null");
470 		return;
471 	}
472 
473 	wmi_handle = target_psoc_get_wmi_hdl(tgt_hdl);
474 	info = (&tgt_hdl->info);
475 
476 	init_param.res_cfg = &info->wlan_res_cfg;
477 	init_param.num_mem_chunks = info->num_mem_chunks;
478 	init_param.mem_chunks = info->mem_chunks;
479 
480 	if (init_deinit_is_service_ext_msg(psoc, tgt_hdl) ==
481 			QDF_STATUS_SUCCESS) {
482 		init_param.hw_mode_id = info->preferred_hw_mode;
483 		/* Temp change, until FW submits support for handling this TLV
484 		 * For single mode, skip sending hw_mode
485 		 */
486 		if (info->preferred_hw_mode == WMI_HOST_HW_MODE_SINGLE)
487 			init_param.hw_mode_id = WMI_HOST_HW_MODE_MAX;
488 
489 		init_deinit_derive_band_to_mac_param(psoc, tgt_hdl,
490 						     &init_param);
491 	} else {
492 		ret_val = tgt_if_regulatory_modify_freq_range(psoc);
493 		if (QDF_IS_STATUS_ERROR(ret_val)) {
494 			target_if_err("Modify freq range is failed");
495 			return;
496 		}
497 	}
498 
499 	ret_val = target_if_alloc_pdevs(psoc, tgt_hdl);
500 	if (ret_val != QDF_STATUS_SUCCESS)
501 		return;
502 
503 	ret_val = target_if_update_pdev_tgt_info(psoc, tgt_hdl);
504 	if (ret_val != QDF_STATUS_SUCCESS)
505 		return;
506 
507 	info->wlan_res_cfg.max_ndp_sessions =
508 		QDF_MIN(info->wlan_res_cfg.max_ndp_sessions,
509 			info->service_ext2_param.max_ndp_sessions);
510 
511 	if (info->service_ext2_param.twt_ack_support_cap) {
512 		info->wlan_res_cfg.twt_ack_support_cap = true;
513 		target_if_twt_set_twt_ack_support(psoc, true);
514 	}
515 
516 	info->wlan_res_cfg.target_cap_flags =
517 		target_psoc_get_target_cap_flags(tgt_hdl);
518 
519 	target_if_debug("FW version 0x%x ", info->target_caps.fw_version);
520 	if (init_deinit_is_service_ext_msg(psoc, tgt_hdl) ==
521 							QDF_STATUS_SUCCESS) {
522 		fw_build_vers_ext = info->service_ext_param.fw_build_vers_ext;
523 		target_if_debug("fw_build_vers_ext:0x%x HDL version info:0x%0x, CRM sub ID:0x%x\n",
524 				fw_build_vers_ext, fw_build_vers_ext & 0x3FF,
525 				(fw_build_vers_ext >> 25) & 0x7F);
526 	} else {
527 		target_if_debug("0x%x\n", info->target_caps.fw_version_1);
528 	}
529 
530 	if (wmi_service_enabled(wmi_handle, wmi_service_ext2_msg))
531 		init_deinit_derive_afc_dev_type_param(psoc, &init_param);
532 
533 	target_if_ext_res_cfg_enable(psoc, tgt_hdl, NULL);
534 
535 	target_if_set_reo_shared_qref_feature(psoc, info);
536 
537 	wmi_unified_init_cmd_send(wmi_handle, &init_param);
538 
539 	/* Set Max scans allowed */
540 	target_if_scan_set_max_active_scans(psoc,
541 					    WLAN_MAX_ACTIVE_SCANS_ALLOWED);
542 
543 	if (wmi_service_enabled(wmi_handle, wmi_service_hw_db2dbm_support))
544 		wlan_psoc_nif_fw_ext_cap_set(psoc, WLAN_SOC_CEXT_HW_DB2DBM);
545 }
546