xref: /wlan-dirver/qca-wifi-host-cmn/target_if/init_deinit/src/init_cmd_api.c (revision 11f5a63a6cbdda84849a730de22f0a71e635d58c)
1 /*
2  * Copyright (c) 2018-2019 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) {
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 || !mem_reqs) {
209 		target_if_err("Invalid parameters, tgt_hdl: %pK, mem_reqs: %pK",
210 			      tgt_hdl, mem_reqs);
211 		return QDF_STATUS_E_INVAL;
212 	}
213 
214 	info = (&tgt_hdl->info);
215 
216 	if (((fw_prio == FW_MEM_HIGH_PRIORITY) &&
217 	     (mem_reqs[idx].num_unit_info &
218 			HOST_CONTIGUOUS_MEM_CHUNK_REQUIRED)) ||
219 	    ((fw_prio == FW_MEM_LOW_PRIORITY) &&
220 			(!(mem_reqs[idx].num_unit_info &
221 				HOST_CONTIGUOUS_MEM_CHUNK_REQUIRED)))) {
222 		/* First allocate the memory that requires contiguous memory */
223 		num_units = mem_reqs[idx].num_units;
224 		if (mem_reqs[idx].num_unit_info) {
225 			if (mem_reqs[idx].num_unit_info &
226 					NUM_UNITS_IS_NUM_PEERS) {
227 				/*
228 				 * number of units allocated is equal to number
229 				 * of peers, 1 extra for self peer on target.
230 				 * this needs to be fixed, host and target can
231 				 * get out of sync
232 				 */
233 				num_units = info->wlan_res_cfg.num_peers + 1;
234 			}
235 			if (mem_reqs[idx].num_unit_info &
236 				NUM_UNITS_IS_NUM_ACTIVE_PEERS) {
237 				/*
238 				 * Requesting allocation of memory using
239 				 * num_active_peers in qcache. if qcache is
240 				 * disabled in host, then it should allocate
241 				 * memory for num_peers instead of
242 				 * num_active_peers.
243 				 */
244 				if (info->wlan_res_cfg.num_active_peers)
245 					num_units =
246 					info->wlan_res_cfg.num_active_peers + 1;
247 				else
248 					num_units =
249 					info->wlan_res_cfg.num_peers + 1;
250 			}
251 		}
252 
253 		target_if_debug("idx %d req %d  num_units %d num_unit_info %d unit size %d actual units %d",
254 				idx, mem_reqs[idx].req_id,
255 				mem_reqs[idx].num_units,
256 				mem_reqs[idx].num_unit_info,
257 				mem_reqs[idx].unit_size, num_units);
258 
259 		status = init_deinit_alloc_host_mem(psoc, tgt_hdl,
260 				mem_reqs[idx].req_id, num_units,
261 				mem_reqs[idx].unit_size,
262 				mem_reqs[idx].num_unit_info);
263 		if (status == QDF_STATUS_E_FAILURE) {
264 			target_if_err(
265 				"psoc:(%pK) num_mem_chunk exceeds supp number",
266 									psoc);
267 			return QDF_STATUS_E_FAILURE;
268 		} else if (status == QDF_STATUS_E_NOMEM) {
269 			target_if_err("soc:(%pK) mem alloc failure", psoc);
270 			return QDF_STATUS_E_NOMEM;
271 		}
272 	}
273 
274 	return QDF_STATUS_SUCCESS;
275 }
276 
277 QDF_STATUS init_deinit_free_num_units(struct wlan_objmgr_psoc *psoc,
278 			struct target_psoc_info *tgt_hdl)
279 {
280 	struct tgt_info *info;
281 	qdf_device_t qdf_dev;
282 	uint32_t idx;
283 	QDF_STATUS status;
284 
285 	if (!tgt_hdl) {
286 		target_if_err("target_psoc_info is null");
287 		return QDF_STATUS_E_INVAL;
288 	}
289 
290 	if ((tgt_hdl->tif_ops) &&
291 	    (tgt_hdl->tif_ops->mem_mgr_free_chunks)) {
292 		status = tgt_hdl->tif_ops->mem_mgr_free_chunks(psoc, tgt_hdl);
293 	} else {
294 		qdf_dev = wlan_psoc_get_qdf_dev(psoc);
295 		if (!qdf_dev) {
296 			target_if_err("qdf_dev is null");
297 			QDF_BUG(0);
298 			return QDF_STATUS_E_INVAL;
299 		}
300 		info = (&tgt_hdl->info);
301 		for (idx = 0; idx < info->num_mem_chunks; idx++) {
302 			qdf_mem_free_consistent(
303 				qdf_dev, qdf_dev->dev,
304 				info->mem_chunks[idx].len,
305 				info->mem_chunks[idx].vaddr,
306 				info->mem_chunks[idx].paddr,
307 				qdf_get_dma_mem_context(
308 					(&(info->mem_chunks[idx])), memctx));
309 
310 			info->mem_chunks[idx].vaddr = NULL;
311 			info->mem_chunks[idx].paddr = 0;
312 			info->mem_chunks[idx].len = 0;
313 		}
314 		info->num_mem_chunks = 0;
315 		status = QDF_STATUS_SUCCESS;
316 	}
317 
318 	return status;
319 }
320 
321 QDF_STATUS init_deinit_handle_host_mem_req(
322 		 struct wlan_objmgr_psoc *psoc,
323 		 struct target_psoc_info *tgt_hdl, uint8_t *event)
324 {
325 	uint8_t num_mem_reqs;
326 	host_mem_req *mem_reqs;
327 	uint32_t i;
328 	uint32_t idx;
329 	QDF_STATUS status = QDF_STATUS_SUCCESS;
330 	struct wmi_unified *wmi_handle;
331 	struct tgt_info *info;
332 
333 	if (!tgt_hdl) {
334 		target_if_err("target_psoc_info is null");
335 		return QDF_STATUS_E_INVAL;
336 	}
337 
338 	wmi_handle = target_psoc_get_wmi_hdl(tgt_hdl);
339 	info = (&tgt_hdl->info);
340 
341 	mem_reqs = wmi_extract_host_mem_req_from_service_ready(
342 					wmi_handle, event, &num_mem_reqs);
343 	if (!num_mem_reqs)
344 		return QDF_STATUS_SUCCESS;
345 
346 	if (num_mem_reqs > MAX_MEM_CHUNKS) {
347 		target_if_err_rl("num_mem_reqs:%u is out of bounds",
348 				 num_mem_reqs);
349 		return QDF_STATUS_E_FAILURE;
350 	}
351 
352 	for (i = 0; i < FW_PRIORITY_MAX; i++) {
353 		for (idx = 0; idx < num_mem_reqs; idx++) {
354 			status = init_deinit_alloc_num_units(psoc, tgt_hdl,
355 				mem_reqs, i, idx);
356 			if (status != QDF_STATUS_SUCCESS)
357 				return status;
358 		}
359 	}
360 
361 	return status;
362 }
363 
364 void init_deinit_derive_band_to_mac_param(
365 		struct wlan_objmgr_psoc *psoc,
366 		struct target_psoc_info *tgt_hdl,
367 		struct wmi_host_pdev_band_to_mac *band_to_mac)
368 {
369 	uint8_t i;
370 	struct wlan_psoc_host_mac_phy_caps *mac_phy_cap;
371 	struct wlan_psoc_host_hal_reg_capabilities_ext *reg_cap;
372 	struct tgt_info *info;
373 
374 	if (!tgt_hdl) {
375 		target_if_err("target_psoc_info is null ");
376 		return;
377 	}
378 
379 	info = (&tgt_hdl->info);
380 
381 	reg_cap = ucfg_reg_get_hal_reg_cap(psoc);
382 	if (!reg_cap) {
383 		target_if_err("reg cap is NULL");
384 		return;
385 	}
386 
387 	mac_phy_cap = target_psoc_get_mac_phy_cap(tgt_hdl);
388 	if (!mac_phy_cap) {
389 		target_if_err("mac_phy_cap is NULL");
390 		return;
391 	}
392 	for (i = 0; i < target_psoc_get_num_radios(tgt_hdl); i++) {
393 		if (mac_phy_cap->supported_bands ==
394 			(WMI_HOST_WLAN_5G_CAPABILITY |
395 					WMI_HOST_WLAN_2G_CAPABILITY)) {
396 			/*Supports both 5G and 2G. Use freq from both radios*/
397 			target_if_debug("Supports both 2G and 5G");
398 			band_to_mac[i].pdev_id = mac_phy_cap->pdev_id;
399 			band_to_mac[i].start_freq =
400 					reg_cap[i].low_2ghz_chan;
401 			band_to_mac[i].end_freq =
402 					reg_cap[i].high_5ghz_chan;
403 
404 		} else if (mac_phy_cap->supported_bands ==
405 				WMI_HOST_WLAN_2G_CAPABILITY) {
406 			band_to_mac[i].pdev_id = mac_phy_cap->pdev_id;
407 			band_to_mac[i].start_freq =
408 					reg_cap[i].low_2ghz_chan;
409 			band_to_mac[i].end_freq =
410 					reg_cap[i].high_2ghz_chan;
411 
412 			reg_cap[mac_phy_cap->phy_id].low_5ghz_chan = 0;
413 			reg_cap[mac_phy_cap->phy_id].high_5ghz_chan = 0;
414 
415 			target_if_debug("2G radio - pdev_id = %d start_freq = %d end_freq= %d",
416 				       band_to_mac[i].pdev_id,
417 				       band_to_mac[i].start_freq,
418 				       band_to_mac[i].end_freq);
419 
420 		} else if (mac_phy_cap->supported_bands ==
421 					WMI_HOST_WLAN_5G_CAPABILITY) {
422 			band_to_mac[i].pdev_id = mac_phy_cap->pdev_id;
423 			band_to_mac[i].start_freq =
424 						reg_cap[i].low_5ghz_chan;
425 			band_to_mac[i].end_freq =
426 						reg_cap[i].high_5ghz_chan;
427 
428 			reg_cap[mac_phy_cap->phy_id].low_2ghz_chan = 0;
429 			reg_cap[mac_phy_cap->phy_id].high_2ghz_chan = 0;
430 
431 			target_if_debug("5G radio -pdev_id = %d start_freq = %d end_freq =%d\n",
432 				       band_to_mac[i].pdev_id,
433 				       band_to_mac[i].start_freq,
434 				       band_to_mac[i].end_freq);
435 		}
436 		mac_phy_cap++;
437 	}
438 }
439 
440 void init_deinit_prepare_send_init_cmd(
441 		 struct wlan_objmgr_psoc *psoc,
442 		 struct target_psoc_info *tgt_hdl)
443 {
444 	struct wmi_init_cmd_param init_param = {0};
445 	struct tgt_info *info;
446 	struct wmi_unified *wmi_handle;
447 	QDF_STATUS ret_val;
448 
449 	if (!tgt_hdl) {
450 		target_if_err("target_psoc_info is null");
451 		return;
452 	}
453 
454 	wmi_handle = target_psoc_get_wmi_hdl(tgt_hdl);
455 	info = (&tgt_hdl->info);
456 
457 	init_param.res_cfg = &info->wlan_res_cfg;
458 	init_param.num_mem_chunks = info->num_mem_chunks;
459 	init_param.mem_chunks = info->mem_chunks;
460 
461 	if (init_deinit_is_service_ext_msg(psoc, tgt_hdl) ==
462 			QDF_STATUS_SUCCESS) {
463 		init_param.hw_mode_id = info->preferred_hw_mode;
464 		/* Temp change, until FW submits support for handling this TLV
465 		 * For single mode, skip sending hw_mode
466 		 */
467 		if (info->preferred_hw_mode == WMI_HOST_HW_MODE_SINGLE)
468 			init_param.hw_mode_id = WMI_HOST_HW_MODE_MAX;
469 
470 		init_param.num_band_to_mac = target_psoc_get_num_radios(
471 								tgt_hdl);
472 
473 		init_deinit_derive_band_to_mac_param(psoc, tgt_hdl,
474 						     init_param.band_to_mac);
475 	} else {
476 		ret_val = tgt_if_regulatory_modify_freq_range(psoc);
477 		if (QDF_IS_STATUS_ERROR(ret_val)) {
478 			target_if_err("Modify freq range is failed");
479 			return;
480 		}
481 	}
482 
483 	ret_val = target_if_alloc_pdevs(psoc, tgt_hdl);
484 	if (ret_val != QDF_STATUS_SUCCESS)
485 		return;
486 
487 	ret_val = target_if_update_pdev_tgt_info(psoc, tgt_hdl);
488 	if (ret_val != QDF_STATUS_SUCCESS)
489 		return;
490 
491 	target_if_debug("FW version 0x%x ", info->target_caps.fw_version);
492 	if (init_deinit_is_service_ext_msg(psoc, tgt_hdl) == QDF_STATUS_SUCCESS)
493 		target_if_debug("0x%x\n",
494 				info->service_ext_param.fw_build_vers_ext);
495 	else
496 		target_if_debug("0x%x\n", info->target_caps.fw_version_1);
497 
498 	wmi_unified_init_cmd_send(wmi_handle, &init_param);
499 
500 	/* Set Max scans allowed */
501 	target_if_scan_set_max_active_scans(psoc,
502 					    WLAN_MAX_ACTIVE_SCANS_ALLOWED);
503 
504 	if (wmi_service_enabled(wmi_handle, wmi_service_hw_db2dbm_support))
505 		wlan_psoc_nif_fw_ext_cap_set(psoc, WLAN_SOC_CEXT_HW_DB2DBM);
506 }
507