1 /*
2  * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /**
21  * DOC: target_if_wifi_pos.c
22  * This file defines the functions pertinent to wifi positioning component's
23  * target if layer.
24  */
25 #include "wifi_pos_utils_pub.h"
26 
27 #include "wmi_unified_api.h"
28 #include "wlan_lmac_if_def.h"
29 #include "target_if_wifi_pos.h"
30 #include "../../../../umac/wifi_pos/src/wifi_pos_main_i.h"
31 #include "wifi_pos_utils_i.h"
32 #include "target_if.h"
33 #ifdef WLAN_FEATURE_CIF_CFR
34 #include "hal_api.h"
35 
36 #define RING_BASE_ALIGN 8
37 
target_if_wifi_pos_vaddr_lookup(struct wifi_pos_psoc_priv_obj * priv,void * paddr,uint8_t ring_num,uint32_t cookie)38 static void *target_if_wifi_pos_vaddr_lookup(
39 				struct wifi_pos_psoc_priv_obj *priv,
40 				void *paddr, uint8_t ring_num, uint32_t cookie)
41 {
42 	if (priv->dma_buf_pool[ring_num][cookie].paddr == paddr) {
43 		return priv->dma_buf_pool[ring_num][cookie].vaddr +
44 				priv->dma_buf_pool[ring_num][cookie].offset;
45 	} else {
46 		target_if_err("incorrect paddr found on cookie slot");
47 		return NULL;
48 	}
49 }
50 
51 QDF_STATUS
target_if_wifi_pos_replenish_ring(struct wifi_pos_psoc_priv_obj * priv,uint8_t ring_idx,void * aligned_vaddr,uint32_t cookie)52 target_if_wifi_pos_replenish_ring(struct wifi_pos_psoc_priv_obj *priv,
53 				  uint8_t ring_idx,
54 				  void *aligned_vaddr, uint32_t cookie)
55 {
56 	uint64_t *ring_entry;
57 	uint32_t dw_lo, dw_hi = 0, map_status;
58 	void *hal_soc = priv->hal_soc;
59 	void *srng = priv->dma_cfg[ring_idx].srng;
60 	void *paddr;
61 
62 	if (!aligned_vaddr) {
63 		target_if_debug("NULL aligned_vaddr provided");
64 		return QDF_STATUS_SUCCESS;
65 	}
66 
67 	map_status = qdf_mem_map_nbytes_single(NULL, aligned_vaddr,
68 			QDF_DMA_FROM_DEVICE,
69 			priv->dma_cap[ring_idx].min_buf_size,
70 			(qdf_dma_addr_t *)&paddr);
71 	if (map_status) {
72 		target_if_err("mem map failed status: %d", map_status);
73 		return QDF_STATUS_E_FAILURE;
74 	}
75 	QDF_ASSERT(!((uint64_t)paddr % priv->dma_cap[ring_idx].min_buf_align));
76 	priv->dma_buf_pool[ring_idx][cookie].paddr = paddr;
77 
78 	hal_srng_access_start(hal_soc, srng);
79 	ring_entry = hal_srng_src_get_next(hal_soc, srng);
80 	dw_lo = (uint64_t)paddr & 0xFFFFFFFF;
81 	WMI_OEM_DMA_DATA_ADDR_HI_SET(dw_hi, (uint64_t)paddr >> 32);
82 	WMI_OEM_DMA_DATA_ADDR_HI_HOST_DATA_SET(dw_hi, cookie);
83 	*ring_entry = (uint64_t)dw_hi << 32 | dw_lo;
84 	hal_srng_access_end(hal_soc, srng);
85 
86 	return QDF_STATUS_SUCCESS;
87 }
88 
target_if_wifi_pos_get_indirect_data(struct wifi_pos_psoc_priv_obj * priv_obj,struct wmi_host_oem_indirect_data * indirect,struct oem_data_rsp * rsp,uint32_t * cookie)89 QDF_STATUS target_if_wifi_pos_get_indirect_data(
90 		struct wifi_pos_psoc_priv_obj *priv_obj,
91 		struct wmi_host_oem_indirect_data *indirect,
92 		struct oem_data_rsp *rsp, uint32_t *cookie)
93 {
94 	void *paddr = NULL;
95 	uint32_t addr_hi;
96 	uint8_t ring_idx = 0, num_rings;
97 	uint32_t allocated_len;
98 
99 	if (!indirect) {
100 		target_if_debug("no indirect data. regular event received");
101 		return QDF_STATUS_SUCCESS;
102 	}
103 
104 	ring_idx = indirect->pdev_id - 1;
105 	num_rings = priv_obj->num_rings;
106 	if (ring_idx >= num_rings) {
107 		target_if_err("incorrect pdev_id: %d", indirect->pdev_id);
108 		return QDF_STATUS_E_INVAL;
109 	}
110 
111 	allocated_len = priv_obj->dma_cap[ring_idx].min_buf_size +
112 				(priv_obj->dma_cap[ring_idx].min_buf_align - 1);
113 	if (indirect->len > allocated_len ||
114 	    indirect->len > OEM_DATA_DMA_BUFF_SIZE) {
115 		target_if_err("Invalid indirect len: %d, allocated_len:%d",
116 			      indirect->len, allocated_len);
117 		return QDF_STATUS_E_INVAL;
118 	}
119 
120 	addr_hi = (uint64_t)WMI_OEM_DMA_DATA_ADDR_HI_GET(
121 						indirect->addr_hi);
122 	paddr = (void *)((uint64_t)addr_hi << 32 | indirect->addr_lo);
123 	*cookie = WMI_OEM_DMA_DATA_ADDR_HI_HOST_DATA_GET(
124 						indirect->addr_hi);
125 	rsp->vaddr = target_if_wifi_pos_vaddr_lookup(priv_obj,
126 					paddr, ring_idx, *cookie);
127 	rsp->dma_len = indirect->len;
128 	qdf_mem_unmap_nbytes_single(NULL, (qdf_dma_addr_t)paddr,
129 			QDF_DMA_FROM_DEVICE,
130 			priv_obj->dma_cap[ring_idx].min_buf_size);
131 
132 	return QDF_STATUS_SUCCESS;
133 }
134 #endif
135 
target_if_wifi_pos_get_vht_ch_width(struct wlan_objmgr_psoc * psoc,enum phy_ch_width * ch_width)136 QDF_STATUS target_if_wifi_pos_get_vht_ch_width(struct wlan_objmgr_psoc *psoc,
137 					       enum phy_ch_width *ch_width)
138 {
139 	struct target_psoc_info *tgt_hdl;
140 	int vht_cap_info;
141 
142 	*ch_width = CH_WIDTH_INVALID;
143 
144 	if (!psoc)
145 		return QDF_STATUS_E_INVAL;
146 
147 	tgt_hdl = wlan_psoc_get_tgt_if_handle(psoc);
148 	if (!tgt_hdl)
149 		return QDF_STATUS_E_INVAL;
150 
151 	*ch_width = CH_WIDTH_80MHZ;
152 
153 	vht_cap_info = target_if_get_vht_cap_info(tgt_hdl);
154 
155 	if (vht_cap_info & WLAN_VHTCAP_SUP_CHAN_WIDTH_80_160)
156 		*ch_width = CH_WIDTH_80P80MHZ;
157 	else if (vht_cap_info & WLAN_VHTCAP_SUP_CHAN_WIDTH_160)
158 		*ch_width = CH_WIDTH_160MHZ;
159 
160 	return QDF_STATUS_SUCCESS;
161 }
162 
163 #ifndef CNSS_GENL
target_if_wifi_pos_convert_pdev_id_host_to_target(struct wlan_objmgr_psoc * psoc,uint32_t host_pdev_id,uint32_t * target_pdev_id)164 QDF_STATUS target_if_wifi_pos_convert_pdev_id_host_to_target(
165 		struct wlan_objmgr_psoc *psoc, uint32_t host_pdev_id,
166 		uint32_t *target_pdev_id)
167 {
168 	wmi_unified_t wmi_hdl = GET_WMI_HDL_FROM_PSOC(psoc);
169 
170 	if (!wmi_hdl) {
171 		target_if_err("null wmi_hdl");
172 		return QDF_STATUS_E_NULL_VALUE;
173 	}
174 
175 	return wmi_convert_pdev_id_host_to_target(wmi_hdl, host_pdev_id,
176 						  target_pdev_id);
177 }
178 
target_if_wifi_pos_convert_pdev_id_target_to_host(struct wlan_objmgr_psoc * psoc,uint32_t target_pdev_id,uint32_t * host_pdev_id)179 QDF_STATUS target_if_wifi_pos_convert_pdev_id_target_to_host(
180 		struct wlan_objmgr_psoc *psoc, uint32_t target_pdev_id,
181 		uint32_t *host_pdev_id)
182 {
183 	wmi_unified_t wmi_hdl = GET_WMI_HDL_FROM_PSOC(psoc);
184 
185 	if (!wmi_hdl) {
186 		target_if_err("null wmi_hdl");
187 		return QDF_STATUS_E_NULL_VALUE;
188 	}
189 
190 	return wmi_convert_pdev_id_target_to_host(wmi_hdl, target_pdev_id,
191 						  host_pdev_id);
192 }
193 #endif /* CNSS_GENL */
194 
195 #ifdef WLAN_FEATURE_CIF_CFR
target_if_wifi_pos_fill_ring(uint8_t ring_idx,struct hal_srng * srng,struct wifi_pos_psoc_priv_obj * priv)196 static QDF_STATUS target_if_wifi_pos_fill_ring(uint8_t ring_idx,
197 					struct hal_srng *srng,
198 					struct wifi_pos_psoc_priv_obj *priv)
199 {
200 	uint32_t i;
201 	void *buf, *buf_aligned;
202 
203 	for (i = 0; i < priv->dma_cfg[ring_idx].num_ptr; i++) {
204 		buf = qdf_mem_malloc(priv->dma_cap[ring_idx].min_buf_size +
205 				priv->dma_cap[ring_idx].min_buf_align - 1);
206 		if (!buf)
207 			return QDF_STATUS_E_NOMEM;
208 
209 		priv->dma_buf_pool[ring_idx][i].vaddr = buf;
210 		buf_aligned = (void *)qdf_roundup((uint64_t)buf,
211 				priv->dma_cap[ring_idx].min_buf_align);
212 		priv->dma_buf_pool[ring_idx][i].offset = buf_aligned - buf;
213 		priv->dma_buf_pool[ring_idx][i].cookie = i;
214 		target_if_wifi_pos_replenish_ring(priv, ring_idx,
215 						  buf_aligned, i);
216 	}
217 
218 	return QDF_STATUS_SUCCESS;
219 }
220 
target_if_wifi_pos_empty_ring(uint8_t ring_idx,struct wifi_pos_psoc_priv_obj * priv)221 static QDF_STATUS target_if_wifi_pos_empty_ring(uint8_t ring_idx,
222 					struct wifi_pos_psoc_priv_obj *priv)
223 {
224 	uint32_t i;
225 
226 	for (i = 0; i < priv->dma_cfg[ring_idx].num_ptr; i++) {
227 		qdf_mem_unmap_nbytes_single(NULL,
228 			(qdf_dma_addr_t)priv->dma_buf_pool[ring_idx][i].vaddr,
229 			QDF_DMA_FROM_DEVICE,
230 			priv->dma_cap[ring_idx].min_buf_size);
231 		qdf_mem_free(priv->dma_buf_pool[ring_idx][i].vaddr);
232 	}
233 
234 	return QDF_STATUS_SUCCESS;
235 }
236 
target_if_wifi_pos_init_ring(uint8_t ring_idx,struct wifi_pos_psoc_priv_obj * priv)237 static QDF_STATUS target_if_wifi_pos_init_ring(uint8_t ring_idx,
238 					struct wifi_pos_psoc_priv_obj *priv)
239 {
240 	void *srng;
241 	uint32_t num_entries;
242 	qdf_dma_addr_t paddr;
243 	uint32_t ring_alloc_size;
244 	void *hal_soc = priv->hal_soc;
245 	struct hal_srng_params ring_params = {0};
246 	uint32_t max_entries = hal_srng_max_entries(hal_soc, WIFI_POS_SRC);
247 	uint32_t entry_size = hal_srng_get_entrysize(hal_soc, WIFI_POS_SRC);
248 
249 	num_entries = priv->dma_cap[ring_idx].min_num_ptr > max_entries ?
250 			max_entries : priv->dma_cap[ring_idx].min_num_ptr;
251 	priv->dma_cfg[ring_idx].num_ptr = num_entries;
252 	priv->dma_buf_pool[ring_idx] = qdf_mem_malloc(num_entries *
253 					sizeof(struct wifi_pos_dma_buf_info));
254 	if (!priv->dma_buf_pool[ring_idx])
255 		return QDF_STATUS_E_NOMEM;
256 
257 	ring_alloc_size = (num_entries * entry_size) + RING_BASE_ALIGN - 1;
258 	priv->dma_cfg[ring_idx].ring_alloc_size = ring_alloc_size;
259 	priv->dma_cfg[ring_idx].base_vaddr_unaligned =
260 		qdf_mem_alloc_consistent(NULL, NULL, ring_alloc_size, &paddr);
261 	priv->dma_cfg[ring_idx].base_paddr_unaligned = (void *)paddr;
262 	if (!priv->dma_cfg[ring_idx].base_vaddr_unaligned) {
263 		target_if_err("malloc failed");
264 		return QDF_STATUS_E_NOMEM;
265 	}
266 
267 	priv->dma_cfg[ring_idx].base_vaddr_aligned = (void *)qdf_roundup(
268 		(uint64_t)priv->dma_cfg[ring_idx].base_vaddr_unaligned,
269 		RING_BASE_ALIGN);
270 	ring_params.ring_base_vaddr =
271 		priv->dma_cfg[ring_idx].base_vaddr_aligned;
272 	priv->dma_cfg[ring_idx].base_paddr_aligned = (void *)qdf_roundup(
273 		(uint64_t)priv->dma_cfg[ring_idx].base_paddr_unaligned,
274 		RING_BASE_ALIGN);
275 	ring_params.ring_base_paddr =
276 		(qdf_dma_addr_t)priv->dma_cfg[ring_idx].base_paddr_aligned;
277 	ring_params.num_entries = num_entries;
278 	srng = hal_srng_setup(hal_soc, WIFI_POS_SRC, 0,
279 			      priv->dma_cap[ring_idx].pdev_id, &ring_params, 0);
280 	if (!srng) {
281 		target_if_err("srng setup failed");
282 		return QDF_STATUS_E_FAILURE;
283 	}
284 	priv->dma_cfg[ring_idx].srng = srng;
285 	priv->dma_cfg[ring_idx].tail_idx_addr =
286 			(void *)hal_srng_get_tp_addr(hal_soc, srng);
287 	priv->dma_cfg[ring_idx].head_idx_addr =
288 			(void *)hal_srng_get_tp_addr(hal_soc, srng);
289 
290 	return target_if_wifi_pos_fill_ring(ring_idx, srng, priv);
291 }
292 
target_if_wifi_pos_deinit_ring(uint8_t ring_idx,struct wifi_pos_psoc_priv_obj * priv)293 static QDF_STATUS target_if_wifi_pos_deinit_ring(uint8_t ring_idx,
294 					struct wifi_pos_psoc_priv_obj *priv)
295 {
296 	target_if_wifi_pos_empty_ring(ring_idx, priv);
297 	priv->dma_buf_pool[ring_idx] = NULL;
298 	hal_srng_cleanup(priv->hal_soc, priv->dma_cfg[ring_idx].srng, 0);
299 	qdf_mem_free_consistent(NULL, NULL,
300 		priv->dma_cfg[ring_idx].ring_alloc_size,
301 		priv->dma_cfg[ring_idx].base_vaddr_unaligned,
302 		(qdf_dma_addr_t)priv->dma_cfg[ring_idx].base_paddr_unaligned,
303 		0);
304 	qdf_mem_free(priv->dma_buf_pool[ring_idx]);
305 
306 	return QDF_STATUS_SUCCESS;
307 }
308 
target_if_wifi_pos_init_srngs(struct wifi_pos_psoc_priv_obj * priv)309 static QDF_STATUS target_if_wifi_pos_init_srngs(
310 					struct wifi_pos_psoc_priv_obj *priv)
311 {
312 	uint8_t i;
313 	QDF_STATUS status;
314 
315 	/* allocate memory for num_rings pointers */
316 	priv->dma_cfg = qdf_mem_malloc(priv->num_rings *
317 				sizeof(struct wifi_pos_dma_rings_cap));
318 	if (!priv->dma_cfg)
319 		return QDF_STATUS_E_NOMEM;
320 
321 	priv->dma_buf_pool = qdf_mem_malloc(priv->num_rings *
322 				sizeof(struct wifi_pos_dma_buf_info *));
323 	if (!priv->dma_buf_pool)
324 		return QDF_STATUS_E_NOMEM;
325 
326 	for (i = 0; i < priv->num_rings; i++) {
327 		status = target_if_wifi_pos_init_ring(i, priv);
328 		if (QDF_IS_STATUS_ERROR(status)) {
329 			target_if_err("init for ring[%d] failed", i);
330 			return status;
331 		}
332 	}
333 
334 	return QDF_STATUS_SUCCESS;
335 }
336 
target_if_wifi_pos_deinit_srngs(struct wifi_pos_psoc_priv_obj * priv)337 static QDF_STATUS target_if_wifi_pos_deinit_srngs(
338 					struct wifi_pos_psoc_priv_obj *priv)
339 {
340 	uint8_t i;
341 
342 	for (i = 0; i < priv->num_rings; i++)
343 		target_if_wifi_pos_deinit_ring(i, priv);
344 
345 	qdf_mem_free(priv->dma_buf_pool);
346 	priv->dma_buf_pool = NULL;
347 
348 	return QDF_STATUS_SUCCESS;
349 }
350 
target_if_wifi_pos_cfg_fw(struct wlan_objmgr_psoc * psoc,struct wifi_pos_psoc_priv_obj * priv)351 static QDF_STATUS target_if_wifi_pos_cfg_fw(struct wlan_objmgr_psoc *psoc,
352 					struct wifi_pos_psoc_priv_obj *priv)
353 {
354 	uint8_t i;
355 	QDF_STATUS status;
356 	wmi_unified_t wmi_hdl = GET_WMI_HDL_FROM_PSOC(psoc);
357 	wmi_oem_dma_ring_cfg_req_fixed_param cfg = {0};
358 
359 	if (!wmi_hdl) {
360 		target_if_err("WMA closed, can't send oem data req cmd");
361 		return QDF_STATUS_E_INVAL;
362 	}
363 
364 	target_if_debug("Sending oem dma ring cfg to target");
365 
366 	for (i = 0; i < priv->num_rings; i++) {
367 		cfg.pdev_id = priv->dma_cfg[i].pdev_id;
368 		cfg.base_addr_lo = (uint64_t)priv->dma_cfg[i].base_paddr_aligned
369 						& 0xFFFFFFFF;
370 		cfg.base_addr_hi = (uint64_t)priv->dma_cfg[i].base_paddr_aligned
371 						& 0xFFFFFFFF00000000;
372 		cfg.head_idx_addr_lo = (uint64_t)priv->dma_cfg[i].head_idx_addr
373 						& 0xFFFFFFFF;
374 		cfg.head_idx_addr_hi = (uint64_t)priv->dma_cfg[i].head_idx_addr
375 						& 0xFFFFFFFF00000000;
376 		cfg.tail_idx_addr_lo = (uint64_t)priv->dma_cfg[i].tail_idx_addr
377 						& 0xFFFFFFFF;
378 		cfg.tail_idx_addr_hi = (uint64_t)priv->dma_cfg[i].tail_idx_addr
379 						& 0xFFFFFFFF00000000;
380 		cfg.num_ptr = priv->dma_cfg[i].num_ptr;
381 		status = wmi_unified_oem_dma_ring_cfg(wmi_hdl, &cfg);
382 		if (!QDF_IS_STATUS_SUCCESS(status)) {
383 			target_if_err("wmi cmd send failed");
384 			return status;
385 		}
386 	}
387 
388 	return status;
389 }
390 
target_if_wifi_pos_deinit_dma_rings(struct wlan_objmgr_psoc * psoc)391 QDF_STATUS target_if_wifi_pos_deinit_dma_rings(struct wlan_objmgr_psoc *psoc)
392 {
393 	struct wifi_pos_psoc_priv_obj *priv = wifi_pos_get_psoc_priv_obj(psoc);
394 
395 	target_if_wifi_pos_deinit_srngs(priv);
396 	qdf_mem_free(priv->dma_cap);
397 	priv->dma_cap = NULL;
398 
399 	return QDF_STATUS_SUCCESS;
400 }
401 
target_if_wifi_pos_init_cir_cfr_rings(struct wlan_objmgr_psoc * psoc,void * hal_soc,uint8_t num_mac,void * buf)402 QDF_STATUS target_if_wifi_pos_init_cir_cfr_rings(struct wlan_objmgr_psoc *psoc,
403 					     void *hal_soc, uint8_t num_mac,
404 					     void *buf)
405 {
406 	uint8_t i;
407 	QDF_STATUS status = QDF_STATUS_SUCCESS;
408 	WMI_OEM_DMA_RING_CAPABILITIES *dma_cap = buf;
409 	struct wifi_pos_psoc_priv_obj *priv = wifi_pos_get_psoc_priv_obj(psoc);
410 
411 	if (!priv) {
412 		target_if_err("unable to get wifi_pos psoc obj");
413 		return QDF_STATUS_E_NULL_VALUE;
414 	}
415 
416 	priv->hal_soc = hal_soc;
417 	priv->num_rings = num_mac;
418 	priv->dma_cap = qdf_mem_malloc(priv->num_rings *
419 					sizeof(struct wifi_pos_dma_rings_cap));
420 	if (!priv->dma_cap)
421 		return QDF_STATUS_E_NOMEM;
422 
423 	for (i = 0; i < num_mac; i++) {
424 		priv->dma_cap[i].pdev_id = dma_cap[i].pdev_id;
425 		priv->dma_cap[i].min_num_ptr = dma_cap[i].min_num_ptr;
426 		priv->dma_cap[i].min_buf_size = dma_cap[i].min_buf_size;
427 		priv->dma_cap[i].min_buf_align = dma_cap[i].min_buf_align;
428 	}
429 
430 	/* initialize DMA rings now */
431 	status = target_if_wifi_pos_init_srngs(priv);
432 	if (QDF_IS_STATUS_ERROR(status)) {
433 		target_if_err("dma init failed: %d", status);
434 		goto dma_init_failed;
435 	}
436 
437 	/* send cfg req cmd to firmware */
438 	status = target_if_wifi_pos_cfg_fw(psoc, priv);
439 	if (QDF_IS_STATUS_ERROR(status)) {
440 		target_if_err("configure to FW failed: %d", status);
441 		goto dma_init_failed;
442 	}
443 
444 	return QDF_STATUS_SUCCESS;
445 
446 dma_init_failed:
447 	target_if_wifi_pos_deinit_dma_rings(psoc);
448 	return status;
449 }
450 
451 #endif
452