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