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
dp_wfds_send_config_msg(struct dp_direct_link_wfds_context * dl_wfds)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
dp_wfds_req_mem_msg(struct dp_direct_link_wfds_context * dl_wfds)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
dp_wfds_ipcc_map_n_cfg_msg(struct dp_direct_link_wfds_context * dlink_wfds)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 */
dp_wfds_work(void * arg)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
dp_wfds_event_post(struct dp_direct_link_wfds_context * dl_wfds,enum dp_wfds_event_type wfds_evt_type,void * data)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
dp_wfds_get_desc_type_from_mem_arena(enum wlan_qmi_wfds_mem_arenas mem_arena)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
dp_wfds_alloc_mem_arena(struct dp_direct_link_wfds_context * dl_wfds,enum wlan_qmi_wfds_mem_arenas mem_arena,uint16_t entry_size,uint16_t num_entries)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
dp_wfds_free_mem_arena(struct dp_direct_link_wfds_context * dl_wfds,enum wlan_qmi_wfds_mem_arenas mem_arena)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
dp_wfds_alloc_mem_arena(struct dp_direct_link_wfds_context * dl_wfds,enum wlan_qmi_wfds_mem_arenas mem_arena,uint16_t entry_size,uint16_t num_entries)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
dp_wfds_free_mem_arena(struct dp_direct_link_wfds_context * dl_wfds,enum wlan_qmi_wfds_mem_arenas mem_arena)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
dp_wfds_handle_request_mem_ind(struct wlan_qmi_wfds_mem_ind_msg * mem_msg)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
dp_wfds_handle_ipcc_map_n_cfg_ind(struct wlan_qmi_wfds_ipcc_map_n_cfg_ind_msg * ipcc_msg)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
dp_wfds_new_server(void)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
dp_wfds_del_server(void)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
dp_wfds_init(struct dp_direct_link_context * dp_direct_link_ctx)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
dp_wfds_deinit(struct dp_direct_link_context * dp_direct_link_ctx,bool is_ssr)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