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