xref: /wlan-dirver/qca-wifi-host-cmn/target_if/init_deinit/src/init_cmd_api.c (revision a175314c51a4ce5cec2835cc8a8c7dc0c1810915)
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_info(
107 		"req_id %d idx %d num_units %d unit_len %d",
108 		req_id, idx, num_units, unit_len);
109 
110 	return num_units;
111 }
112 
113 /* Host mem size units, it is used for round-off */
114 #define HOST_MEM_SIZE_UNIT 4
115 
116 /**
117  *  init_deinit_alloc_host_mem() - allocates amount of memory requested by FW.
118  *  @psoc: PSOC object
119  *  @tgt_hdl: Target PSOC info
120  *  @req_id: request id
121  *  @num_units: Number of units
122  *  @unit_len: Unit length
123  *  @num_unit_info: Num unit info
124  *
125  *  API to allocate host memory requested by FW
126  *
127  *  Return: QDF_STATUS_SUCCESS on successful allocation
128  *          QDF_STATUS_E_FAILURE on failure
129  */
130 static QDF_STATUS init_deinit_alloc_host_mem(struct wlan_objmgr_psoc *psoc,
131 		struct target_psoc_info *tgt_hdl, u_int32_t req_id,
132 		u_int32_t num_units, u_int32_t unit_len,
133 		u_int32_t num_unit_info)
134 {
135 	struct tgt_info *info;
136 	uint32_t remaining_units;
137 	uint32_t allocated_units = 0;
138 	uint32_t idx;
139 
140 	info = (&tgt_hdl->info);
141 	/* adjust the length to nearest multiple of unit size */
142 	unit_len = (unit_len + (HOST_MEM_SIZE_UNIT - 1)) &
143 				(~(HOST_MEM_SIZE_UNIT - 1));
144 	idx = info->num_mem_chunks;
145 	remaining_units = num_units;
146 
147 	while (remaining_units) {
148 		if (idx == MAX_MEM_CHUNKS) {
149 			target_if_err(
150 				"REACHED MAX CHUNK LIMIT for mem units %d",
151 					num_units);
152 			target_if_err(
153 			"unit len %d requested by FW, only allocated %d",
154 				unit_len, (num_units - remaining_units));
155 			info->num_mem_chunks = idx;
156 			return QDF_STATUS_E_FAILURE;
157 		}
158 
159 		if ((tgt_hdl->tif_ops) &&
160 		    (tgt_hdl->tif_ops->mem_mgr_alloc_chunk))
161 			allocated_units = tgt_hdl->tif_ops->mem_mgr_alloc_chunk(
162 						psoc, tgt_hdl, req_id, idx,
163 						remaining_units,
164 						unit_len, num_unit_info);
165 		else
166 			allocated_units = init_deinit_alloc_host_mem_chunk(
167 						psoc, tgt_hdl, req_id, idx,
168 						remaining_units,
169 						unit_len, num_unit_info);
170 		if (allocated_units == 0) {
171 			target_if_err("FAILED TO ALLOC mem unit len %d",
172 				      unit_len);
173 			target_if_err("units requested %d units allocated %d",
174 				      num_units, (num_units - remaining_units));
175 			info->num_mem_chunks = idx;
176 			return QDF_STATUS_E_NOMEM;
177 		}
178 		remaining_units -= allocated_units;
179 		++idx;
180 	}
181 	info->num_mem_chunks = idx;
182 
183 	return QDF_STATUS_SUCCESS;
184 }
185 
186 /**
187  *  init_deinit_alloc_num_units() - allocates num units requested by FW.
188  *  @psoc: PSOC object
189  *  @tgt_hdl: Target PSOC info
190  *  @mem_reqs: pointer to mem req
191  *  @num_units: Number
192  *  @i: FW priority
193  *  @idx: Index
194  *
195  *  API to allocate num units of host memory requested by FW
196  *
197  *  Return: QDF_STATUS_SUCCESS on successful allocation
198  *          QDF_STATUS_E_FAILURE on failure
199  */
200 static QDF_STATUS init_deinit_alloc_num_units(struct wlan_objmgr_psoc *psoc,
201 			struct target_psoc_info *tgt_hdl,
202 			host_mem_req *mem_reqs, uint16_t fw_prio,
203 			uint16_t idx)
204 {
205 	struct tgt_info *info;
206 	uint32_t num_units;
207 	QDF_STATUS status;
208 
209 	if (!tgt_hdl) {
210 		target_if_err("target_psoc_info is null");
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_info("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 common_wmi_handle *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 	for (i = 0; i < FW_PRIORITY_MAX; i++) {
347 		for (idx = 0; idx < num_mem_reqs; idx++) {
348 			status = init_deinit_alloc_num_units(psoc, tgt_hdl,
349 				mem_reqs, i, idx);
350 			if (status != QDF_STATUS_SUCCESS)
351 				return status;
352 		}
353 	}
354 
355 	return status;
356 }
357 
358 void init_deinit_derive_band_to_mac_param(
359 		struct wlan_objmgr_psoc *psoc,
360 		struct target_psoc_info *tgt_hdl,
361 		struct wmi_host_pdev_band_to_mac *band_to_mac)
362 {
363 	uint8_t i;
364 	struct wlan_psoc_host_mac_phy_caps *mac_phy_cap;
365 	struct wlan_psoc_host_hal_reg_capabilities_ext *reg_cap;
366 	struct tgt_info *info;
367 
368 	if (!tgt_hdl) {
369 		target_if_err("target_psoc_info is null ");
370 		return;
371 	}
372 
373 	info = (&tgt_hdl->info);
374 
375 	reg_cap = ucfg_reg_get_hal_reg_cap(psoc);
376 	if (!reg_cap) {
377 		target_if_err("reg cap is NULL");
378 		return;
379 	}
380 
381 	for (i = 0; i < target_psoc_get_num_radios(tgt_hdl); i++) {
382 		mac_phy_cap = &info->mac_phy_cap[i];
383 		if (mac_phy_cap->supported_bands ==
384 			(WMI_HOST_WLAN_5G_CAPABILITY |
385 					WMI_HOST_WLAN_2G_CAPABILITY)) {
386 			/*Supports both 5G and 2G. Use freq from both radios*/
387 			target_if_info("Supports both 2G and 5G");
388 			band_to_mac[i].pdev_id = mac_phy_cap->pdev_id;
389 			band_to_mac[i].start_freq =
390 					reg_cap[i].low_2ghz_chan;
391 			band_to_mac[i].end_freq =
392 					reg_cap[i].high_5ghz_chan;
393 
394 		} else if (mac_phy_cap->supported_bands ==
395 				WMI_HOST_WLAN_2G_CAPABILITY) {
396 			band_to_mac[i].pdev_id = mac_phy_cap->pdev_id;
397 			band_to_mac[i].start_freq =
398 					reg_cap[i].low_2ghz_chan;
399 			band_to_mac[i].end_freq =
400 					reg_cap[i].high_2ghz_chan;
401 
402 			reg_cap[mac_phy_cap->phy_id].low_5ghz_chan = 0;
403 			reg_cap[mac_phy_cap->phy_id].high_5ghz_chan = 0;
404 
405 			target_if_info(
406 			"2G radio - pdev_id = %d start_freq = %d end_freq= %d",
407 				band_to_mac[i].pdev_id,
408 				band_to_mac[i].start_freq,
409 				band_to_mac[i].end_freq);
410 
411 		} else if (mac_phy_cap->supported_bands ==
412 					WMI_HOST_WLAN_5G_CAPABILITY) {
413 			band_to_mac[i].pdev_id = mac_phy_cap->pdev_id;
414 			band_to_mac[i].start_freq =
415 						reg_cap[i].low_5ghz_chan;
416 			band_to_mac[i].end_freq =
417 						reg_cap[i].high_5ghz_chan;
418 
419 			reg_cap[mac_phy_cap->phy_id].low_2ghz_chan = 0;
420 			reg_cap[mac_phy_cap->phy_id].high_2ghz_chan = 0;
421 
422 			target_if_info(
423 			"5G radio -pdev_id = %d start_freq = %d end_freq =%d\n",
424 				band_to_mac[i].pdev_id,
425 				band_to_mac[i].start_freq,
426 				band_to_mac[i].end_freq);
427 		}
428 	}
429 }
430 
431 void init_deinit_prepare_send_init_cmd(
432 		 struct wlan_objmgr_psoc *psoc,
433 		 struct target_psoc_info *tgt_hdl)
434 {
435 	struct wmi_init_cmd_param init_param = {0};
436 	struct tgt_info *info;
437 	struct common_wmi_handle *wmi_handle;
438 	QDF_STATUS ret_val;
439 
440 	if (!tgt_hdl) {
441 		target_if_err("target_psoc_info is null");
442 		return;
443 	}
444 
445 	wmi_handle = target_psoc_get_wmi_hdl(tgt_hdl);
446 	info = (&tgt_hdl->info);
447 
448 	init_param.res_cfg = &info->wlan_res_cfg;
449 	init_param.num_mem_chunks = info->num_mem_chunks;
450 	init_param.mem_chunks = info->mem_chunks;
451 
452 	if (init_deinit_is_service_ext_msg(psoc, tgt_hdl) ==
453 			QDF_STATUS_SUCCESS) {
454 		init_param.hw_mode_id = info->preferred_hw_mode;
455 		/* Temp change, until FW submits support for handling this TLV
456 		 * For single mode, skip sending hw_mode
457 		 */
458 		if (info->preferred_hw_mode == WMI_HOST_HW_MODE_SINGLE)
459 			init_param.hw_mode_id = WMI_HOST_HW_MODE_MAX;
460 
461 		init_param.num_band_to_mac = target_psoc_get_num_radios(
462 								tgt_hdl);
463 
464 		init_deinit_derive_band_to_mac_param(psoc, tgt_hdl,
465 						     init_param.band_to_mac);
466 	} else {
467 		ret_val = tgt_if_regulatory_modify_freq_range(psoc);
468 		if (QDF_IS_STATUS_ERROR(ret_val)) {
469 			target_if_err("Modify freq range is failed");
470 			return;
471 		}
472 	}
473 
474 	ret_val = target_if_alloc_pdevs(psoc, tgt_hdl);
475 	if (ret_val != QDF_STATUS_SUCCESS)
476 		return;
477 
478 	ret_val = target_if_update_pdev_tgt_info(psoc, tgt_hdl);
479 	if (ret_val != QDF_STATUS_SUCCESS)
480 		return;
481 
482 	target_if_info("FW version 0x%x ", info->target_caps.fw_version);
483 	if (init_deinit_is_service_ext_msg(psoc, tgt_hdl) ==
484 			QDF_STATUS_SUCCESS)
485 		target_if_info("0x%x\n",
486 			       info->service_ext_param.fw_build_vers_ext);
487 	else
488 		target_if_info("0x%x\n", info->target_caps.fw_version_1);
489 
490 	wmi_unified_init_cmd_send(wmi_handle, &init_param);
491 
492 	/* Set Max scans allowed */
493 	target_if_scan_set_max_active_scans(psoc,
494 					    WLAN_MAX_ACTIVE_SCANS_ALLOWED);
495 }
496