xref: /wlan-dirver/qca-wifi-host-cmn/target_if/init_deinit/src/init_cmd_api.c (revision 45a38684b07295822dc8eba39e293408f203eec8)
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 and
73 	 * CFR_CAPTURE buffer 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 	      req_id == CFR_CAPTURE_HOST_MEM_REQ_ID))) {
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 QDF_STATUS init_deinit_free_num_units(struct wlan_objmgr_psoc *psoc,
186 			struct target_psoc_info *tgt_hdl)
187 {
188 	struct tgt_info *info;
189 	qdf_device_t qdf_dev;
190 	uint32_t idx;
191 	QDF_STATUS status;
192 
193 	if (!tgt_hdl) {
194 		target_if_err("target_psoc_info is null");
195 		return QDF_STATUS_E_INVAL;
196 	}
197 
198 	if ((tgt_hdl->tif_ops) &&
199 	    (tgt_hdl->tif_ops->mem_mgr_free_chunks)) {
200 		status = tgt_hdl->tif_ops->mem_mgr_free_chunks(psoc, tgt_hdl);
201 	} else {
202 		qdf_dev = wlan_psoc_get_qdf_dev(psoc);
203 		if (!qdf_dev) {
204 			target_if_err("qdf_dev is null");
205 			QDF_BUG(0);
206 			return QDF_STATUS_E_INVAL;
207 		}
208 		info = (&tgt_hdl->info);
209 		for (idx = 0; idx < info->num_mem_chunks; idx++) {
210 			qdf_mem_free_consistent(
211 					qdf_dev, qdf_dev->dev,
212 					info->mem_chunks[idx].len,
213 					info->mem_chunks[idx].vaddr,
214 					info->mem_chunks[idx].paddr,
215 					qdf_get_dma_mem_context(
216 					(&info->mem_chunks[idx]), memctx));
217 
218 			info->mem_chunks[idx].vaddr = NULL;
219 			info->mem_chunks[idx].paddr = 0;
220 			info->mem_chunks[idx].len = 0;
221 		}
222 		info->num_mem_chunks = 0;
223 		status = QDF_STATUS_SUCCESS;
224 	}
225 
226 	return status;
227 }
228 
229 QDF_STATUS init_deinit_handle_host_mem_req(
230 		struct wlan_objmgr_psoc *psoc,
231 		struct target_psoc_info *tgt_hdl, uint8_t *event)
232 {
233 	uint32_t num_mem_reqs;
234 	host_mem_req mem_reqs;
235 	uint32_t i;
236 	uint32_t idx;
237 	QDF_STATUS status = QDF_STATUS_SUCCESS;
238 	struct wmi_unified *wmi_handle;
239 	struct tgt_info *info;
240 
241 	if (!tgt_hdl) {
242 		target_if_err("target_psoc_info is null");
243 		return QDF_STATUS_E_INVAL;
244 	}
245 
246 	wmi_handle = target_psoc_get_wmi_hdl(tgt_hdl);
247 	info = (&tgt_hdl->info);
248 
249 	num_mem_reqs = wmi_extract_num_mem_reqs_from_service_ready(
250 							wmi_handle, event);
251 	if (!num_mem_reqs)
252 		return QDF_STATUS_SUCCESS;
253 
254 	if (num_mem_reqs > MAX_MEM_CHUNKS) {
255 		target_if_err_rl("num_mem_reqs:%u is out of bounds",
256 				num_mem_reqs);
257 		return QDF_STATUS_E_FAILURE;
258 	}
259 
260 	for (i = 0; i < WMI_FW_PRIORITY_MAX; i++) {
261 		for (idx = 0; idx < num_mem_reqs; idx++) {
262 			status = wmi_extract_host_mem_req_from_service_ready(
263 					wmi_handle, event, &mem_reqs,
264 					info->wlan_res_cfg.num_active_peers,
265 					info->wlan_res_cfg.num_peers, i, idx);
266 			if (mem_reqs.tgt_num_units) {
267 				status = init_deinit_alloc_host_mem(
268 						psoc,
269 						tgt_hdl,
270 						mem_reqs.req_id,
271 						mem_reqs.tgt_num_units,
272 						mem_reqs.unit_size,
273 						mem_reqs.num_unit_info);
274 				if (status == QDF_STATUS_E_FAILURE) {
275 					target_if_err("num_mem_chunk exceeds supp number");
276 				} else if (status == QDF_STATUS_E_NOMEM) {
277 					target_if_err("mem alloc failure");
278 				}
279 			}
280 
281 			if (status != QDF_STATUS_SUCCESS)
282 				return status;
283 		}
284 	}
285 
286 	return status;
287 }
288 
289 void init_deinit_derive_band_to_mac_param(
290 		struct wlan_objmgr_psoc *psoc,
291 		struct target_psoc_info *tgt_hdl,
292 		struct wmi_host_pdev_band_to_mac *band_to_mac)
293 {
294 	uint8_t i;
295 	struct wlan_psoc_host_mac_phy_caps *mac_phy_cap;
296 	struct wlan_psoc_host_hal_reg_capabilities_ext *reg_cap;
297 	struct tgt_info *info;
298 
299 	if (!tgt_hdl) {
300 		target_if_err("target_psoc_info is null ");
301 		return;
302 	}
303 
304 	info = (&tgt_hdl->info);
305 
306 	reg_cap = ucfg_reg_get_hal_reg_cap(psoc);
307 	if (!reg_cap) {
308 		target_if_err("reg cap is NULL");
309 		return;
310 	}
311 
312 	mac_phy_cap = target_psoc_get_mac_phy_cap(tgt_hdl);
313 	if (!mac_phy_cap) {
314 		target_if_err("mac_phy_cap is NULL");
315 		return;
316 	}
317 	for (i = 0; i < target_psoc_get_num_radios(tgt_hdl); i++) {
318 		if (mac_phy_cap->supported_bands ==
319 			(WMI_HOST_WLAN_5G_CAPABILITY |
320 					WMI_HOST_WLAN_2G_CAPABILITY)) {
321 			/*Supports both 5G and 2G. Use freq from both radios*/
322 			target_if_debug("Supports both 2G and 5G");
323 			band_to_mac[i].pdev_id = mac_phy_cap->pdev_id;
324 			band_to_mac[i].start_freq =
325 					reg_cap[i].low_2ghz_chan;
326 			band_to_mac[i].end_freq =
327 					reg_cap[i].high_5ghz_chan;
328 
329 		} else if (mac_phy_cap->supported_bands ==
330 				WMI_HOST_WLAN_2G_CAPABILITY) {
331 			band_to_mac[i].pdev_id = mac_phy_cap->pdev_id;
332 			band_to_mac[i].start_freq =
333 					reg_cap[i].low_2ghz_chan;
334 			band_to_mac[i].end_freq =
335 					reg_cap[i].high_2ghz_chan;
336 
337 			reg_cap[mac_phy_cap->phy_id].low_5ghz_chan = 0;
338 			reg_cap[mac_phy_cap->phy_id].high_5ghz_chan = 0;
339 
340 			target_if_debug("2G radio - pdev_id = %d start_freq = %d end_freq= %d",
341 				       band_to_mac[i].pdev_id,
342 				       band_to_mac[i].start_freq,
343 				       band_to_mac[i].end_freq);
344 
345 		} else if (mac_phy_cap->supported_bands ==
346 					WMI_HOST_WLAN_5G_CAPABILITY) {
347 			band_to_mac[i].pdev_id = mac_phy_cap->pdev_id;
348 			band_to_mac[i].start_freq =
349 						reg_cap[i].low_5ghz_chan;
350 			band_to_mac[i].end_freq =
351 						reg_cap[i].high_5ghz_chan;
352 
353 			reg_cap[mac_phy_cap->phy_id].low_2ghz_chan = 0;
354 			reg_cap[mac_phy_cap->phy_id].high_2ghz_chan = 0;
355 
356 			target_if_debug("5G radio -pdev_id = %d start_freq = %d end_freq =%d\n",
357 				       band_to_mac[i].pdev_id,
358 				       band_to_mac[i].start_freq,
359 				       band_to_mac[i].end_freq);
360 		}
361 		mac_phy_cap++;
362 	}
363 }
364 
365 /* if num of mac per band is sent by host then FW will not initialize
366  * its data structure with its default value. Host either have to set
367  * these value as per current HW mode or else these variable should be
368  * initialized to 0.
369  * Ex - If host is sending default HW mode as DBS in INIT_CMDID
370  * then either host should fill both the MACs (mac0 and mac1) or
371  * else don't fill for even a single mac, it should be initialized to
372  * 0 which means FW will initialize its data structures based on its
373  * default value.
374  */
375 #ifdef FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT
376 static bool is_num_band_to_mac_required(struct wmi_unified *wmi_handle)
377 {
378 	bool is_required = true;
379 
380 	/* For target where interband MCC is not supported, num of
381 	 * mac should be set to default value i.e. 0
382 	 */
383 	is_required = (wmi_service_enabled(wmi_handle,
384 				wmi_service_dual_band_simultaneous_support) ||
385 		       !wmi_service_enabled(wmi_handle,
386 				wmi_service_no_interband_mcc_support));
387 	return is_required;
388 }
389 #else
390 static bool is_num_band_to_mac_required(struct wmi_unified *wmi_handle)
391 {
392 	return true;
393 }
394 #endif
395 
396 void init_deinit_prepare_send_init_cmd(
397 		 struct wlan_objmgr_psoc *psoc,
398 		 struct target_psoc_info *tgt_hdl)
399 {
400 	struct wmi_init_cmd_param init_param = {0};
401 	struct tgt_info *info;
402 	struct wmi_unified *wmi_handle;
403 	QDF_STATUS ret_val;
404 
405 	if (!tgt_hdl) {
406 		target_if_err("target_psoc_info is null");
407 		return;
408 	}
409 
410 	wmi_handle = target_psoc_get_wmi_hdl(tgt_hdl);
411 	info = (&tgt_hdl->info);
412 
413 	init_param.res_cfg = &info->wlan_res_cfg;
414 	init_param.num_mem_chunks = info->num_mem_chunks;
415 	init_param.mem_chunks = info->mem_chunks;
416 
417 	if (init_deinit_is_service_ext_msg(psoc, tgt_hdl) ==
418 			QDF_STATUS_SUCCESS) {
419 		init_param.hw_mode_id = info->preferred_hw_mode;
420 		/* Temp change, until FW submits support for handling this TLV
421 		 * For single mode, skip sending hw_mode
422 		 */
423 		if (info->preferred_hw_mode == WMI_HOST_HW_MODE_SINGLE)
424 			init_param.hw_mode_id = WMI_HOST_HW_MODE_MAX;
425 
426 		if (is_num_band_to_mac_required(wmi_handle))
427 			init_param.num_band_to_mac =
428 					 target_psoc_get_num_radios(tgt_hdl);
429 
430 		init_deinit_derive_band_to_mac_param(psoc, tgt_hdl,
431 						     init_param.band_to_mac);
432 	} else {
433 		ret_val = tgt_if_regulatory_modify_freq_range(psoc);
434 		if (QDF_IS_STATUS_ERROR(ret_val)) {
435 			target_if_err("Modify freq range is failed");
436 			return;
437 		}
438 	}
439 
440 	ret_val = target_if_alloc_pdevs(psoc, tgt_hdl);
441 	if (ret_val != QDF_STATUS_SUCCESS)
442 		return;
443 
444 	ret_val = target_if_update_pdev_tgt_info(psoc, tgt_hdl);
445 	if (ret_val != QDF_STATUS_SUCCESS)
446 		return;
447 
448 	info->wlan_res_cfg.max_ndp_sessions =
449 		QDF_MIN(info->wlan_res_cfg.max_ndp_sessions,
450 			info->service_ext2_param.max_ndp_sessions);
451 
452 	target_if_debug("FW version 0x%x ", info->target_caps.fw_version);
453 	if (init_deinit_is_service_ext_msg(psoc, tgt_hdl) == QDF_STATUS_SUCCESS)
454 		target_if_debug("0x%x\n",
455 				info->service_ext_param.fw_build_vers_ext);
456 	else
457 		target_if_debug("0x%x\n", info->target_caps.fw_version_1);
458 
459 	wmi_unified_init_cmd_send(wmi_handle, &init_param);
460 
461 	/* Set Max scans allowed */
462 	target_if_scan_set_max_active_scans(psoc,
463 					    WLAN_MAX_ACTIVE_SCANS_ALLOWED);
464 
465 	if (wmi_service_enabled(wmi_handle, wmi_service_hw_db2dbm_support))
466 		wlan_psoc_nif_fw_ext_cap_set(psoc, WLAN_SOC_CEXT_HW_DB2DBM);
467 }
468