xref: /wlan-dirver/qca-wifi-host-cmn/target_if/init_deinit/src/init_cmd_api.c (revision 1b9674e21e24478fba4530f5ae7396b9555e9c6a)
1 /*
2  * Copyright (c) 2018 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 <wlan_defs.h>
34 #include <target_if_scan.h>
35 #include <target_if_reg.h>
36 
37 /**
38  *  init_deinit_alloc_host_mem_chunk() - allocates chunk of memory requested
39  *                                       by FW.
40  *  @psoc: PSOC object
41  *  @tgt_hdl: Target PSOC info
42  *  @req_id: request id
43  *  @idx: chunk id
44  *  @num_units: Number of units
45  *  @unit_len: Unit length
46  *  @num_unit_info: Num unit info
47  *
48  *  API to allocate host memory chunk requested by FW
49  *
50  *  Return: num_units on successful allocation
51  *          0 on failure
52  */
53 static uint32_t init_deinit_alloc_host_mem_chunk(struct wlan_objmgr_psoc *psoc,
54 			struct target_psoc_info *tgt_hdl,
55 			u_int32_t req_id, u_int32_t idx, u_int32_t num_units,
56 			u_int32_t unit_len, u_int32_t num_unit_info)
57 {
58 	qdf_dma_addr_t paddr;
59 	uint32_t ichunk = 0;
60 	struct tgt_info *info;
61 	qdf_device_t qdf_dev;
62 
63 	info = (&tgt_hdl->info);
64 
65 	if (!num_units  || !unit_len)
66 		return 0;
67 
68 	qdf_dev = wlan_psoc_get_qdf_dev(psoc);
69 	if (!qdf_dev)
70 		return 0;
71 
72 	/*
73 	 * We have skip smaller chunks memory allocation for TXBF_CV buffer
74 	 * as Firmware is expecting continuous memory
75 	 */
76 	if (!((num_unit_info & HOST_CONTIGUOUS_MEM_CHUNK_REQUIRED) &&
77 	      (req_id == TXBF_CV_POOL0 || req_id == TXBF_CV_POOL1 ||
78 	      req_id == TXBF_CV_POOL2))) {
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 == NULL) {
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 /**
186  *  init_deinit_alloc_num_units() - allocates num units requested by FW.
187  *  @psoc: PSOC object
188  *  @tgt_hdl: Target PSOC info
189  *  @mem_reqs: pointer to mem req
190  *  @num_units: Number
191  *  @i: FW priority
192  *  @idx: Index
193  *
194  *  API to allocate num units of host memory requested by FW
195  *
196  *  Return: QDF_STATUS_SUCCESS on successful allocation
197  *          QDF_STATUS_E_FAILURE on failure
198  */
199 static QDF_STATUS init_deinit_alloc_num_units(struct wlan_objmgr_psoc *psoc,
200 			struct target_psoc_info *tgt_hdl,
201 			host_mem_req *mem_reqs, uint16_t fw_prio,
202 			uint16_t idx)
203 {
204 	struct tgt_info *info;
205 	uint32_t num_units;
206 	QDF_STATUS status;
207 
208 	if (!tgt_hdl) {
209 		target_if_err("target_psoc_info is null");
210 		return QDF_STATUS_E_INVAL;
211 	}
212 
213 	info = (&tgt_hdl->info);
214 
215 	if (((fw_prio == FW_MEM_HIGH_PRIORITY) &&
216 	     (mem_reqs[idx].num_unit_info &
217 			HOST_CONTIGUOUS_MEM_CHUNK_REQUIRED)) ||
218 	    ((fw_prio == FW_MEM_LOW_PRIORITY) &&
219 			(!(mem_reqs[idx].num_unit_info &
220 				HOST_CONTIGUOUS_MEM_CHUNK_REQUIRED)))) {
221 		/* First allocate the memory that requires contiguous memory */
222 		num_units = mem_reqs[idx].num_units;
223 		if (mem_reqs[idx].num_unit_info) {
224 			if (mem_reqs[idx].num_unit_info &
225 					NUM_UNITS_IS_NUM_PEERS) {
226 				/*
227 				 * number of units allocated is equal to number
228 				 * of peers, 1 extra for self peer on target.
229 				 * this needs to be fixed, host and target can
230 				 * get out of sync
231 				 */
232 				num_units = info->wlan_res_cfg.num_peers + 1;
233 			}
234 			if (mem_reqs[idx].num_unit_info &
235 				NUM_UNITS_IS_NUM_ACTIVE_PEERS) {
236 				/*
237 				 * Requesting allocation of memory using
238 				 * num_active_peers in qcache. if qcache is
239 				 * disabled in host, then it should allocate
240 				 * memory for num_peers instead of
241 				 * num_active_peers.
242 				 */
243 				if (info->wlan_res_cfg.num_active_peers)
244 					num_units =
245 					info->wlan_res_cfg.num_active_peers + 1;
246 				else
247 					num_units =
248 					info->wlan_res_cfg.num_peers + 1;
249 			}
250 		}
251 
252 		target_if_debug("idx %d req %d  num_units %d num_unit_info %d unit size %d actual units %d",
253 				idx, mem_reqs[idx].req_id,
254 				mem_reqs[idx].num_units,
255 				mem_reqs[idx].num_unit_info,
256 				mem_reqs[idx].unit_size, num_units);
257 
258 		status = init_deinit_alloc_host_mem(psoc, tgt_hdl,
259 				mem_reqs[idx].req_id, num_units,
260 				mem_reqs[idx].unit_size,
261 				mem_reqs[idx].num_unit_info);
262 		if (status == QDF_STATUS_E_FAILURE) {
263 			target_if_err(
264 				"psoc:(%pK) num_mem_chunk exceeds supp number",
265 									psoc);
266 			return QDF_STATUS_E_FAILURE;
267 		} else if (status == QDF_STATUS_E_NOMEM) {
268 			target_if_err("soc:(%pK) mem alloc failure", psoc);
269 			return QDF_STATUS_E_NOMEM;
270 		}
271 	}
272 
273 	return QDF_STATUS_SUCCESS;
274 }
275 
276 QDF_STATUS init_deinit_free_num_units(struct wlan_objmgr_psoc *psoc,
277 			struct target_psoc_info *tgt_hdl)
278 {
279 	struct tgt_info *info;
280 	qdf_device_t qdf_dev;
281 	uint32_t idx;
282 	QDF_STATUS status;
283 
284 	if (!tgt_hdl) {
285 		target_if_err("target_psoc_info is null");
286 		return QDF_STATUS_E_INVAL;
287 	}
288 
289 	if ((tgt_hdl->tif_ops) &&
290 	    (tgt_hdl->tif_ops->mem_mgr_free_chunks)) {
291 		status = tgt_hdl->tif_ops->mem_mgr_free_chunks(psoc, tgt_hdl);
292 	} else {
293 		qdf_dev = wlan_psoc_get_qdf_dev(psoc);
294 		if (!qdf_dev) {
295 			target_if_err("qdf_dev is null");
296 			QDF_BUG(0);
297 			return QDF_STATUS_E_INVAL;
298 		}
299 		info = (&tgt_hdl->info);
300 		for (idx = 0; idx < info->num_mem_chunks; idx++) {
301 			qdf_mem_free_consistent(
302 				qdf_dev, qdf_dev->dev,
303 				info->mem_chunks[idx].len,
304 				info->mem_chunks[idx].vaddr,
305 				info->mem_chunks[idx].paddr,
306 				qdf_get_dma_mem_context(
307 					(&(info->mem_chunks[idx])), memctx));
308 
309 			info->mem_chunks[idx].vaddr = NULL;
310 			info->mem_chunks[idx].paddr = 0;
311 			info->mem_chunks[idx].len = 0;
312 		}
313 		info->num_mem_chunks = 0;
314 		status = QDF_STATUS_SUCCESS;
315 	}
316 
317 	return status;
318 }
319 
320 QDF_STATUS init_deinit_handle_host_mem_req(
321 		 struct wlan_objmgr_psoc *psoc,
322 		 struct target_psoc_info *tgt_hdl, uint8_t *event)
323 {
324 	uint8_t num_mem_reqs;
325 	host_mem_req *mem_reqs;
326 	uint32_t i;
327 	uint32_t idx;
328 	QDF_STATUS status = QDF_STATUS_SUCCESS;
329 	struct common_wmi_handle *wmi_handle;
330 	struct tgt_info *info;
331 
332 	if (!tgt_hdl) {
333 		target_if_err("target_psoc_info is null");
334 		return QDF_STATUS_E_INVAL;
335 	}
336 
337 	wmi_handle = target_psoc_get_wmi_hdl(tgt_hdl);
338 	info = (&tgt_hdl->info);
339 
340 	mem_reqs = wmi_extract_host_mem_req_from_service_ready(
341 					wmi_handle, event, &num_mem_reqs);
342 	if (!num_mem_reqs)
343 		return QDF_STATUS_SUCCESS;
344 
345 	for (i = 0; i < FW_PRIORITY_MAX; i++) {
346 		for (idx = 0; idx < num_mem_reqs; idx++) {
347 			status = init_deinit_alloc_num_units(psoc, tgt_hdl,
348 				mem_reqs, i, idx);
349 			if (status != QDF_STATUS_SUCCESS)
350 				return status;
351 		}
352 	}
353 
354 	return status;
355 }
356 
357 void init_deinit_derive_band_to_mac_param(
358 		struct wlan_objmgr_psoc *psoc,
359 		struct target_psoc_info *tgt_hdl,
360 		struct wmi_host_pdev_band_to_mac *band_to_mac)
361 {
362 	uint8_t i;
363 	struct wlan_psoc_host_mac_phy_caps *mac_phy_cap;
364 	struct wlan_psoc_host_hal_reg_capabilities_ext *reg_cap;
365 	struct tgt_info *info;
366 
367 	if (!tgt_hdl) {
368 		target_if_err("target_psoc_info is null ");
369 		return;
370 	}
371 
372 	info = (&tgt_hdl->info);
373 
374 	reg_cap = ucfg_reg_get_hal_reg_cap(psoc);
375 	if (!reg_cap) {
376 		target_if_err("reg cap is NULL");
377 		return;
378 	}
379 
380 	for (i = 0; i < target_psoc_get_num_radios(tgt_hdl); i++) {
381 		mac_phy_cap = &info->mac_phy_cap[i];
382 		if (mac_phy_cap->supported_bands ==
383 			(WMI_HOST_WLAN_5G_CAPABILITY |
384 					WMI_HOST_WLAN_2G_CAPABILITY)) {
385 			/*Supports both 5G and 2G. Use freq from both radios*/
386 			target_if_debug("Supports both 2G and 5G");
387 			band_to_mac[i].pdev_id = mac_phy_cap->pdev_id;
388 			band_to_mac[i].start_freq =
389 					reg_cap[i].low_2ghz_chan;
390 			band_to_mac[i].end_freq =
391 					reg_cap[i].high_5ghz_chan;
392 
393 		} else if (mac_phy_cap->supported_bands ==
394 				WMI_HOST_WLAN_2G_CAPABILITY) {
395 			band_to_mac[i].pdev_id = mac_phy_cap->pdev_id;
396 			band_to_mac[i].start_freq =
397 					reg_cap[i].low_2ghz_chan;
398 			band_to_mac[i].end_freq =
399 					reg_cap[i].high_2ghz_chan;
400 
401 			reg_cap[mac_phy_cap->phy_id].low_5ghz_chan = 0;
402 			reg_cap[mac_phy_cap->phy_id].high_5ghz_chan = 0;
403 
404 			target_if_debug("2G radio - pdev_id = %d start_freq = %d end_freq= %d",
405 					band_to_mac[i].pdev_id,
406 					band_to_mac[i].start_freq,
407 					band_to_mac[i].end_freq);
408 
409 		} else if (mac_phy_cap->supported_bands ==
410 					WMI_HOST_WLAN_5G_CAPABILITY) {
411 			band_to_mac[i].pdev_id = mac_phy_cap->pdev_id;
412 			band_to_mac[i].start_freq =
413 						reg_cap[i].low_5ghz_chan;
414 			band_to_mac[i].end_freq =
415 						reg_cap[i].high_5ghz_chan;
416 
417 			reg_cap[mac_phy_cap->phy_id].low_2ghz_chan = 0;
418 			reg_cap[mac_phy_cap->phy_id].high_2ghz_chan = 0;
419 
420 			target_if_debug("5G radio -pdev_id = %d start_freq = %d end_freq =%d\n",
421 					band_to_mac[i].pdev_id,
422 					band_to_mac[i].start_freq,
423 					band_to_mac[i].end_freq);
424 		}
425 	}
426 }
427 
428 void init_deinit_prepare_send_init_cmd(
429 		 struct wlan_objmgr_psoc *psoc,
430 		 struct target_psoc_info *tgt_hdl)
431 {
432 	struct wmi_init_cmd_param init_param = {0};
433 	struct tgt_info *info;
434 	struct common_wmi_handle *wmi_handle;
435 	QDF_STATUS ret_val;
436 
437 	if (!tgt_hdl) {
438 		target_if_err("target_psoc_info is null");
439 		return;
440 	}
441 
442 	wmi_handle = target_psoc_get_wmi_hdl(tgt_hdl);
443 	info = (&tgt_hdl->info);
444 
445 	init_param.res_cfg = &info->wlan_res_cfg;
446 	init_param.num_mem_chunks = info->num_mem_chunks;
447 	init_param.mem_chunks = info->mem_chunks;
448 
449 	if (init_deinit_is_service_ext_msg(psoc, tgt_hdl) ==
450 			QDF_STATUS_SUCCESS) {
451 		init_param.hw_mode_id = info->preferred_hw_mode;
452 		/* Temp change, until FW submits support for handling this TLV
453 		 * For single mode, skip sending hw_mode
454 		 */
455 		if (info->preferred_hw_mode == WMI_HOST_HW_MODE_SINGLE)
456 			init_param.hw_mode_id = WMI_HOST_HW_MODE_MAX;
457 
458 		init_param.num_band_to_mac = target_psoc_get_num_radios(
459 								tgt_hdl);
460 
461 		init_deinit_derive_band_to_mac_param(psoc, tgt_hdl,
462 						     init_param.band_to_mac);
463 	} else {
464 		ret_val = tgt_if_regulatory_modify_freq_range(psoc);
465 		if (QDF_IS_STATUS_ERROR(ret_val)) {
466 			target_if_err("Modify freq range is failed");
467 			return;
468 		}
469 	}
470 
471 	ret_val = target_if_alloc_pdevs(psoc, tgt_hdl);
472 	if (ret_val != QDF_STATUS_SUCCESS)
473 		return;
474 
475 	ret_val = target_if_update_pdev_tgt_info(psoc, tgt_hdl);
476 	if (ret_val != QDF_STATUS_SUCCESS)
477 		return;
478 
479 	target_if_info("FW version 0x%x ", info->target_caps.fw_version);
480 	if (init_deinit_is_service_ext_msg(psoc, tgt_hdl) == QDF_STATUS_SUCCESS)
481 		target_if_info("0x%x\n",
482 			       info->service_ext_param.fw_build_vers_ext);
483 	else
484 		target_if_info("0x%x\n", info->target_caps.fw_version_1);
485 
486 	wmi_unified_init_cmd_send(wmi_handle, &init_param);
487 
488 	/* Set Max scans allowed */
489 	target_if_scan_set_max_active_scans(psoc,
490 					    WLAN_MAX_ACTIVE_SCANS_ALLOWED);
491 }
492