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