xref: /wlan-dirver/qca-wifi-host-cmn/target_if/init_deinit/src/init_cmd_api.c (revision 6d768494e5ce14eb1603a695c86739d12ecc6ec2)
1 /*
2  * Copyright (c) 2018-2020 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 buffer
73 	 * 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 		ichunk = ((num_units * unit_len) >>
79 			HOST_MEM_CHUNK_MAX_SIZE_POWER2);
80 		if (ichunk)
81 			num_units = num_units / (ichunk + 1);
82 	}
83 
84 	info->mem_chunks[idx].vaddr = NULL;
85 	/* reduce the requested allocation by half until allocation succeeds */
86 	while (!info->mem_chunks[idx].vaddr && num_units) {
87 		info->mem_chunks[idx].vaddr = qdf_mem_alloc_consistent(qdf_dev,
88 				qdf_dev->dev, num_units * unit_len, &paddr);
89 		if (!info->mem_chunks[idx].vaddr) {
90 			if (num_unit_info &
91 					HOST_CONTIGUOUS_MEM_CHUNK_REQUIRED) {
92 				num_units = 0;
93 				target_if_err("mem chink alloc failed for %d",
94 					      idx);
95 				break;
96 			}
97 			/* reduce length by half */
98 			num_units = (num_units >> 1);
99 		} else {
100 			info->mem_chunks[idx].paddr = paddr;
101 			info->mem_chunks[idx].len = num_units*unit_len;
102 			info->mem_chunks[idx].req_id =  req_id;
103 		}
104 	}
105 	target_if_debug("req_id %d idx %d num_units %d unit_len %d",
106 			req_id, idx, num_units, unit_len);
107 
108 	return num_units;
109 }
110 
111 /* Host mem size units, it is used for round-off */
112 #define HOST_MEM_SIZE_UNIT 4
113 
114 /**
115  *  init_deinit_alloc_host_mem() - allocates amount of memory requested by FW.
116  *  @psoc: PSOC object
117  *  @tgt_hdl: Target PSOC info
118  *  @req_id: request id
119  *  @num_units: Number of units
120  *  @unit_len: Unit length
121  *  @num_unit_info: Num unit info
122  *
123  *  API to allocate host memory requested by FW
124  *
125  *  Return: QDF_STATUS_SUCCESS on successful allocation
126  *          QDF_STATUS_E_FAILURE on failure
127  */
128 static QDF_STATUS init_deinit_alloc_host_mem(struct wlan_objmgr_psoc *psoc,
129 		struct target_psoc_info *tgt_hdl, u_int32_t req_id,
130 		u_int32_t num_units, u_int32_t unit_len,
131 		u_int32_t num_unit_info)
132 {
133 	struct tgt_info *info;
134 	uint32_t remaining_units;
135 	uint32_t allocated_units = 0;
136 	uint32_t idx;
137 
138 	info = (&tgt_hdl->info);
139 	/* adjust the length to nearest multiple of unit size */
140 	unit_len = (unit_len + (HOST_MEM_SIZE_UNIT - 1)) &
141 				(~(HOST_MEM_SIZE_UNIT - 1));
142 	idx = info->num_mem_chunks;
143 	remaining_units = num_units;
144 
145 	while (remaining_units) {
146 		if (idx == MAX_MEM_CHUNKS) {
147 			target_if_err(
148 				"REACHED MAX CHUNK LIMIT for mem units %d",
149 					num_units);
150 			target_if_err(
151 			"unit len %d requested by FW, only allocated %d",
152 				unit_len, (num_units - remaining_units));
153 			info->num_mem_chunks = idx;
154 			return QDF_STATUS_E_FAILURE;
155 		}
156 
157 		if ((tgt_hdl->tif_ops) &&
158 		    (tgt_hdl->tif_ops->mem_mgr_alloc_chunk))
159 			allocated_units = tgt_hdl->tif_ops->mem_mgr_alloc_chunk(
160 						psoc, tgt_hdl, req_id, idx,
161 						remaining_units,
162 						unit_len, num_unit_info);
163 		else
164 			allocated_units = init_deinit_alloc_host_mem_chunk(
165 						psoc, tgt_hdl, req_id, idx,
166 						remaining_units,
167 						unit_len, num_unit_info);
168 		if (allocated_units == 0) {
169 			target_if_err("FAILED TO ALLOC mem unit len %d",
170 				      unit_len);
171 			target_if_err("units requested %d units allocated %d",
172 				      num_units, (num_units - remaining_units));
173 			info->num_mem_chunks = idx;
174 			return QDF_STATUS_E_NOMEM;
175 		}
176 		remaining_units -= allocated_units;
177 		++idx;
178 	}
179 	info->num_mem_chunks = idx;
180 
181 	return QDF_STATUS_SUCCESS;
182 }
183 
184 QDF_STATUS init_deinit_free_num_units(struct wlan_objmgr_psoc *psoc,
185 			struct target_psoc_info *tgt_hdl)
186 {
187 	struct tgt_info *info;
188 	qdf_device_t qdf_dev;
189 	uint32_t idx;
190 	QDF_STATUS status;
191 
192 	if (!tgt_hdl) {
193 		target_if_err("target_psoc_info is null");
194 		return QDF_STATUS_E_INVAL;
195 	}
196 
197 	if ((tgt_hdl->tif_ops) &&
198 	    (tgt_hdl->tif_ops->mem_mgr_free_chunks)) {
199 		status = tgt_hdl->tif_ops->mem_mgr_free_chunks(psoc, tgt_hdl);
200 	} else {
201 		qdf_dev = wlan_psoc_get_qdf_dev(psoc);
202 		if (!qdf_dev) {
203 			target_if_err("qdf_dev is null");
204 			QDF_BUG(0);
205 			return QDF_STATUS_E_INVAL;
206 		}
207 		info = (&tgt_hdl->info);
208 		for (idx = 0; idx < info->num_mem_chunks; idx++) {
209 			qdf_mem_free_consistent(
210 					qdf_dev, qdf_dev->dev,
211 					info->mem_chunks[idx].len,
212 					info->mem_chunks[idx].vaddr,
213 					info->mem_chunks[idx].paddr,
214 					qdf_get_dma_mem_context(
215 					(&info->mem_chunks[idx]), memctx));
216 
217 			info->mem_chunks[idx].vaddr = NULL;
218 			info->mem_chunks[idx].paddr = 0;
219 			info->mem_chunks[idx].len = 0;
220 		}
221 		info->num_mem_chunks = 0;
222 		status = QDF_STATUS_SUCCESS;
223 	}
224 
225 	return status;
226 }
227 
228 QDF_STATUS init_deinit_handle_host_mem_req(
229 		struct wlan_objmgr_psoc *psoc,
230 		struct target_psoc_info *tgt_hdl, uint8_t *event)
231 {
232 	uint32_t num_mem_reqs;
233 	host_mem_req mem_reqs;
234 	uint32_t i;
235 	uint32_t idx;
236 	QDF_STATUS status = QDF_STATUS_SUCCESS;
237 	struct wmi_unified *wmi_handle;
238 	struct tgt_info *info;
239 
240 	if (!tgt_hdl) {
241 		target_if_err("target_psoc_info is null");
242 		return QDF_STATUS_E_INVAL;
243 	}
244 
245 	wmi_handle = target_psoc_get_wmi_hdl(tgt_hdl);
246 	info = (&tgt_hdl->info);
247 
248 	num_mem_reqs = wmi_extract_num_mem_reqs_from_service_ready(
249 							wmi_handle, event);
250 	if (!num_mem_reqs)
251 		return QDF_STATUS_SUCCESS;
252 
253 	if (num_mem_reqs > MAX_MEM_CHUNKS) {
254 		target_if_err_rl("num_mem_reqs:%u is out of bounds",
255 				num_mem_reqs);
256 		return QDF_STATUS_E_FAILURE;
257 	}
258 
259 	for (i = 0; i < WMI_FW_PRIORITY_MAX; i++) {
260 		for (idx = 0; idx < num_mem_reqs; idx++) {
261 			status = wmi_extract_host_mem_req_from_service_ready(
262 					wmi_handle, event, &mem_reqs,
263 					info->wlan_res_cfg.num_active_peers,
264 					info->wlan_res_cfg.num_peers, i, idx);
265 			if (mem_reqs.tgt_num_units) {
266 				status = init_deinit_alloc_host_mem(
267 						psoc,
268 						tgt_hdl,
269 						mem_reqs.req_id,
270 						mem_reqs.tgt_num_units,
271 						mem_reqs.unit_size,
272 						mem_reqs.num_unit_info);
273 				if (status == QDF_STATUS_E_FAILURE) {
274 					target_if_err("num_mem_chunk exceeds supp number");
275 				} else if (status == QDF_STATUS_E_NOMEM) {
276 					target_if_err("mem alloc failure");
277 				}
278 			}
279 
280 			if (status != QDF_STATUS_SUCCESS)
281 				return status;
282 		}
283 	}
284 
285 	return status;
286 }
287 
288 void init_deinit_derive_band_to_mac_param(
289 		struct wlan_objmgr_psoc *psoc,
290 		struct target_psoc_info *tgt_hdl,
291 		struct wmi_host_pdev_band_to_mac *band_to_mac)
292 {
293 	uint8_t i;
294 	struct wlan_psoc_host_mac_phy_caps *mac_phy_cap;
295 	struct wlan_psoc_host_hal_reg_capabilities_ext *reg_cap;
296 	struct tgt_info *info;
297 
298 	if (!tgt_hdl) {
299 		target_if_err("target_psoc_info is null ");
300 		return;
301 	}
302 
303 	info = (&tgt_hdl->info);
304 
305 	reg_cap = ucfg_reg_get_hal_reg_cap(psoc);
306 	if (!reg_cap) {
307 		target_if_err("reg cap is NULL");
308 		return;
309 	}
310 
311 	mac_phy_cap = target_psoc_get_mac_phy_cap(tgt_hdl);
312 	if (!mac_phy_cap) {
313 		target_if_err("mac_phy_cap is NULL");
314 		return;
315 	}
316 	for (i = 0; i < target_psoc_get_num_radios(tgt_hdl); i++) {
317 		if (mac_phy_cap->supported_bands ==
318 			(WMI_HOST_WLAN_5G_CAPABILITY |
319 					WMI_HOST_WLAN_2G_CAPABILITY)) {
320 			/*Supports both 5G and 2G. Use freq from both radios*/
321 			target_if_debug("Supports both 2G and 5G");
322 			band_to_mac[i].pdev_id = mac_phy_cap->pdev_id;
323 			band_to_mac[i].start_freq =
324 					reg_cap[i].low_2ghz_chan;
325 			band_to_mac[i].end_freq =
326 					reg_cap[i].high_5ghz_chan;
327 
328 		} else if (mac_phy_cap->supported_bands ==
329 				WMI_HOST_WLAN_2G_CAPABILITY) {
330 			band_to_mac[i].pdev_id = mac_phy_cap->pdev_id;
331 			band_to_mac[i].start_freq =
332 					reg_cap[i].low_2ghz_chan;
333 			band_to_mac[i].end_freq =
334 					reg_cap[i].high_2ghz_chan;
335 
336 			reg_cap[mac_phy_cap->phy_id].low_5ghz_chan = 0;
337 			reg_cap[mac_phy_cap->phy_id].high_5ghz_chan = 0;
338 
339 			target_if_debug("2G radio - pdev_id = %d start_freq = %d end_freq= %d",
340 				       band_to_mac[i].pdev_id,
341 				       band_to_mac[i].start_freq,
342 				       band_to_mac[i].end_freq);
343 
344 		} else if (mac_phy_cap->supported_bands ==
345 					WMI_HOST_WLAN_5G_CAPABILITY) {
346 			band_to_mac[i].pdev_id = mac_phy_cap->pdev_id;
347 			band_to_mac[i].start_freq =
348 						reg_cap[i].low_5ghz_chan;
349 			band_to_mac[i].end_freq =
350 						reg_cap[i].high_5ghz_chan;
351 
352 			reg_cap[mac_phy_cap->phy_id].low_2ghz_chan = 0;
353 			reg_cap[mac_phy_cap->phy_id].high_2ghz_chan = 0;
354 
355 			target_if_debug("5G radio -pdev_id = %d start_freq = %d end_freq =%d\n",
356 				       band_to_mac[i].pdev_id,
357 				       band_to_mac[i].start_freq,
358 				       band_to_mac[i].end_freq);
359 		}
360 		mac_phy_cap++;
361 	}
362 }
363 
364 /* if num of mac per band is sent by host then FW will not initialize
365  * its data structure with its default value. Host either have to set
366  * these value as per current HW mode or else these variable should be
367  * initialized to 0.
368  * Ex - If host is sending default HW mode as DBS in INIT_CMDID
369  * then either host should fill both the MACs (mac0 and mac1) or
370  * else don't fill for even a single mac, it should be initialized to
371  * 0 which means FW will initialize its data structures based on its
372  * default value.
373  */
374 #ifdef FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT
375 static bool is_num_band_to_mac_required(struct wmi_unified *wmi_handle)
376 {
377 	bool is_required = true;
378 
379 	/* For target where interband MCC is not supported, num of
380 	 * mac should be set to default value i.e. 0
381 	 */
382 	is_required = (wmi_service_enabled(wmi_handle,
383 				wmi_service_dual_band_simultaneous_support) ||
384 		       !wmi_service_enabled(wmi_handle,
385 				wmi_service_no_interband_mcc_support));
386 	return is_required;
387 }
388 #else
389 static bool is_num_band_to_mac_required(struct wmi_unified *wmi_handle)
390 {
391 	return true;
392 }
393 #endif
394 
395 void init_deinit_prepare_send_init_cmd(
396 		 struct wlan_objmgr_psoc *psoc,
397 		 struct target_psoc_info *tgt_hdl)
398 {
399 	struct wmi_init_cmd_param init_param = {0};
400 	struct tgt_info *info;
401 	struct wmi_unified *wmi_handle;
402 	QDF_STATUS ret_val;
403 
404 	if (!tgt_hdl) {
405 		target_if_err("target_psoc_info is null");
406 		return;
407 	}
408 
409 	wmi_handle = target_psoc_get_wmi_hdl(tgt_hdl);
410 	info = (&tgt_hdl->info);
411 
412 	init_param.res_cfg = &info->wlan_res_cfg;
413 	init_param.num_mem_chunks = info->num_mem_chunks;
414 	init_param.mem_chunks = info->mem_chunks;
415 
416 	if (init_deinit_is_service_ext_msg(psoc, tgt_hdl) ==
417 			QDF_STATUS_SUCCESS) {
418 		init_param.hw_mode_id = info->preferred_hw_mode;
419 		/* Temp change, until FW submits support for handling this TLV
420 		 * For single mode, skip sending hw_mode
421 		 */
422 		if (info->preferred_hw_mode == WMI_HOST_HW_MODE_SINGLE)
423 			init_param.hw_mode_id = WMI_HOST_HW_MODE_MAX;
424 
425 		if (is_num_band_to_mac_required(wmi_handle))
426 			init_param.num_band_to_mac =
427 					 target_psoc_get_num_radios(tgt_hdl);
428 
429 		init_deinit_derive_band_to_mac_param(psoc, tgt_hdl,
430 						     init_param.band_to_mac);
431 	} else {
432 		ret_val = tgt_if_regulatory_modify_freq_range(psoc);
433 		if (QDF_IS_STATUS_ERROR(ret_val)) {
434 			target_if_err("Modify freq range is failed");
435 			return;
436 		}
437 	}
438 
439 	ret_val = target_if_alloc_pdevs(psoc, tgt_hdl);
440 	if (ret_val != QDF_STATUS_SUCCESS)
441 		return;
442 
443 	ret_val = target_if_update_pdev_tgt_info(psoc, tgt_hdl);
444 	if (ret_val != QDF_STATUS_SUCCESS)
445 		return;
446 
447 	info->wlan_res_cfg.max_ndp_sessions =
448 		QDF_MIN(info->wlan_res_cfg.max_ndp_sessions,
449 			info->service_ext2_param.max_ndp_sessions);
450 
451 	target_if_debug("FW version 0x%x ", info->target_caps.fw_version);
452 	if (init_deinit_is_service_ext_msg(psoc, tgt_hdl) == QDF_STATUS_SUCCESS)
453 		target_if_debug("0x%x\n",
454 				info->service_ext_param.fw_build_vers_ext);
455 	else
456 		target_if_debug("0x%x\n", info->target_caps.fw_version_1);
457 
458 	wmi_unified_init_cmd_send(wmi_handle, &init_param);
459 
460 	/* Set Max scans allowed */
461 	target_if_scan_set_max_active_scans(psoc,
462 					    WLAN_MAX_ACTIVE_SCANS_ALLOWED);
463 
464 	if (wmi_service_enabled(wmi_handle, wmi_service_hw_db2dbm_support))
465 		wlan_psoc_nif_fw_ext_cap_set(psoc, WLAN_SOC_CEXT_HW_DB2DBM);
466 }
467