xref: /wlan-dirver/qcacld-3.0/components/dp/core/src/wlan_dp_wfds.c (revision 7c5cc5e6246419000c47ce0bf8f1fb92b514edfa)
1 /*
2  * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 #include "wlan_dp_wfds.h"
17 #include "hif.h"
18 #include "hal_api.h"
19 #include "dp_types.h"
20 #include "dp_rx.h"
21 #include "pld_common.h"
22 #include "wlan_objmgr_psoc_obj.h"
23 #include <qdf_mem.h>
24 #include "wlan_dp_prealloc.h"
25 #include <htc_api.h>
26 
27 static struct dp_direct_link_wfds_context *gp_dl_wfds_ctx;
28 
29 /**
30  * dp_wfds_send_config_msg() - Send config message to WFDS QMI server
31  * @dl_wfds: Direct Link WFDS context
32  *
33  * Return: QDF status
34  */
35 static QDF_STATUS
36 dp_wfds_send_config_msg(struct dp_direct_link_wfds_context *dl_wfds)
37 {
38 	struct dp_direct_link_context *direct_link_ctx =
39 					dl_wfds->direct_link_ctx;
40 	struct wlan_qmi_wfds_config_req_msg *info;
41 	struct dp_soc *dp_soc =
42 		wlan_psoc_get_dp_handle(dl_wfds->direct_link_ctx->dp_ctx->psoc);
43 	struct hif_opaque_softc *hif_ctx;
44 	qdf_device_t qdf_dev;
45 	void *hal_soc;
46 	struct hal_mem_info mem_info = {0};
47 	struct hif_direct_link_ce_info ce_info[QMI_WFDS_CE_MAX_SRNG] = {0};
48 	QDF_STATUS status;
49 	struct hif_ce_ring_info *srng_info;
50 	struct hal_srng_params srng_params = {0};
51 	hal_ring_handle_t refill_ring;
52 	uint8_t i;
53 
54 	qdf_dev = dl_wfds->direct_link_ctx->dp_ctx->qdf_dev;
55 
56 	if (!dp_soc || !dp_soc->hif_handle || !qdf_dev)
57 		return QDF_STATUS_E_FAILURE;
58 
59 	hif_ctx = dp_soc->hif_handle;
60 
61 	hal_soc = hif_get_hal_handle(hif_ctx);
62 	if (!hal_soc)
63 		return QDF_STATUS_E_FAILURE;
64 
65 	hal_get_meminfo(hal_soc, &mem_info);
66 
67 	info = qdf_mem_malloc(sizeof(*info));
68 	if (!info)
69 		return QDF_STATUS_E_NOMEM;
70 
71 	info->shadow_rdptr_mem_paddr =
72 				(uint64_t)mem_info.shadow_rdptr_mem_paddr;
73 	info->shadow_rdptr_mem_size = sizeof(uint32_t) * HAL_SRNG_ID_MAX;
74 	info->shadow_wrptr_mem_paddr =
75 				(uint64_t)mem_info.shadow_wrptr_mem_paddr;
76 	info->shadow_wrptr_mem_size = sizeof(uint32_t) * HAL_MAX_LMAC_RINGS;
77 	info->pcie_bar_pa = (uint64_t)mem_info.dev_base_paddr;
78 
79 	dl_wfds->iommu_cfg.shadow_rdptr_paddr = info->shadow_rdptr_mem_paddr;
80 	dl_wfds->iommu_cfg.shadow_rdptr_map_size = info->shadow_rdptr_mem_size;
81 	dl_wfds->iommu_cfg.shadow_wrptr_paddr = info->shadow_wrptr_mem_paddr;
82 	dl_wfds->iommu_cfg.shadow_wrptr_map_size = info->shadow_wrptr_mem_size;
83 
84 	pld_audio_smmu_map(qdf_dev->dev,
85 			   qdf_mem_paddr_from_dmaaddr(qdf_dev,
86 						      info->shadow_rdptr_mem_paddr),
87 			   info->shadow_rdptr_mem_paddr,
88 			   info->shadow_rdptr_mem_size);
89 	pld_audio_smmu_map(qdf_dev->dev,
90 			   qdf_mem_paddr_from_dmaaddr(qdf_dev,
91 						      info->shadow_wrptr_mem_paddr),
92 			   info->shadow_wrptr_mem_paddr,
93 			   info->shadow_wrptr_mem_size);
94 
95 	info->ce_info_len = QMI_WFDS_CE_MAX_SRNG;
96 	status = hif_get_direct_link_ce_srng_info(hif_ctx, ce_info,
97 						  QMI_WFDS_CE_MAX_SRNG);
98 	if (QDF_IS_STATUS_ERROR(status)) {
99 		dp_err("Direct Link CE srng info get failed");
100 		qdf_mem_free(info);
101 		return status;
102 	}
103 
104 	for (i = 0; i < QMI_WFDS_CE_MAX_SRNG; i++) {
105 		info->ce_info[i].ce_id = ce_info[i].ce_id;
106 		info->ce_info[i].ce_dir = ce_info[i].pipe_dir;
107 
108 		srng_info = &ce_info[i].ring_info;
109 		info->ce_info[i].srng_info.ring_id = srng_info->ring_id;
110 		info->ce_info[i].srng_info.dir = srng_info->ring_dir;
111 		info->ce_info[i].srng_info.num_entries = srng_info->num_entries;
112 		info->ce_info[i].srng_info.entry_size = srng_info->entry_size;
113 		info->ce_info[i].srng_info.ring_base_paddr =
114 						     srng_info->ring_base_paddr;
115 		info->ce_info[i].srng_info.hp_paddr = srng_info->hp_paddr;
116 		info->ce_info[i].srng_info.tp_paddr = srng_info->tp_paddr;
117 
118 		dl_wfds->iommu_cfg.direct_link_srng_ring_base_paddr[i] =
119 			srng_info->ring_base_paddr;
120 		dl_wfds->iommu_cfg.direct_link_srng_ring_map_size[i] =
121 			srng_info->entry_size * srng_info->num_entries * 4;
122 
123 		pld_audio_smmu_map(qdf_dev->dev,
124 				   qdf_mem_paddr_from_dmaaddr(qdf_dev,
125 							      srng_info->ring_base_paddr),
126 				   srng_info->ring_base_paddr,
127 				   dl_wfds->iommu_cfg.direct_link_srng_ring_map_size[i]);
128 	}
129 
130 	refill_ring = direct_link_ctx->direct_link_refill_ring_hdl->hal_srng;
131 	hal_get_srng_params(hal_soc, refill_ring, &srng_params);
132 	info->rx_refill_ring.ring_id = srng_params.ring_id;
133 	info->rx_refill_ring.dir =
134 		(srng_params.ring_dir == HAL_SRNG_SRC_RING) ?
135 		QMI_WFDS_SRNG_SOURCE_RING : QMI_WFDS_SRNG_DESTINATION_RING;
136 	info->rx_refill_ring.num_entries = srng_params.num_entries;
137 	info->rx_refill_ring.entry_size = srng_params.entry_size;
138 	info->rx_refill_ring.ring_base_paddr = srng_params.ring_base_paddr;
139 
140 	dl_wfds->iommu_cfg.direct_link_refill_ring_base_paddr = srng_params.ring_base_paddr;
141 	dl_wfds->iommu_cfg.direct_link_refill_ring_map_size =
142 		srng_params.entry_size * srng_params.num_entries * 4;
143 
144 	pld_audio_smmu_map(qdf_dev->dev,
145 			   qdf_mem_paddr_from_dmaaddr(qdf_dev,
146 						      srng_params.ring_base_paddr),
147 			   srng_params.ring_base_paddr,
148 			   dl_wfds->iommu_cfg.direct_link_refill_ring_map_size);
149 
150 	info->rx_refill_ring.hp_paddr =
151 				hal_srng_get_hp_addr(hal_soc, refill_ring);
152 	info->rx_refill_ring.tp_paddr =
153 				hal_srng_get_tp_addr(hal_soc, refill_ring);
154 
155 	info->rx_pkt_tlv_len = dp_soc->rx_pkt_tlv_size;
156 	info->rx_rbm = dp_rx_get_rx_bm_id(dp_soc);
157 	info->pci_slot = pld_get_pci_slot(qdf_dev->dev);
158 	qdf_assert(info.pci_slot >= 0);
159 	info->lpass_ep_id = direct_link_ctx->lpass_ep_id;
160 
161 	status = wlan_qmi_wfds_send_config_msg(direct_link_ctx->dp_ctx->psoc,
162 					       info);
163 	qdf_mem_free(info);
164 
165 	if (QDF_IS_STATUS_ERROR(status)) {
166 		dp_err("Configuration message send failed %d", status);
167 		return status;
168 	}
169 
170 	qdf_atomic_set(&dl_wfds->wfds_state,
171 		       DP_WFDS_SVC_CONFIG_DONE);
172 
173 	return status;
174 }
175 
176 /**
177  * dp_wfds_req_mem_msg() - Send Request Memory message to QMI server
178  * @dl_wfds: Direct Link QMI context
179  *
180  * Return: QDF status
181  */
182 static QDF_STATUS
183 dp_wfds_req_mem_msg(struct dp_direct_link_wfds_context *dl_wfds)
184 {
185 	struct wlan_qmi_wfds_mem_req_msg *info;
186 	struct dp_soc *dp_soc =
187 		wlan_psoc_get_dp_handle(dl_wfds->direct_link_ctx->dp_ctx->psoc);
188 	struct hif_opaque_softc *hif_ctx;
189 	qdf_device_t qdf_dev;
190 	QDF_STATUS status;
191 	struct qdf_mem_multi_page_t *pages;
192 	uint16_t num_pages;
193 	uint8_t i;
194 
195 	qdf_dev = dl_wfds->direct_link_ctx->dp_ctx->qdf_dev;
196 
197 	if (!dl_wfds || !dp_soc || !dp_soc->hif_handle || !qdf_dev)
198 		return QDF_STATUS_E_NOSUPPORT;
199 
200 	hif_ctx = dp_soc->hif_handle;
201 
202 	info = qdf_mem_malloc(sizeof(*info));
203 	if (!info)
204 		return QDF_STATUS_E_NOMEM;
205 
206 	info->mem_arena_page_info_len = dl_wfds->num_mem_arenas;
207 	for (i = 0; i < dl_wfds->num_mem_arenas; i++) {
208 		if (i == QMI_WFDS_MEM_ARENA_CE_RX_MSG_BUFFERS) {
209 			uint64_t *dma_addr = NULL;
210 			uint32_t buf_size;
211 
212 			num_pages =
213 			    hif_get_direct_link_ce_dest_srng_buffers(hif_ctx,
214 								     &dma_addr,
215 								     &buf_size);
216 			qdf_assert(dma_addr);
217 
218 			info->mem_arena_page_info[i].num_entries_per_page =
219 					qdf_page_size / buf_size;
220 			info->mem_arena_page_info[i].page_dma_addr_len =
221 								      num_pages;
222 			while (num_pages--) {
223 				info->mem_arena_page_info[i].page_dma_addr[num_pages] =
224 							dma_addr[num_pages];
225 				pld_audio_smmu_map(qdf_dev->dev,
226 						   qdf_mem_paddr_from_dmaaddr(qdf_dev, dma_addr[num_pages]),
227 						   dma_addr[num_pages],
228 						   buf_size);
229 			}
230 
231 			qdf_mem_free(dma_addr);
232 			continue;
233 		}
234 
235 		num_pages = dl_wfds->mem_arena_pages[i].num_pages;
236 		pages = &dl_wfds->mem_arena_pages[i];
237 
238 		info->mem_arena_page_info[i].num_entries_per_page =
239 		       dl_wfds->mem_arena_pages[i].num_element_per_page;
240 		info->mem_arena_page_info[i].page_dma_addr_len = num_pages;
241 
242 		while (num_pages--) {
243 			info->mem_arena_page_info[i].page_dma_addr[num_pages] =
244 					pages->dma_pages[num_pages].page_p_addr;
245 
246 			pld_audio_smmu_map(qdf_dev->dev,
247 					qdf_mem_paddr_from_dmaaddr(qdf_dev, pages->dma_pages[num_pages].page_p_addr),
248 					pages->dma_pages[num_pages].page_p_addr,
249 					pages->page_size);
250 		}
251 	}
252 
253 	status = wlan_qmi_wfds_send_req_mem_msg(
254 					dl_wfds->direct_link_ctx->dp_ctx->psoc,
255 					info);
256 	qdf_mem_free(info);
257 
258 	if (QDF_IS_STATUS_ERROR(status)) {
259 		dp_err("Memory request message send failed %d", status);
260 		return status;
261 	}
262 
263 	qdf_atomic_set(&dl_wfds->wfds_state,
264 		       DP_WFDS_SVC_MEM_CONFIG_DONE);
265 
266 	return status;
267 }
268 
269 /**
270  * dp_wfds_ipcc_map_n_cfg_msg() - Send the IPCC map and configure message
271  *  to QMI server
272  * @dlink_wfds: Direct Link QMI context
273  *
274  * Return: QDF status
275  */
276 static QDF_STATUS
277 dp_wfds_ipcc_map_n_cfg_msg(struct dp_direct_link_wfds_context *dlink_wfds)
278 {
279 	struct wlan_qmi_wfds_ipcc_map_n_cfg_req_msg info = {0};
280 	QDF_STATUS status;
281 
282 	info.status = QMI_WFDS_STATUS_SUCCESS;
283 
284 	status = wlan_qmi_wfds_ipcc_map_n_cfg_msg(
285 				dlink_wfds->direct_link_ctx->dp_ctx->psoc,
286 				&info);
287 	if (QDF_IS_STATUS_ERROR(status)) {
288 		dp_err("IPCC map n cfg message send failed %d", status);
289 		return status;
290 	}
291 
292 	qdf_atomic_set(&dlink_wfds->wfds_state,
293 		       DP_WFDS_SVC_IPCC_MAP_N_CFG_DONE);
294 
295 	return status;
296 }
297 
298 /**
299  * dp_wfds_work() - DP WFDS work handler
300  * @arg: direct link QMI context
301  *
302  * Return: None
303  */
304 static void dp_wfds_work(void *arg)
305 {
306 	struct dp_direct_link_wfds_context *dl_wfds = arg;
307 	struct dp_wfds_event *wfds_evt;
308 
309 	dp_debug("entry");
310 
311 	qdf_spinlock_acquire(&dl_wfds->wfds_event_list_lock);
312 	while ((wfds_evt =
313 		qdf_list_first_entry_or_null(&dl_wfds->wfds_event_list,
314 					     struct dp_wfds_event,
315 					     list_node))) {
316 		qdf_list_remove_node(&dl_wfds->wfds_event_list,
317 				     &wfds_evt->list_node);
318 		qdf_spinlock_release(&dl_wfds->wfds_event_list_lock);
319 
320 		switch (wfds_evt->wfds_evt_type) {
321 		case DP_WFDS_NEW_SERVER:
322 			dp_wfds_send_config_msg(dl_wfds);
323 			break;
324 		case DP_WFDS_MEM_REQ:
325 			dp_wfds_req_mem_msg(dl_wfds);
326 			break;
327 		case DP_WFDS_IPCC_MAP_N_CFG:
328 			dp_wfds_ipcc_map_n_cfg_msg(dl_wfds);
329 			break;
330 		default:
331 			break;
332 		}
333 
334 		qdf_mem_free(wfds_evt);
335 
336 		qdf_spinlock_acquire(&dl_wfds->wfds_event_list_lock);
337 	}
338 	qdf_spinlock_release(&dl_wfds->wfds_event_list_lock);
339 
340 	dp_debug("exit");
341 }
342 
343 /**
344  * dp_wfds_event_post() - Post WFDS event to be processed in worker context
345  * @dl_wfds: Direct Link QMI context
346  * @wfds_evt_type: QMI event type
347  * @data: pointer to QMI data
348  *
349  * Return: QDF status
350  */
351 static QDF_STATUS
352 dp_wfds_event_post(struct dp_direct_link_wfds_context *dl_wfds,
353 		   enum dp_wfds_event_type wfds_evt_type, void *data)
354 {
355 	struct dp_wfds_event *wfds_evt;
356 
357 	wfds_evt = qdf_mem_malloc(sizeof(*wfds_evt));
358 	if (!wfds_evt)
359 		return QDF_STATUS_E_NOMEM;
360 
361 	wfds_evt->wfds_evt_type = wfds_evt_type;
362 	wfds_evt->data = data;
363 
364 	qdf_spinlock_acquire(&dl_wfds->wfds_event_list_lock);
365 	qdf_list_insert_back(&dl_wfds->wfds_event_list,
366 			     &wfds_evt->list_node);
367 	qdf_spinlock_release(&dl_wfds->wfds_event_list_lock);
368 
369 	qdf_queue_work(0, dl_wfds->wfds_wq, &dl_wfds->wfds_work);
370 
371 	return QDF_STATUS_SUCCESS;
372 }
373 
374 #ifdef DP_MEM_PRE_ALLOC
375 /**
376  * dp_wfds_get_desc_type_from_mem_arena() - Get descriptor type for the memory
377  *  arena
378  * @mem_arena: memory arena
379  *
380  * Return: DP descriptor type
381  */
382 static uint32_t
383 dp_wfds_get_desc_type_from_mem_arena(enum wlan_qmi_wfds_mem_arenas mem_arena)
384 {
385 	switch (mem_arena) {
386 	case QMI_WFDS_MEM_ARENA_TX_BUFFERS:
387 		return QDF_DP_TX_DIRECT_LINK_BUF_TYPE;
388 	case QMI_WFDS_MEM_ARENA_CE_TX_MSG_BUFFERS:
389 		return QDF_DP_TX_DIRECT_LINK_CE_BUF_TYPE;
390 	default:
391 		dp_debug("No desc type for mem arena %d", mem_arena);
392 		qdf_assert(0);
393 		return QDF_DP_DESC_TYPE_MAX;
394 	}
395 }
396 
397 /**
398  * dp_wfds_alloc_mem_arena() - Allocate memory for the arena
399  * @dl_wfds: Direct Link QMI context
400  * @mem_arena: memory arena
401  * @entry_size: element size
402  * @num_entries: number of elements
403  *
404  * Return: None
405  */
406 static void
407 dp_wfds_alloc_mem_arena(struct dp_direct_link_wfds_context *dl_wfds,
408 			enum wlan_qmi_wfds_mem_arenas mem_arena,
409 			uint16_t entry_size, uint16_t num_entries)
410 {
411 	qdf_device_t qdf_ctx = dl_wfds->direct_link_ctx->dp_ctx->qdf_dev;
412 	uint32_t desc_type;
413 
414 	desc_type = dp_wfds_get_desc_type_from_mem_arena(mem_arena);
415 
416 	if (desc_type != QDF_DP_DESC_TYPE_MAX)
417 		dp_prealloc_get_multi_pages(desc_type, entry_size,
418 					    num_entries,
419 					    &dl_wfds->mem_arena_pages[mem_arena],
420 					    false);
421 
422 	if (!dl_wfds->mem_arena_pages[mem_arena].num_pages)
423 		qdf_mem_multi_pages_alloc(qdf_ctx,
424 					  &dl_wfds->mem_arena_pages[mem_arena],
425 					  entry_size, num_entries, 0, false);
426 }
427 
428 /**
429  * dp_wfds_free_mem_arena() - Free memory for the arena
430  * @dl_wfds: Direct Link QMI context
431  * @mem_arena: memory arena
432  *
433  * Return: None
434  */
435 static void
436 dp_wfds_free_mem_arena(struct dp_direct_link_wfds_context *dl_wfds,
437 		       enum wlan_qmi_wfds_mem_arenas mem_arena)
438 {
439 	qdf_device_t qdf_ctx = dl_wfds->direct_link_ctx->dp_ctx->qdf_dev;
440 	uint32_t desc_type;
441 
442 	if (dl_wfds->mem_arena_pages[mem_arena].is_mem_prealloc) {
443 		desc_type = dp_wfds_get_desc_type_from_mem_arena(mem_arena);
444 		dp_prealloc_put_multi_pages(desc_type,
445 					  &dl_wfds->mem_arena_pages[mem_arena]);
446 	} else {
447 		qdf_mem_multi_pages_free(qdf_ctx,
448 					 &dl_wfds->mem_arena_pages[mem_arena],
449 					 0, false);
450 	}
451 }
452 #else
453 static void
454 dp_wfds_alloc_mem_arena(struct dp_direct_link_wfds_context *dl_wfds,
455 			enum wlan_qmi_wfds_mem_arenas mem_arena,
456 			uint16_t entry_size, uint16_t num_entries)
457 {
458 	qdf_device_t qdf_ctx = dl_wfds->direct_link_ctx->dp_ctx->qdf_dev;
459 
460 	qdf_mem_multi_pages_alloc(qdf_ctx,
461 				  &dl_wfds->mem_arena_pages[mem_arena],
462 				  entry_size, num_entries, 0, false);
463 }
464 
465 static void
466 dp_wfds_free_mem_arena(struct dp_direct_link_wfds_context *dl_wfds,
467 		       enum wlan_qmi_wfds_mem_arenas mem_arena)
468 {
469 	qdf_device_t qdf_ctx = dl_wfds->direct_link_ctx->dp_ctx->qdf_dev;
470 
471 	qdf_mem_multi_pages_free(qdf_ctx,
472 				 &dl_wfds->mem_arena_pages[mem_arena],
473 				 0, false);
474 }
475 #endif
476 
477 void
478 dp_wfds_handle_request_mem_ind(struct wlan_qmi_wfds_mem_ind_msg *mem_msg)
479 {
480 	struct dp_direct_link_wfds_context *dl_wfds = gp_dl_wfds_ctx;
481 	uint8_t i;
482 
483 	if (!dl_wfds)
484 		return;
485 
486 	dp_debug("Received request mem indication from QMI server");
487 
488 	dl_wfds->num_mem_arenas = mem_msg->mem_arena_info_len;
489 	dl_wfds->mem_arena_pages =
490 		qdf_mem_malloc(sizeof(*dl_wfds->mem_arena_pages) *
491 			       mem_msg->mem_arena_info_len);
492 	if (!dl_wfds->mem_arena_pages)
493 		return;
494 
495 	for (i = 0; i < dl_wfds->num_mem_arenas; i++) {
496 		if (i == QMI_WFDS_MEM_ARENA_CE_RX_MSG_BUFFERS)
497 			continue;
498 
499 		dp_wfds_alloc_mem_arena(dl_wfds, i,
500 					mem_msg->mem_arena_info[i].entry_size,
501 					mem_msg->mem_arena_info[i].num_entries);
502 
503 		if (!dl_wfds->mem_arena_pages[i].num_pages) {
504 			while (--i >= 0 &&
505 			       dl_wfds->mem_arena_pages[i].num_pages)
506 				dp_wfds_free_mem_arena(dl_wfds, i);
507 
508 			qdf_mem_free(dl_wfds->mem_arena_pages);
509 			dl_wfds->mem_arena_pages = NULL;
510 			dl_wfds->num_mem_arenas = 0;
511 
512 			return;
513 		}
514 	}
515 
516 	dp_wfds_event_post(dl_wfds, DP_WFDS_MEM_REQ, NULL);
517 }
518 
519 void
520 dp_wfds_handle_ipcc_map_n_cfg_ind(struct wlan_qmi_wfds_ipcc_map_n_cfg_ind_msg *ipcc_msg)
521 {
522 	struct dp_direct_link_wfds_context *dl_wfds = gp_dl_wfds_ctx;
523 	qdf_device_t qdf_ctx = dl_wfds->direct_link_ctx->dp_ctx->qdf_dev;
524 	struct dp_soc *dp_soc =
525 		wlan_psoc_get_dp_handle(dl_wfds->direct_link_ctx->dp_ctx->psoc);
526 	struct hif_opaque_softc *hif_ctx;
527 	uint8_t i;
528 
529 	if (!dl_wfds || !qdf_ctx || !dp_soc || !dp_soc->hif_handle)
530 		return;
531 
532 	hif_ctx = dp_soc->hif_handle;
533 
534 	dp_debug("Received IPCC map n cfg indication from QMI server");
535 
536 	/*
537 	 * IPCC Address for all the CE srngs will be the same and only the
538 	 * IPCC data will differ.
539 	 */
540 	pld_smmu_map(qdf_ctx->dev, ipcc_msg->ipcc_ce_info[0].ipcc_trig_addr,
541 		     &dl_wfds->ipcc_dma_addr, sizeof(uint32_t));
542 
543 	dl_wfds->ipcc_ce_id_len = ipcc_msg->ipcc_ce_info_len;
544 
545 	for (i = 0; i < ipcc_msg->ipcc_ce_info_len; i++) {
546 		dl_wfds->ipcc_ce_id[i] = ipcc_msg->ipcc_ce_info[i].ce_id;
547 		hif_set_irq_config_by_ceid(hif_ctx,
548 				      ipcc_msg->ipcc_ce_info[i].ce_id,
549 				      dl_wfds->ipcc_dma_addr,
550 				      ipcc_msg->ipcc_ce_info[i].ipcc_trig_data);
551 	}
552 
553 	dp_wfds_event_post(dl_wfds, DP_WFDS_IPCC_MAP_N_CFG, NULL);
554 }
555 
556 QDF_STATUS dp_wfds_new_server(void)
557 {
558 	struct dp_direct_link_wfds_context *dl_wfds = gp_dl_wfds_ctx;
559 	void *htc_handle = cds_get_context(QDF_MODULE_ID_HTC);
560 
561 	if (!dl_wfds || !htc_handle)
562 		return QDF_STATUS_E_INVAL;
563 
564 	qdf_atomic_set(&dl_wfds->wfds_state, DP_WFDS_SVC_CONNECTED);
565 
566 	htc_vote_link_up(htc_handle, HTC_LINK_VOTE_DIRECT_LINK_USER_ID);
567 	dp_debug("Connected to WFDS QMI service, state: 0x%x",
568 		 qdf_atomic_read(&dl_wfds->wfds_state));
569 
570 	return dp_wfds_event_post(dl_wfds, DP_WFDS_NEW_SERVER, NULL);
571 }
572 
573 void dp_wfds_del_server(void)
574 {
575 	struct dp_direct_link_wfds_context *dl_wfds = gp_dl_wfds_ctx;
576 	qdf_device_t qdf_ctx = dl_wfds->direct_link_ctx->dp_ctx->qdf_dev;
577 	void *htc_handle = cds_get_context(QDF_MODULE_ID_HTC);
578 	void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF);
579 	enum dp_wfds_state dl_wfds_state;
580 	uint8_t i;
581 	uint16_t page_idx;
582 
583 	if (!dl_wfds || !qdf_ctx || !hif_ctx || !htc_handle)
584 		return;
585 
586 	dp_debug("WFDS QMI server exiting");
587 
588 	dl_wfds_state = qdf_atomic_read(&dl_wfds->wfds_state);
589 	qdf_atomic_set(&dl_wfds->wfds_state,
590 		       DP_WFDS_SVC_DISCONNECTED);
591 
592 	if (dl_wfds_state >= DP_WFDS_SVC_IPCC_MAP_N_CFG_DONE &&
593 	    dl_wfds->ipcc_dma_addr) {
594 		for (i = 0; i < dl_wfds->ipcc_ce_id_len; i++)
595 			hif_set_irq_config_by_ceid(hif_ctx,
596 						   dl_wfds->ipcc_ce_id[i],
597 						   0, 0);
598 
599 		pld_smmu_unmap(qdf_ctx->dev, dl_wfds->ipcc_dma_addr,
600 			       sizeof(uint32_t));
601 	}
602 
603 	if (dl_wfds_state >= DP_WFDS_SVC_MEM_CONFIG_DONE) {
604 		uint64_t *dma_addr = NULL;
605 		uint16_t num_pages;
606 		uint32_t buf_size;
607 
608 		for (i = 0; i < dl_wfds->num_mem_arenas; i++) {
609 			struct qdf_mem_multi_page_t *mp_info;
610 
611 			if (!dl_wfds->mem_arena_pages[i].num_pages)
612 				continue;
613 
614 			mp_info = &dl_wfds->mem_arena_pages[i];
615 			for (page_idx = 0; page_idx < mp_info->num_pages;
616 			     page_idx++)
617 				pld_audio_smmu_unmap(qdf_ctx->dev,
618 				       mp_info->dma_pages[page_idx].page_p_addr,
619 				       mp_info->page_size);
620 
621 			dp_wfds_free_mem_arena(dl_wfds, i);
622 		}
623 
624 		qdf_mem_free(dl_wfds->mem_arena_pages);
625 		dl_wfds->mem_arena_pages = NULL;
626 		dl_wfds->num_mem_arenas = 0;
627 
628 		num_pages = hif_get_direct_link_ce_dest_srng_buffers(hif_ctx,
629 								     &dma_addr,
630 								     &buf_size);
631 		qdf_assert(dma_addr);
632 
633 		while (num_pages--)
634 			pld_audio_smmu_unmap(qdf_ctx->dev, dma_addr[num_pages],
635 					     buf_size);
636 
637 		qdf_mem_free(dma_addr);
638 	}
639 
640 	if (dl_wfds_state >= DP_WFDS_SVC_CONFIG_DONE) {
641 		pld_audio_smmu_unmap(qdf_ctx->dev,
642 				     dl_wfds->iommu_cfg.shadow_rdptr_paddr,
643 				     dl_wfds->iommu_cfg.shadow_rdptr_map_size);
644 		pld_audio_smmu_unmap(qdf_ctx->dev,
645 				     dl_wfds->iommu_cfg.shadow_wrptr_paddr,
646 				     dl_wfds->iommu_cfg.shadow_wrptr_map_size);
647 
648 		for (i = 0; i < QMI_WFDS_CE_MAX_SRNG; i++)
649 			pld_audio_smmu_unmap(qdf_ctx->dev,
650 				dl_wfds->iommu_cfg.direct_link_srng_ring_base_paddr[i],
651 				dl_wfds->iommu_cfg.direct_link_srng_ring_map_size[i]);
652 
653 		pld_audio_smmu_unmap(qdf_ctx->dev,
654 			dl_wfds->iommu_cfg.direct_link_refill_ring_base_paddr,
655 			dl_wfds->iommu_cfg.direct_link_refill_ring_map_size);
656 	}
657 
658 	htc_vote_link_down(htc_handle, HTC_LINK_VOTE_DIRECT_LINK_USER_ID);
659 }
660 
661 QDF_STATUS dp_wfds_init(struct dp_direct_link_context *dp_direct_link_ctx)
662 {
663 	struct dp_direct_link_wfds_context *dl_wfds;
664 	QDF_STATUS status;
665 
666 	dl_wfds = qdf_mem_malloc(sizeof(*dl_wfds));
667 	if (!dl_wfds) {
668 		status = QDF_STATUS_E_NOMEM;
669 		goto out;
670 	}
671 
672 	qdf_spinlock_create(&dl_wfds->wfds_event_list_lock);
673 	qdf_list_create(&dl_wfds->wfds_event_list, 0);
674 
675 	status = qdf_create_work(0, &dl_wfds->wfds_work,
676 				 dp_wfds_work, dl_wfds);
677 	if (status != QDF_STATUS_SUCCESS) {
678 		dp_err("DP QMI work create failed");
679 		goto wfds_work_create_fail;
680 	}
681 
682 	dl_wfds->wfds_wq = qdf_alloc_unbound_workqueue("dp_wfds_wq");
683 	if (!dl_wfds->wfds_wq) {
684 		dp_err("DP QMI workqueue allocate failed");
685 		goto wfds_wq_alloc_fail;
686 	}
687 
688 	qdf_atomic_set(&dl_wfds->wfds_state,
689 		       DP_WFDS_SVC_DISCONNECTED);
690 
691 	status = wlan_qmi_wfds_init(dp_direct_link_ctx->dp_ctx->psoc);
692 	if (QDF_IS_STATUS_ERROR(status)) {
693 		dp_err("WFDS QMI initialization failed %d", status);
694 		goto qmi_wfds_init_fail;
695 	}
696 
697 	dp_direct_link_ctx->dl_wfds = dl_wfds;
698 	dl_wfds->direct_link_ctx = dp_direct_link_ctx;
699 	gp_dl_wfds_ctx = dl_wfds;
700 	dp_debug("WFDS QMI init successful");
701 
702 	return status;
703 
704 qmi_wfds_init_fail:
705 	qdf_flush_workqueue(0, dl_wfds->wfds_wq);
706 	qdf_destroy_workqueue(0, dl_wfds->wfds_wq);
707 
708 wfds_wq_alloc_fail:
709 	qdf_flush_work(&dl_wfds->wfds_work);
710 	qdf_destroy_work(0, &dl_wfds->wfds_work);
711 
712 wfds_work_create_fail:
713 	qdf_spinlock_destroy(&dl_wfds->wfds_event_list_lock);
714 	qdf_list_destroy(&dl_wfds->wfds_event_list);
715 	qdf_mem_free(dl_wfds);
716 
717 out:
718 	return status;
719 }
720 
721 void dp_wfds_deinit(struct dp_direct_link_context *dp_direct_link_ctx,
722 		    bool is_ssr)
723 {
724 	struct dp_direct_link_wfds_context *dl_wfds;
725 
726 	if (!dp_direct_link_ctx)
727 		return;
728 
729 	dl_wfds = dp_direct_link_ctx->dl_wfds;
730 
731 	dp_debug("WFDS QMI deinit");
732 
733 	qdf_flush_workqueue(0, dl_wfds->wfds_wq);
734 	qdf_destroy_workqueue(0, dl_wfds->wfds_wq);
735 
736 	qdf_flush_work(&dl_wfds->wfds_work);
737 	qdf_destroy_work(0, &dl_wfds->wfds_work);
738 
739 	qdf_spinlock_destroy(&dl_wfds->wfds_event_list_lock);
740 	qdf_list_destroy(&dl_wfds->wfds_event_list);
741 
742 	if (qdf_atomic_read(&dl_wfds->wfds_state) !=
743 	    DP_WFDS_SVC_DISCONNECTED)
744 		wlan_qmi_wfds_send_misc_req_msg(dp_direct_link_ctx->dp_ctx->psoc,
745 						is_ssr);
746 
747 	wlan_qmi_wfds_deinit(dp_direct_link_ctx->dp_ctx->psoc);
748 	gp_dl_wfds_ctx = NULL;
749 
750 	qdf_mem_free(dl_wfds);
751 }
752