| /* |
| * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. |
| * |
| * Permission to use, copy, modify, and/or distribute this software for |
| * any purpose with or without fee is hereby granted, provided that the |
| * above copyright notice and this permission notice appear in all |
| * copies. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL |
| * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE |
| * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL |
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR |
| * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
| * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
| * PERFORMANCE OF THIS SOFTWARE. |
| */ |
| |
| #include "target_if.h" |
| #include "wlan_lmac_if_def.h" |
| #include "target_if_direct_buf_rx_main.h" |
| #include <target_if_direct_buf_rx_api.h> |
| #include "hal_api.h" |
| #include <service_ready_util.h> |
| #include <init_deinit_lmac.h> |
| |
| /** |
| * struct module_name : Module name information structure |
| * @module_name_str : Module name subscribing to DBR |
| */ |
| struct module_name { |
| unsigned char module_name_str[QDF_MAX_NAME_SIZE]; |
| }; |
| |
| static const struct module_name g_dbr_module_name[DBR_MODULE_MAX] = { |
| [DBR_MODULE_SPECTRAL] = {"SPECTRAL"}, |
| [DBR_MODULE_CFR] = {"CFR"}, |
| }; |
| |
| static uint8_t get_num_dbr_modules_per_pdev(struct wlan_objmgr_pdev *pdev) |
| { |
| struct wlan_objmgr_psoc *psoc; |
| struct wlan_psoc_host_dbr_ring_caps *dbr_ring_cap; |
| uint8_t num_dbr_ring_caps, cap_idx, pdev_id, num_modules; |
| struct target_psoc_info *tgt_psoc_info; |
| struct wlan_psoc_host_service_ext_param *ext_svc_param; |
| |
| psoc = wlan_pdev_get_psoc(pdev); |
| |
| if (!psoc) { |
| direct_buf_rx_err("psoc is null"); |
| return 0; |
| } |
| |
| tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc); |
| if (!tgt_psoc_info) { |
| direct_buf_rx_err("target_psoc_info is null"); |
| return 0; |
| } |
| ext_svc_param = target_psoc_get_service_ext_param(tgt_psoc_info); |
| num_dbr_ring_caps = ext_svc_param->num_dbr_ring_caps; |
| dbr_ring_cap = target_psoc_get_dbr_ring_caps(tgt_psoc_info); |
| pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); |
| num_modules = 0; |
| |
| for (cap_idx = 0; cap_idx < num_dbr_ring_caps; cap_idx++) { |
| if (dbr_ring_cap[cap_idx].pdev_id == pdev_id) |
| num_modules++; |
| } |
| |
| return num_modules; |
| } |
| |
| static QDF_STATUS populate_dbr_cap_mod_param(struct wlan_objmgr_pdev *pdev, |
| struct direct_buf_rx_module_param *mod_param) |
| { |
| struct wlan_objmgr_psoc *psoc; |
| struct wlan_psoc_host_dbr_ring_caps *dbr_ring_cap; |
| uint8_t cap_idx; |
| bool cap_found = false; |
| enum DBR_MODULE mod_id = mod_param->mod_id; |
| uint32_t num_dbr_ring_caps, pdev_id; |
| struct target_psoc_info *tgt_psoc_info; |
| struct wlan_psoc_host_service_ext_param *ext_svc_param; |
| |
| psoc = wlan_pdev_get_psoc(pdev); |
| |
| if (!psoc) { |
| direct_buf_rx_err("psoc is null"); |
| return QDF_STATUS_E_INVAL; |
| } |
| |
| tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc); |
| if (!tgt_psoc_info) { |
| direct_buf_rx_err("target_psoc_info is null"); |
| return QDF_STATUS_E_INVAL; |
| } |
| |
| ext_svc_param = target_psoc_get_service_ext_param(tgt_psoc_info); |
| num_dbr_ring_caps = ext_svc_param->num_dbr_ring_caps; |
| dbr_ring_cap = target_psoc_get_dbr_ring_caps(tgt_psoc_info); |
| pdev_id = mod_param->pdev_id; |
| |
| for (cap_idx = 0; cap_idx < num_dbr_ring_caps; cap_idx++) { |
| if (dbr_ring_cap[cap_idx].pdev_id == pdev_id) { |
| if (dbr_ring_cap[cap_idx].mod_id == mod_id) { |
| mod_param->dbr_ring_cap->ring_elems_min = |
| dbr_ring_cap[cap_idx].ring_elems_min; |
| mod_param->dbr_ring_cap->min_buf_size = |
| dbr_ring_cap[cap_idx].min_buf_size; |
| mod_param->dbr_ring_cap->min_buf_align = |
| dbr_ring_cap[cap_idx].min_buf_align; |
| cap_found = true; |
| } |
| } |
| } |
| |
| if (!cap_found) { |
| direct_buf_rx_err("No cap found for module %d in pdev %d", |
| mod_id, pdev_id); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| return QDF_STATUS_SUCCESS; |
| } |
| |
| QDF_STATUS target_if_direct_buf_rx_pdev_create_handler( |
| struct wlan_objmgr_pdev *pdev, void *data) |
| { |
| struct direct_buf_rx_pdev_obj *dbr_pdev_obj; |
| struct wlan_objmgr_psoc *psoc; |
| uint8_t num_modules; |
| QDF_STATUS status; |
| |
| direct_buf_rx_enter(); |
| |
| if (!pdev) { |
| direct_buf_rx_err("pdev context passed is null"); |
| return QDF_STATUS_E_INVAL; |
| } |
| |
| psoc = wlan_pdev_get_psoc(pdev); |
| |
| if (!psoc) { |
| direct_buf_rx_err("psoc is null"); |
| return QDF_STATUS_E_INVAL; |
| } |
| |
| dbr_pdev_obj = qdf_mem_malloc(sizeof(*dbr_pdev_obj)); |
| |
| if (!dbr_pdev_obj) |
| return QDF_STATUS_E_NOMEM; |
| |
| direct_buf_rx_info("Dbr pdev obj %pK", dbr_pdev_obj); |
| |
| status = wlan_objmgr_pdev_component_obj_attach(pdev, |
| WLAN_TARGET_IF_COMP_DIRECT_BUF_RX, |
| dbr_pdev_obj, QDF_STATUS_SUCCESS); |
| |
| if (status != QDF_STATUS_SUCCESS) { |
| direct_buf_rx_err("Failed to attach dir buf rx component %d", |
| status); |
| qdf_mem_free(dbr_pdev_obj); |
| return status; |
| } |
| |
| num_modules = get_num_dbr_modules_per_pdev(pdev); |
| direct_buf_rx_debug("Number of modules = %d pdev %d DBR pdev obj %pK", |
| num_modules, wlan_objmgr_pdev_get_pdev_id(pdev), |
| dbr_pdev_obj); |
| dbr_pdev_obj->num_modules = num_modules; |
| |
| if (!dbr_pdev_obj->num_modules) { |
| direct_buf_rx_info("Number of modules = %d", num_modules); |
| return QDF_STATUS_SUCCESS; |
| } |
| |
| direct_buf_rx_debug("sring number = %d", DBR_SRNG_NUM); |
| dbr_pdev_obj->dbr_mod_param = qdf_mem_malloc(num_modules * |
| DBR_SRNG_NUM * |
| sizeof(struct direct_buf_rx_module_param)); |
| |
| if (!dbr_pdev_obj->dbr_mod_param) { |
| direct_buf_rx_err("alloc dbr mod param fail"); |
| wlan_objmgr_pdev_component_obj_detach(pdev, |
| WLAN_TARGET_IF_COMP_DIRECT_BUF_RX, |
| dbr_pdev_obj); |
| qdf_mem_free(dbr_pdev_obj); |
| return QDF_STATUS_E_NOMEM; |
| } |
| |
| return QDF_STATUS_SUCCESS; |
| } |
| |
| QDF_STATUS target_if_direct_buf_rx_pdev_destroy_handler( |
| struct wlan_objmgr_pdev *pdev, void *data) |
| { |
| struct direct_buf_rx_pdev_obj *dbr_pdev_obj; |
| QDF_STATUS status; |
| uint8_t num_modules, mod_idx, srng_id; |
| |
| if (!pdev) { |
| direct_buf_rx_err("pdev context passed is null"); |
| return QDF_STATUS_E_INVAL; |
| } |
| |
| dbr_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj(pdev, |
| WLAN_TARGET_IF_COMP_DIRECT_BUF_RX); |
| |
| if (!dbr_pdev_obj) { |
| direct_buf_rx_err("dir buf rx object is null"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| num_modules = dbr_pdev_obj->num_modules; |
| for (mod_idx = 0; mod_idx < num_modules; mod_idx++) { |
| for (srng_id = 0; srng_id < DBR_SRNG_NUM; srng_id++) |
| target_if_deinit_dbr_ring(pdev, dbr_pdev_obj, |
| mod_idx, srng_id); |
| } |
| |
| qdf_mem_free(dbr_pdev_obj->dbr_mod_param); |
| dbr_pdev_obj->dbr_mod_param = NULL; |
| |
| status = wlan_objmgr_pdev_component_obj_detach(pdev, |
| WLAN_TARGET_IF_COMP_DIRECT_BUF_RX, |
| dbr_pdev_obj); |
| |
| if (status != QDF_STATUS_SUCCESS) { |
| direct_buf_rx_err("failed to detach dir buf rx component %d", |
| status); |
| } |
| |
| qdf_mem_free(dbr_pdev_obj); |
| |
| return status; |
| } |
| |
| QDF_STATUS target_if_direct_buf_rx_psoc_create_handler( |
| struct wlan_objmgr_psoc *psoc, void *data) |
| { |
| struct direct_buf_rx_psoc_obj *dbr_psoc_obj; |
| QDF_STATUS status; |
| |
| direct_buf_rx_enter(); |
| |
| if (!psoc) { |
| direct_buf_rx_err("psoc context passed is null"); |
| return QDF_STATUS_E_INVAL; |
| } |
| |
| dbr_psoc_obj = qdf_mem_malloc(sizeof(*dbr_psoc_obj)); |
| |
| if (!dbr_psoc_obj) |
| return QDF_STATUS_E_NOMEM; |
| |
| direct_buf_rx_debug("Dbr psoc obj %pK", dbr_psoc_obj); |
| |
| status = wlan_objmgr_psoc_component_obj_attach(psoc, |
| WLAN_TARGET_IF_COMP_DIRECT_BUF_RX, dbr_psoc_obj, |
| QDF_STATUS_SUCCESS); |
| |
| if (status != QDF_STATUS_SUCCESS) { |
| direct_buf_rx_err("Failed to attach dir buf rx component %d", |
| status); |
| goto attach_error; |
| } |
| |
| return status; |
| |
| attach_error: |
| qdf_mem_free(dbr_psoc_obj); |
| |
| return status; |
| } |
| |
| QDF_STATUS target_if_direct_buf_rx_psoc_destroy_handler( |
| struct wlan_objmgr_psoc *psoc, void *data) |
| { |
| QDF_STATUS status; |
| struct direct_buf_rx_psoc_obj *dbr_psoc_obj; |
| |
| direct_buf_rx_enter(); |
| |
| dbr_psoc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, |
| WLAN_TARGET_IF_COMP_DIRECT_BUF_RX); |
| |
| if (!dbr_psoc_obj) { |
| direct_buf_rx_err("dir buf rx psoc obj is null"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| status = wlan_objmgr_psoc_component_obj_detach(psoc, |
| WLAN_TARGET_IF_COMP_DIRECT_BUF_RX, |
| dbr_psoc_obj); |
| |
| if (status != QDF_STATUS_SUCCESS) { |
| direct_buf_rx_err("failed to detach dir buf rx component %d", |
| status); |
| } |
| |
| qdf_mem_free(dbr_psoc_obj); |
| |
| return status; |
| } |
| |
| static QDF_STATUS target_if_dbr_replenish_ring(struct wlan_objmgr_pdev *pdev, |
| struct direct_buf_rx_module_param *mod_param, |
| void *aligned_vaddr, uint32_t cookie) |
| { |
| uint64_t *ring_entry; |
| uint32_t dw_lo, dw_hi = 0, map_status; |
| void *hal_soc, *srng; |
| qdf_dma_addr_t paddr; |
| struct wlan_objmgr_psoc *psoc; |
| struct direct_buf_rx_psoc_obj *dbr_psoc_obj; |
| struct direct_buf_rx_ring_cfg *dbr_ring_cfg; |
| struct direct_buf_rx_ring_cap *dbr_ring_cap; |
| struct direct_buf_rx_buf_info *dbr_buf_pool; |
| |
| dbr_ring_cfg = mod_param->dbr_ring_cfg; |
| dbr_ring_cap = mod_param->dbr_ring_cap; |
| dbr_buf_pool = mod_param->dbr_buf_pool; |
| |
| psoc = wlan_pdev_get_psoc(pdev); |
| |
| if (!psoc) { |
| direct_buf_rx_err("psoc is null"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| dbr_psoc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, |
| WLAN_TARGET_IF_COMP_DIRECT_BUF_RX); |
| |
| if (!dbr_psoc_obj) { |
| direct_buf_rx_err("dir buf rx psoc object is null"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| hal_soc = dbr_psoc_obj->hal_soc; |
| srng = dbr_ring_cfg->srng; |
| if (!aligned_vaddr) { |
| direct_buf_rx_err("aligned vaddr is null"); |
| return QDF_STATUS_SUCCESS; |
| } |
| |
| map_status = qdf_mem_map_nbytes_single(dbr_psoc_obj->osdev, |
| aligned_vaddr, |
| QDF_DMA_FROM_DEVICE, |
| dbr_ring_cap->min_buf_size, |
| &paddr); |
| if (map_status) { |
| direct_buf_rx_err("mem map failed status = %d", map_status); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| QDF_ASSERT(!((uint64_t)paddr % dbr_ring_cap->min_buf_align)); |
| dbr_buf_pool[cookie].paddr = paddr; |
| |
| hal_srng_access_start(hal_soc, srng); |
| ring_entry = hal_srng_src_get_next(hal_soc, srng); |
| QDF_ASSERT(ring_entry); |
| dw_lo = (uint64_t)paddr & 0xFFFFFFFF; |
| WMI_HOST_DBR_RING_ADDR_HI_SET(dw_hi, (uint64_t)paddr >> 32); |
| WMI_HOST_DBR_DATA_ADDR_HI_HOST_DATA_SET(dw_hi, cookie); |
| *ring_entry = (uint64_t)dw_hi << 32 | dw_lo; |
| hal_srng_access_end(hal_soc, srng); |
| |
| return QDF_STATUS_SUCCESS; |
| } |
| |
| static QDF_STATUS target_if_dbr_fill_ring(struct wlan_objmgr_pdev *pdev, |
| struct direct_buf_rx_module_param *mod_param) |
| { |
| uint32_t idx; |
| struct direct_buf_rx_ring_cfg *dbr_ring_cfg; |
| struct direct_buf_rx_ring_cap *dbr_ring_cap; |
| struct direct_buf_rx_buf_info *dbr_buf_pool; |
| QDF_STATUS status; |
| |
| direct_buf_rx_enter(); |
| |
| dbr_ring_cfg = mod_param->dbr_ring_cfg; |
| dbr_ring_cap = mod_param->dbr_ring_cap; |
| dbr_buf_pool = mod_param->dbr_buf_pool; |
| |
| for (idx = 0; idx < dbr_ring_cfg->num_ptr - 1; idx++) { |
| void *buf_vaddr_unaligned = NULL, *buf_vaddr_aligned; |
| dma_addr_t buf_paddr_aligned, buf_paddr_unaligned; |
| |
| buf_vaddr_aligned = qdf_aligned_malloc( |
| &dbr_ring_cap->min_buf_size, &buf_vaddr_unaligned, |
| &buf_paddr_unaligned, &buf_paddr_aligned, |
| dbr_ring_cap->min_buf_align); |
| |
| if (!buf_vaddr_aligned) { |
| direct_buf_rx_err("dir buf rx ring alloc failed"); |
| return QDF_STATUS_E_NOMEM; |
| } |
| dbr_buf_pool[idx].vaddr = buf_vaddr_unaligned; |
| dbr_buf_pool[idx].offset = buf_vaddr_aligned - |
| buf_vaddr_unaligned; |
| dbr_buf_pool[idx].cookie = idx; |
| status = target_if_dbr_replenish_ring(pdev, mod_param, |
| buf_vaddr_aligned, idx); |
| if (QDF_IS_STATUS_ERROR(status)) { |
| direct_buf_rx_err("replenish failed with status : %d", |
| status); |
| qdf_mem_free(buf_vaddr_unaligned); |
| return QDF_STATUS_E_FAILURE; |
| } |
| } |
| |
| return QDF_STATUS_SUCCESS; |
| } |
| |
| static QDF_STATUS target_if_dbr_init_ring(struct wlan_objmgr_pdev *pdev, |
| struct direct_buf_rx_module_param *mod_param) |
| { |
| void *srng; |
| uint32_t num_entries, ring_alloc_size, max_entries, entry_size; |
| qdf_dma_addr_t paddr; |
| struct hal_srng_params ring_params = {0}; |
| struct wlan_objmgr_psoc *psoc; |
| struct direct_buf_rx_psoc_obj *dbr_psoc_obj; |
| struct direct_buf_rx_ring_cap *dbr_ring_cap; |
| struct direct_buf_rx_ring_cfg *dbr_ring_cfg; |
| QDF_STATUS status; |
| |
| direct_buf_rx_enter(); |
| |
| psoc = wlan_pdev_get_psoc(pdev); |
| |
| if (!psoc) { |
| direct_buf_rx_err("psoc is null"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| dbr_psoc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, |
| WLAN_TARGET_IF_COMP_DIRECT_BUF_RX); |
| |
| if (!dbr_psoc_obj) { |
| direct_buf_rx_err("dir buf rx psoc object is null"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| if (!dbr_psoc_obj->hal_soc || |
| !dbr_psoc_obj->osdev) { |
| direct_buf_rx_err("dir buf rx target attach failed"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| max_entries = hal_srng_max_entries(dbr_psoc_obj->hal_soc, |
| DIR_BUF_RX_DMA_SRC); |
| entry_size = hal_srng_get_entrysize(dbr_psoc_obj->hal_soc, |
| DIR_BUF_RX_DMA_SRC); |
| direct_buf_rx_debug("Max Entries = %d", max_entries); |
| direct_buf_rx_debug("Entry Size = %d", entry_size); |
| |
| status = populate_dbr_cap_mod_param(pdev, mod_param); |
| if (QDF_IS_STATUS_ERROR(status)) { |
| direct_buf_rx_err("Module cap population failed"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| dbr_ring_cap = mod_param->dbr_ring_cap; |
| dbr_ring_cfg = mod_param->dbr_ring_cfg; |
| num_entries = dbr_ring_cap->ring_elems_min > max_entries ? |
| max_entries : dbr_ring_cap->ring_elems_min; |
| direct_buf_rx_debug("Num entries = %d", num_entries); |
| dbr_ring_cfg->num_ptr = num_entries; |
| mod_param->dbr_buf_pool = qdf_mem_malloc(num_entries * sizeof( |
| struct direct_buf_rx_buf_info)); |
| if (!mod_param->dbr_buf_pool) |
| return QDF_STATUS_E_NOMEM; |
| |
| ring_alloc_size = (num_entries * entry_size) + DBR_RING_BASE_ALIGN - 1; |
| dbr_ring_cfg->ring_alloc_size = ring_alloc_size; |
| direct_buf_rx_debug("dbr_psoc_obj %pK", dbr_psoc_obj); |
| dbr_ring_cfg->base_vaddr_unaligned = qdf_mem_alloc_consistent( |
| dbr_psoc_obj->osdev, dbr_psoc_obj->osdev->dev, ring_alloc_size, |
| &paddr); |
| direct_buf_rx_debug("vaddr aligned allocated"); |
| dbr_ring_cfg->base_paddr_unaligned = paddr; |
| if (!dbr_ring_cfg->base_vaddr_unaligned) { |
| direct_buf_rx_err("dir buf rx vaddr alloc failed"); |
| qdf_mem_free(mod_param->dbr_buf_pool); |
| return QDF_STATUS_E_NOMEM; |
| } |
| |
| /* Alignment is defined to 8 for now. Will be advertised by FW */ |
| dbr_ring_cfg->base_vaddr_aligned = (void *)(uintptr_t)qdf_roundup( |
| (uint64_t)(uintptr_t)dbr_ring_cfg->base_vaddr_unaligned, |
| DBR_RING_BASE_ALIGN); |
| ring_params.ring_base_vaddr = dbr_ring_cfg->base_vaddr_aligned; |
| dbr_ring_cfg->base_paddr_aligned = qdf_roundup( |
| (uint64_t)dbr_ring_cfg->base_paddr_unaligned, |
| DBR_RING_BASE_ALIGN); |
| ring_params.ring_base_paddr = |
| (qdf_dma_addr_t)dbr_ring_cfg->base_paddr_aligned; |
| ring_params.num_entries = num_entries; |
| srng = hal_srng_setup(dbr_psoc_obj->hal_soc, DIR_BUF_RX_DMA_SRC, |
| mod_param->mod_id, |
| mod_param->pdev_id, &ring_params); |
| |
| if (!srng) { |
| direct_buf_rx_err("srng setup failed"); |
| qdf_mem_free(mod_param->dbr_buf_pool); |
| qdf_mem_free_consistent(dbr_psoc_obj->osdev, |
| dbr_psoc_obj->osdev->dev, |
| ring_alloc_size, |
| dbr_ring_cfg->base_vaddr_unaligned, |
| (qdf_dma_addr_t)dbr_ring_cfg->base_paddr_unaligned, 0); |
| return QDF_STATUS_E_FAILURE; |
| } |
| dbr_ring_cfg->srng = srng; |
| dbr_ring_cfg->tail_idx_addr = |
| hal_srng_get_tp_addr(dbr_psoc_obj->hal_soc, srng); |
| dbr_ring_cfg->head_idx_addr = |
| hal_srng_get_hp_addr(dbr_psoc_obj->hal_soc, srng); |
| dbr_ring_cfg->buf_size = dbr_ring_cap->min_buf_size; |
| |
| return target_if_dbr_fill_ring(pdev, mod_param); |
| } |
| |
| static QDF_STATUS target_if_dbr_init_srng(struct wlan_objmgr_pdev *pdev, |
| struct direct_buf_rx_module_param *mod_param) |
| { |
| QDF_STATUS status; |
| |
| direct_buf_rx_debug("Init DBR srng"); |
| |
| if (!mod_param) { |
| direct_buf_rx_err("dir buf rx module param is null"); |
| return QDF_STATUS_E_INVAL; |
| } |
| |
| mod_param->dbr_ring_cap = qdf_mem_malloc(sizeof( |
| struct direct_buf_rx_ring_cap)); |
| |
| if (!mod_param->dbr_ring_cap) |
| return QDF_STATUS_E_NOMEM; |
| |
| /* Allocate memory for DBR Ring Config */ |
| mod_param->dbr_ring_cfg = qdf_mem_malloc(sizeof( |
| struct direct_buf_rx_ring_cfg)); |
| |
| if (!mod_param->dbr_ring_cfg) { |
| qdf_mem_free(mod_param->dbr_ring_cap); |
| return QDF_STATUS_E_NOMEM; |
| } |
| |
| status = target_if_dbr_init_ring(pdev, mod_param); |
| |
| if (QDF_IS_STATUS_ERROR(status)) { |
| direct_buf_rx_err("DBR ring init failed"); |
| qdf_mem_free(mod_param->dbr_ring_cfg); |
| qdf_mem_free(mod_param->dbr_ring_cap); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| return QDF_STATUS_SUCCESS; |
| } |
| |
| static QDF_STATUS target_if_dbr_cfg_tgt(struct wlan_objmgr_pdev *pdev, |
| struct direct_buf_rx_module_param *mod_param) |
| { |
| QDF_STATUS status; |
| struct wlan_objmgr_psoc *psoc; |
| void *wmi_hdl; |
| struct direct_buf_rx_cfg_req dbr_cfg_req = {0}; |
| struct direct_buf_rx_ring_cfg *dbr_ring_cfg; |
| struct direct_buf_rx_ring_cap *dbr_ring_cap; |
| struct dbr_module_config *dbr_config; |
| |
| direct_buf_rx_enter(); |
| |
| psoc = wlan_pdev_get_psoc(pdev); |
| if (!psoc) { |
| direct_buf_rx_err("psoc is null"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| dbr_ring_cfg = mod_param->dbr_ring_cfg; |
| dbr_ring_cap = mod_param->dbr_ring_cap; |
| dbr_config = &mod_param->dbr_config; |
| wmi_hdl = get_wmi_unified_hdl_from_psoc(psoc); |
| if (!wmi_hdl) { |
| direct_buf_rx_err("WMI handle null. Can't send WMI CMD"); |
| return QDF_STATUS_E_INVAL; |
| } |
| |
| direct_buf_rx_debug("Sending DBR Ring CFG to target"); |
| dbr_cfg_req.pdev_id = mod_param->pdev_id; |
| /* Module ID numbering starts from 1 in FW. need to fix it */ |
| dbr_cfg_req.mod_id = mod_param->mod_id; |
| dbr_cfg_req.base_paddr_lo = (uint64_t)dbr_ring_cfg->base_paddr_aligned |
| & 0xFFFFFFFF; |
| dbr_cfg_req.base_paddr_hi = (uint64_t)dbr_ring_cfg->base_paddr_aligned |
| & 0xFFFFFFFF00000000; |
| dbr_cfg_req.head_idx_paddr_lo = (uint64_t)dbr_ring_cfg->head_idx_addr |
| & 0xFFFFFFFF; |
| dbr_cfg_req.head_idx_paddr_hi = (uint64_t)dbr_ring_cfg->head_idx_addr |
| & 0xFFFFFFFF00000000; |
| dbr_cfg_req.tail_idx_paddr_lo = (uint64_t)dbr_ring_cfg->tail_idx_addr |
| & 0xFFFFFFFF; |
| dbr_cfg_req.tail_idx_paddr_hi = (uint64_t)dbr_ring_cfg->tail_idx_addr |
| & 0xFFFFFFFF00000000; |
| dbr_cfg_req.num_elems = dbr_ring_cap->ring_elems_min; |
| dbr_cfg_req.buf_size = dbr_ring_cap->min_buf_size; |
| dbr_cfg_req.num_resp_per_event = dbr_config->num_resp_per_event; |
| dbr_cfg_req.event_timeout_ms = dbr_config->event_timeout_in_ms; |
| direct_buf_rx_debug("pdev id %d mod id %d base addr lo %x\n" |
| "base addr hi %x head idx addr lo %x\n" |
| "head idx addr hi %x tail idx addr lo %x\n" |
| "tail idx addr hi %x num ptr %d\n" |
| "num resp %d event timeout %d\n", |
| dbr_cfg_req.pdev_id, dbr_cfg_req.mod_id, |
| dbr_cfg_req.base_paddr_lo, |
| dbr_cfg_req.base_paddr_hi, |
| dbr_cfg_req.head_idx_paddr_lo, |
| dbr_cfg_req.head_idx_paddr_hi, |
| dbr_cfg_req.tail_idx_paddr_lo, |
| dbr_cfg_req.tail_idx_paddr_hi, |
| dbr_cfg_req.num_elems, |
| dbr_cfg_req.num_resp_per_event, |
| dbr_cfg_req.event_timeout_ms); |
| status = wmi_unified_dbr_ring_cfg(wmi_hdl, &dbr_cfg_req); |
| |
| return status; |
| } |
| |
| static QDF_STATUS target_if_init_dbr_ring(struct wlan_objmgr_pdev *pdev, |
| struct direct_buf_rx_pdev_obj *dbr_pdev_obj, |
| enum DBR_MODULE mod_id, uint8_t srng_id) |
| { |
| QDF_STATUS status = QDF_STATUS_SUCCESS; |
| struct direct_buf_rx_module_param *mod_param; |
| |
| direct_buf_rx_debug("Init DBR ring for module %d, srng %d", |
| mod_id, srng_id); |
| |
| if (!dbr_pdev_obj) { |
| direct_buf_rx_err("dir buf rx object is null"); |
| return QDF_STATUS_E_INVAL; |
| } |
| |
| mod_param = &(dbr_pdev_obj->dbr_mod_param[mod_id][srng_id]); |
| |
| if (!mod_param) { |
| direct_buf_rx_err("dir buf rx module param is null"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| direct_buf_rx_debug("mod_param %pK", mod_param); |
| |
| mod_param->mod_id = mod_id; |
| mod_param->pdev_id = dbr_get_pdev_id( |
| srng_id, wlan_objmgr_pdev_get_pdev_id(pdev)); |
| |
| /* Initialize DMA ring now */ |
| status = target_if_dbr_init_srng(pdev, mod_param); |
| if (QDF_IS_STATUS_ERROR(status)) { |
| direct_buf_rx_err("DBR ring init failed %d", status); |
| return status; |
| } |
| |
| /* Send CFG request command to firmware */ |
| status = target_if_dbr_cfg_tgt(pdev, mod_param); |
| if (QDF_IS_STATUS_ERROR(status)) { |
| direct_buf_rx_err("DBR config to target failed %d", status); |
| goto dbr_srng_init_failed; |
| } |
| |
| return QDF_STATUS_SUCCESS; |
| |
| dbr_srng_init_failed: |
| target_if_deinit_dbr_ring(pdev, dbr_pdev_obj, mod_id, srng_id); |
| return status; |
| } |
| |
| QDF_STATUS target_if_direct_buf_rx_module_register( |
| struct wlan_objmgr_pdev *pdev, uint8_t mod_id, |
| struct dbr_module_config *dbr_config, |
| bool (*dbr_rsp_handler) |
| (struct wlan_objmgr_pdev *pdev, |
| struct direct_buf_rx_data *dbr_data)) |
| { |
| QDF_STATUS status; |
| struct direct_buf_rx_pdev_obj *dbr_pdev_obj; |
| struct dbr_module_config *config = NULL; |
| struct direct_buf_rx_module_param *mod_param; |
| uint8_t srng_id; |
| |
| if (!pdev) { |
| direct_buf_rx_err("pdev context passed is null"); |
| return QDF_STATUS_E_INVAL; |
| } |
| |
| if (!dbr_rsp_handler) { |
| direct_buf_rx_err("Response handler is null"); |
| return QDF_STATUS_E_INVAL; |
| } |
| |
| if (mod_id >= DBR_MODULE_MAX) { |
| direct_buf_rx_err("Invalid module id"); |
| return QDF_STATUS_E_INVAL; |
| } |
| |
| dbr_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj(pdev, |
| WLAN_TARGET_IF_COMP_DIRECT_BUF_RX); |
| |
| if (!dbr_pdev_obj) { |
| direct_buf_rx_err("dir buf rx object is null"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| direct_buf_rx_debug("Dbr pdev obj %pK", dbr_pdev_obj); |
| |
| if (!dbr_pdev_obj->dbr_mod_param) { |
| direct_buf_rx_err("dbr_pdev_obj->dbr_mod_param is NULL"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| if (mod_id >= dbr_pdev_obj->num_modules) { |
| direct_buf_rx_err("Module %d not supported in target", mod_id); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| for (srng_id = 0; srng_id < DBR_SRNG_NUM; srng_id++) { |
| mod_param = &dbr_pdev_obj->dbr_mod_param[mod_id][srng_id]; |
| config = &mod_param->dbr_config; |
| mod_param->dbr_rsp_handler = dbr_rsp_handler; |
| *config = *dbr_config; |
| |
| status = target_if_init_dbr_ring(pdev, dbr_pdev_obj, |
| (enum DBR_MODULE)mod_id, |
| srng_id); |
| if (QDF_IS_STATUS_ERROR(status)) |
| direct_buf_rx_err("init dbr ring fail, srng_id %d, status %d", |
| srng_id, status); |
| } |
| |
| return status; |
| } |
| |
| QDF_STATUS target_if_direct_buf_rx_module_unregister( |
| struct wlan_objmgr_pdev *pdev, uint8_t mod_id) |
| { |
| QDF_STATUS status; |
| struct direct_buf_rx_pdev_obj *dbr_pdev_obj; |
| uint8_t srng_id; |
| |
| if (!pdev) { |
| direct_buf_rx_err("pdev context passed is null"); |
| return QDF_STATUS_E_INVAL; |
| } |
| |
| if (mod_id >= DBR_MODULE_MAX) { |
| direct_buf_rx_err("Invalid module id"); |
| return QDF_STATUS_E_INVAL; |
| } |
| |
| dbr_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj |
| (pdev, |
| WLAN_TARGET_IF_COMP_DIRECT_BUF_RX); |
| |
| if (!dbr_pdev_obj) { |
| direct_buf_rx_err("dir buf rx object is null"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| direct_buf_rx_debug("Dbr pdev obj %pK", dbr_pdev_obj); |
| |
| if (!dbr_pdev_obj->dbr_mod_param) { |
| direct_buf_rx_err("dbr_pdev_obj->dbr_mod_param is NULL"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| if (mod_id >= dbr_pdev_obj->num_modules) { |
| direct_buf_rx_err("Module %d not supported in target", mod_id); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| for (srng_id = 0; srng_id < DBR_SRNG_NUM; srng_id++) { |
| status = target_if_deinit_dbr_ring(pdev, dbr_pdev_obj, |
| mod_id, srng_id); |
| direct_buf_rx_info("status %d", status); |
| } |
| |
| return status; |
| } |
| |
| static void *target_if_dbr_vaddr_lookup( |
| struct direct_buf_rx_module_param *mod_param, |
| qdf_dma_addr_t paddr, uint32_t cookie) |
| { |
| struct direct_buf_rx_buf_info *dbr_buf_pool; |
| |
| dbr_buf_pool = mod_param->dbr_buf_pool; |
| |
| if (dbr_buf_pool[cookie].paddr == paddr) { |
| return dbr_buf_pool[cookie].vaddr + |
| dbr_buf_pool[cookie].offset; |
| } |
| |
| direct_buf_rx_debug("Incorrect paddr found on cookie slot"); |
| return NULL; |
| } |
| |
| QDF_STATUS target_if_dbr_cookie_lookup(struct wlan_objmgr_pdev *pdev, |
| uint8_t mod_id, qdf_dma_addr_t paddr, |
| uint32_t *cookie, uint8_t srng_id) |
| { |
| struct direct_buf_rx_buf_info *dbr_buf_pool; |
| struct direct_buf_rx_ring_cfg *dbr_ring_cfg; |
| struct direct_buf_rx_pdev_obj *dbr_pdev_obj; |
| struct direct_buf_rx_module_param *mod_param; |
| enum wlan_umac_comp_id dbr_comp_id = WLAN_TARGET_IF_COMP_DIRECT_BUF_RX; |
| uint32_t idx; |
| |
| dbr_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj(pdev, dbr_comp_id); |
| if (!dbr_pdev_obj) { |
| direct_buf_rx_err("dir buf rx object is null"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| mod_param = &dbr_pdev_obj->dbr_mod_param[mod_id][srng_id]; |
| if (!mod_param) { |
| direct_buf_rx_err("dir buf rx module param is null"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| dbr_ring_cfg = mod_param->dbr_ring_cfg; |
| dbr_buf_pool = mod_param->dbr_buf_pool; |
| |
| for (idx = 0; idx < dbr_ring_cfg->num_ptr - 1; idx++) { |
| if (dbr_buf_pool[idx].paddr && |
| dbr_buf_pool[idx].paddr == paddr) { |
| *cookie = idx; |
| return QDF_STATUS_SUCCESS; |
| } |
| } |
| |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| QDF_STATUS target_if_dbr_buf_release(struct wlan_objmgr_pdev *pdev, |
| uint8_t mod_id, qdf_dma_addr_t paddr, |
| uint32_t cookie, uint8_t srng_id) |
| { |
| struct direct_buf_rx_module_param *mod_param; |
| struct direct_buf_rx_pdev_obj *dbr_pdev_obj; |
| enum wlan_umac_comp_id dbr_comp_id = WLAN_TARGET_IF_COMP_DIRECT_BUF_RX; |
| void *vaddr; |
| QDF_STATUS status; |
| |
| dbr_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj(pdev, dbr_comp_id); |
| if (!dbr_pdev_obj) { |
| direct_buf_rx_err("dir buf rx object is null"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| mod_param = &dbr_pdev_obj->dbr_mod_param[mod_id][srng_id]; |
| if (!mod_param) { |
| direct_buf_rx_err("dir buf rx module param is null"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| vaddr = target_if_dbr_vaddr_lookup(mod_param, paddr, cookie); |
| if (!vaddr) |
| return QDF_STATUS_E_FAILURE; |
| |
| status = target_if_dbr_replenish_ring(pdev, mod_param, |
| vaddr, cookie); |
| if (QDF_IS_STATUS_ERROR(status)) { |
| direct_buf_rx_err("Ring replenish failed"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| return QDF_STATUS_SUCCESS; |
| } |
| |
| static QDF_STATUS target_if_get_dbr_data(struct wlan_objmgr_pdev *pdev, |
| struct direct_buf_rx_module_param *mod_param, |
| struct direct_buf_rx_rsp *dbr_rsp, |
| struct direct_buf_rx_data *dbr_data, |
| uint8_t idx, uint32_t *cookie) |
| { |
| qdf_dma_addr_t paddr = 0; |
| uint32_t addr_hi; |
| struct direct_buf_rx_psoc_obj *dbr_psoc_obj; |
| struct direct_buf_rx_ring_cap *dbr_ring_cap; |
| struct wlan_objmgr_psoc *psoc; |
| |
| psoc = wlan_pdev_get_psoc(pdev); |
| if (!psoc) { |
| direct_buf_rx_err("psoc is null"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| dbr_psoc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, |
| WLAN_TARGET_IF_COMP_DIRECT_BUF_RX); |
| |
| if (!dbr_psoc_obj) { |
| direct_buf_rx_err("dir buf rx psoc object is null"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| dbr_ring_cap = mod_param->dbr_ring_cap; |
| addr_hi = (uint64_t)WMI_HOST_DBR_DATA_ADDR_HI_GET( |
| dbr_rsp->dbr_entries[idx].paddr_hi); |
| paddr = (qdf_dma_addr_t)((uint64_t)addr_hi << 32 | |
| dbr_rsp->dbr_entries[idx].paddr_lo); |
| *cookie = WMI_HOST_DBR_DATA_ADDR_HI_HOST_DATA_GET( |
| dbr_rsp->dbr_entries[idx].paddr_hi); |
| dbr_data->vaddr = target_if_dbr_vaddr_lookup(mod_param, paddr, *cookie); |
| dbr_data->cookie = *cookie; |
| dbr_data->paddr = paddr; |
| direct_buf_rx_debug("Cookie = %d Vaddr look up = %pK", |
| dbr_data->cookie, dbr_data->vaddr); |
| dbr_data->dbr_len = dbr_rsp->dbr_entries[idx].len; |
| qdf_mem_unmap_nbytes_single(dbr_psoc_obj->osdev, (qdf_dma_addr_t)paddr, |
| QDF_DMA_FROM_DEVICE, |
| dbr_ring_cap->min_buf_size); |
| |
| return QDF_STATUS_SUCCESS; |
| } |
| |
| #ifdef DBR_MULTI_SRNG_ENABLE |
| /** |
| * dbr_get_pdev_and_srng_id() - get pdev object and srng id |
| * |
| * @psoc: pointer to psoc object |
| * @pdev_id: pdev id from wmi_pdev_dma_ring_buf_release eventid |
| * @srng_id: pointer to return srng id |
| * |
| * Return : pointer to pdev |
| */ |
| static struct wlan_objmgr_pdev * |
| dbr_get_pdev_and_srng_id(struct wlan_objmgr_psoc *psoc, uint8_t pdev_id, |
| uint8_t *srng_id) |
| { |
| struct wlan_objmgr_pdev *pdev; |
| wlan_objmgr_ref_dbgid dbr_mod_id = WLAN_DIRECT_BUF_RX_ID; |
| |
| pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, dbr_mod_id); |
| if (!pdev) { |
| pdev = wlan_objmgr_get_pdev_by_id(psoc, TGT_WMI_PDEV_ID_SOC, |
| dbr_mod_id); |
| if (pdev) { |
| direct_buf_rx_debug("update srng id from %d to %d", |
| *srng_id, pdev_id); |
| *srng_id = pdev_id; |
| } |
| } |
| |
| return pdev; |
| } |
| #else |
| static struct wlan_objmgr_pdev * |
| dbr_get_pdev_and_srng_id(struct wlan_objmgr_psoc *psoc, uint8_t pdev_id, |
| uint8_t *srng_id) |
| { |
| struct wlan_objmgr_pdev *pdev; |
| wlan_objmgr_ref_dbgid dbr_mod_id = WLAN_DIRECT_BUF_RX_ID; |
| |
| pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, dbr_mod_id); |
| |
| return pdev; |
| } |
| #endif |
| |
| static int target_if_direct_buf_rx_rsp_event_handler(ol_scn_t scn, |
| uint8_t *data_buf, |
| uint32_t data_len) |
| { |
| int ret = 0; |
| uint8_t i = 0; |
| QDF_STATUS status; |
| uint32_t cookie = 0; |
| struct direct_buf_rx_rsp dbr_rsp = {0}; |
| struct direct_buf_rx_data dbr_data = {0}; |
| struct wlan_objmgr_psoc *psoc; |
| struct wlan_objmgr_pdev *pdev; |
| struct direct_buf_rx_buf_info *dbr_buf_pool; |
| struct direct_buf_rx_pdev_obj *dbr_pdev_obj; |
| struct direct_buf_rx_module_param *mod_param; |
| struct common_wmi_handle *wmi_handle; |
| wlan_objmgr_ref_dbgid dbr_mod_id = WLAN_DIRECT_BUF_RX_ID; |
| uint8_t srng_id = 0; |
| |
| direct_buf_rx_enter(); |
| |
| psoc = target_if_get_psoc_from_scn_hdl(scn); |
| if (!psoc) { |
| direct_buf_rx_err("psoc is null"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc); |
| if (!wmi_handle) { |
| direct_buf_rx_err("WMI handle is null"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| if (wmi_extract_dbr_buf_release_fixed( |
| wmi_handle, data_buf, &dbr_rsp) != QDF_STATUS_SUCCESS) { |
| direct_buf_rx_err("unable to extract DBR rsp fixed param"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| direct_buf_rx_debug("Num buf release entry = %d", |
| dbr_rsp.num_buf_release_entry); |
| |
| pdev = dbr_get_pdev_and_srng_id(psoc, (uint8_t)dbr_rsp.pdev_id, |
| &srng_id); |
| if (!pdev || (srng_id >= DBR_SRNG_NUM)) { |
| direct_buf_rx_err("invalid pdev or srng, pdev %pK, srng %d", |
| pdev, srng_id); |
| return QDF_STATUS_E_INVAL; |
| } |
| |
| dbr_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj(pdev, |
| WLAN_TARGET_IF_COMP_DIRECT_BUF_RX); |
| |
| if (!dbr_pdev_obj) { |
| direct_buf_rx_err("dir buf rx object is null"); |
| wlan_objmgr_pdev_release_ref(pdev, dbr_mod_id); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| if (dbr_rsp.mod_id >= dbr_pdev_obj->num_modules) { |
| direct_buf_rx_err("Invalid module id:%d", dbr_rsp.mod_id); |
| wlan_objmgr_pdev_release_ref(pdev, dbr_mod_id); |
| return QDF_STATUS_E_FAILURE; |
| } |
| mod_param = &(dbr_pdev_obj->dbr_mod_param[dbr_rsp.mod_id][srng_id]); |
| |
| if (!mod_param) { |
| direct_buf_rx_err("dir buf rx module param is null"); |
| wlan_objmgr_pdev_release_ref(pdev, dbr_mod_id); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| dbr_buf_pool = mod_param->dbr_buf_pool; |
| dbr_rsp.dbr_entries = qdf_mem_malloc(dbr_rsp.num_buf_release_entry * |
| sizeof(struct direct_buf_rx_entry)); |
| if (!dbr_rsp.dbr_entries) { |
| direct_buf_rx_err("invalid dbr_entries"); |
| wlan_objmgr_pdev_release_ref(pdev, dbr_mod_id); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| if (dbr_rsp.num_meta_data_entry > dbr_rsp.num_buf_release_entry) { |
| direct_buf_rx_err("More than expected number of metadata"); |
| wlan_objmgr_pdev_release_ref(pdev, dbr_mod_id); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| for (i = 0; i < dbr_rsp.num_buf_release_entry; i++) { |
| if (wmi_extract_dbr_buf_release_entry( |
| wmi_handle, data_buf, i, |
| &dbr_rsp.dbr_entries[i]) != QDF_STATUS_SUCCESS) { |
| direct_buf_rx_err("Unable to extract DBR buf entry %d", |
| i+1); |
| qdf_mem_free(dbr_rsp.dbr_entries); |
| wlan_objmgr_pdev_release_ref(pdev, dbr_mod_id); |
| return QDF_STATUS_E_FAILURE; |
| } |
| status = target_if_get_dbr_data(pdev, mod_param, &dbr_rsp, |
| &dbr_data, i, &cookie); |
| |
| if (QDF_IS_STATUS_ERROR(status)) { |
| direct_buf_rx_err("DBR data get failed"); |
| qdf_mem_free(dbr_rsp.dbr_entries); |
| wlan_objmgr_pdev_release_ref(pdev, dbr_mod_id); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| dbr_data.meta_data_valid = false; |
| if (i < dbr_rsp.num_meta_data_entry) { |
| if (wmi_extract_dbr_buf_metadata( |
| wmi_handle, data_buf, i, |
| &dbr_data.meta_data) == QDF_STATUS_SUCCESS) |
| dbr_data.meta_data_valid = true; |
| } |
| if (mod_param->dbr_rsp_handler(pdev, &dbr_data)) { |
| status = target_if_dbr_replenish_ring(pdev, mod_param, |
| dbr_data.vaddr, |
| cookie); |
| if (QDF_IS_STATUS_ERROR(status)) { |
| direct_buf_rx_err("Ring replenish failed"); |
| qdf_mem_free(dbr_rsp.dbr_entries); |
| wlan_objmgr_pdev_release_ref(pdev, dbr_mod_id); |
| return QDF_STATUS_E_FAILURE; |
| } |
| } |
| } |
| |
| qdf_mem_free(dbr_rsp.dbr_entries); |
| wlan_objmgr_pdev_release_ref(pdev, dbr_mod_id); |
| |
| return ret; |
| } |
| |
| static QDF_STATUS target_if_dbr_empty_ring(struct wlan_objmgr_pdev *pdev, |
| struct direct_buf_rx_psoc_obj *dbr_psoc_obj, |
| struct direct_buf_rx_module_param *mod_param) |
| { |
| uint32_t idx; |
| struct direct_buf_rx_ring_cfg *dbr_ring_cfg; |
| struct direct_buf_rx_ring_cap *dbr_ring_cap; |
| struct direct_buf_rx_buf_info *dbr_buf_pool; |
| |
| direct_buf_rx_enter(); |
| dbr_ring_cfg = mod_param->dbr_ring_cfg; |
| dbr_ring_cap = mod_param->dbr_ring_cap; |
| dbr_buf_pool = mod_param->dbr_buf_pool; |
| |
| direct_buf_rx_debug("dbr_ring_cfg %pK, ring_cap %pK buf_pool %pK", |
| dbr_ring_cfg, dbr_ring_cap, dbr_buf_pool); |
| |
| for (idx = 0; idx < dbr_ring_cfg->num_ptr - 1; idx++) { |
| qdf_mem_unmap_nbytes_single(dbr_psoc_obj->osdev, |
| (qdf_dma_addr_t)dbr_buf_pool[idx].paddr, |
| QDF_DMA_FROM_DEVICE, |
| dbr_ring_cap->min_buf_size); |
| qdf_mem_free(dbr_buf_pool[idx].vaddr); |
| } |
| |
| return QDF_STATUS_SUCCESS; |
| } |
| |
| static QDF_STATUS target_if_dbr_deinit_ring(struct wlan_objmgr_pdev *pdev, |
| struct direct_buf_rx_module_param *mod_param) |
| { |
| struct wlan_objmgr_psoc *psoc; |
| struct direct_buf_rx_psoc_obj *dbr_psoc_obj; |
| struct direct_buf_rx_ring_cfg *dbr_ring_cfg; |
| |
| direct_buf_rx_enter(); |
| psoc = wlan_pdev_get_psoc(pdev); |
| if (!psoc) { |
| direct_buf_rx_err("psoc is null"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| dbr_psoc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, |
| WLAN_TARGET_IF_COMP_DIRECT_BUF_RX); |
| |
| if (!dbr_psoc_obj) { |
| direct_buf_rx_err("dir buf rx psoc object is null"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| direct_buf_rx_debug("dbr_psoc_obj %pK", dbr_psoc_obj); |
| |
| dbr_ring_cfg = mod_param->dbr_ring_cfg; |
| if (dbr_ring_cfg) { |
| target_if_dbr_empty_ring(pdev, dbr_psoc_obj, mod_param); |
| hal_srng_cleanup(dbr_psoc_obj->hal_soc, dbr_ring_cfg->srng); |
| qdf_mem_free_consistent(dbr_psoc_obj->osdev, |
| dbr_psoc_obj->osdev->dev, |
| dbr_ring_cfg->ring_alloc_size, |
| dbr_ring_cfg->base_vaddr_unaligned, |
| (qdf_dma_addr_t)dbr_ring_cfg->base_paddr_unaligned, 0); |
| } |
| |
| return QDF_STATUS_SUCCESS; |
| } |
| |
| static QDF_STATUS target_if_dbr_deinit_srng( |
| struct wlan_objmgr_pdev *pdev, |
| struct direct_buf_rx_module_param *mod_param) |
| { |
| struct direct_buf_rx_buf_info *dbr_buf_pool; |
| |
| direct_buf_rx_enter(); |
| dbr_buf_pool = mod_param->dbr_buf_pool; |
| direct_buf_rx_debug("dbr buf pool %pK", dbr_buf_pool); |
| target_if_dbr_deinit_ring(pdev, mod_param); |
| if (mod_param->dbr_buf_pool) |
| qdf_mem_free(dbr_buf_pool); |
| mod_param->dbr_buf_pool = NULL; |
| |
| return QDF_STATUS_SUCCESS; |
| } |
| |
| QDF_STATUS target_if_deinit_dbr_ring(struct wlan_objmgr_pdev *pdev, |
| struct direct_buf_rx_pdev_obj *dbr_pdev_obj, |
| enum DBR_MODULE mod_id, uint8_t srng_id) |
| { |
| struct direct_buf_rx_module_param *mod_param; |
| |
| direct_buf_rx_enter(); |
| mod_param = &(dbr_pdev_obj->dbr_mod_param[mod_id][srng_id]); |
| |
| if (!mod_param) { |
| direct_buf_rx_err("dir buf rx module param is null"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| direct_buf_rx_debug("mod_param %pK, dbr_ring_cap %pK", |
| mod_param, mod_param->dbr_ring_cap); |
| target_if_dbr_deinit_srng(pdev, mod_param); |
| if (mod_param->dbr_ring_cap) |
| qdf_mem_free(mod_param->dbr_ring_cap); |
| mod_param->dbr_ring_cap = NULL; |
| if (mod_param->dbr_ring_cfg) |
| qdf_mem_free(mod_param->dbr_ring_cfg); |
| mod_param->dbr_ring_cfg = NULL; |
| |
| return QDF_STATUS_SUCCESS; |
| } |
| |
| QDF_STATUS target_if_direct_buf_rx_register_events( |
| struct wlan_objmgr_psoc *psoc) |
| { |
| int ret; |
| |
| if (!psoc || !GET_WMI_HDL_FROM_PSOC(psoc)) { |
| direct_buf_rx_err("psoc or psoc->tgt_if_handle is null"); |
| return QDF_STATUS_E_INVAL; |
| } |
| |
| ret = wmi_unified_register_event_handler( |
| get_wmi_unified_hdl_from_psoc(psoc), |
| wmi_dma_buf_release_event_id, |
| target_if_direct_buf_rx_rsp_event_handler, |
| WMI_RX_UMAC_CTX); |
| |
| if (ret) |
| direct_buf_rx_debug("event handler not supported, ret=%d", ret); |
| |
| return QDF_STATUS_SUCCESS; |
| } |
| |
| QDF_STATUS target_if_direct_buf_rx_unregister_events( |
| struct wlan_objmgr_psoc *psoc) |
| { |
| if (!psoc || !GET_WMI_HDL_FROM_PSOC(psoc)) { |
| direct_buf_rx_err("psoc or psoc->tgt_if_handle is null"); |
| return QDF_STATUS_E_INVAL; |
| } |
| |
| wmi_unified_unregister_event_handler( |
| get_wmi_unified_hdl_from_psoc(psoc), |
| wmi_dma_buf_release_event_id); |
| |
| return QDF_STATUS_SUCCESS; |
| } |
| |
| QDF_STATUS target_if_direct_buf_rx_print_ring_stat( |
| struct wlan_objmgr_pdev *pdev) |
| { |
| struct direct_buf_rx_psoc_obj *dbr_psoc_obj; |
| struct direct_buf_rx_pdev_obj *dbr_pdev_obj; |
| struct wlan_objmgr_psoc *psoc; |
| void *srng, *hal_soc; |
| uint32_t hp = 0, tp = 0; |
| struct direct_buf_rx_module_param *mod_param; |
| struct direct_buf_rx_ring_cfg *dbr_ring_cfg; |
| uint8_t num_modules, mod_idx; |
| uint8_t srng_id; |
| |
| if (!pdev) { |
| direct_buf_rx_err("pdev is null"); |
| return QDF_STATUS_E_INVAL; |
| } |
| |
| psoc = wlan_pdev_get_psoc(pdev); |
| dbr_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj(pdev, |
| WLAN_TARGET_IF_COMP_DIRECT_BUF_RX); |
| dbr_psoc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, |
| WLAN_TARGET_IF_COMP_DIRECT_BUF_RX); |
| hal_soc = dbr_psoc_obj->hal_soc; |
| num_modules = dbr_pdev_obj->num_modules; |
| direct_buf_rx_debug("--------------------------------------------------"); |
| direct_buf_rx_debug("| Module ID | Module | Head Idx | Tail Idx |"); |
| direct_buf_rx_debug("--------------------------------------------------"); |
| for (mod_idx = 0; mod_idx < num_modules; mod_idx++) { |
| for (srng_id = 0; srng_id < DBR_SRNG_NUM; srng_id++) { |
| mod_param = |
| &dbr_pdev_obj->dbr_mod_param[mod_idx][srng_id]; |
| dbr_ring_cfg = mod_param->dbr_ring_cfg; |
| srng = dbr_ring_cfg->srng; |
| hal_get_sw_hptp(hal_soc, srng, &tp, &hp); |
| direct_buf_rx_debug("|%11d|%14s|%10x|%10x|", |
| mod_idx, g_dbr_module_name[mod_idx]. |
| module_name_str, |
| hp, tp); |
| } |
| } |
| direct_buf_rx_debug("--------------------------------------------------"); |
| |
| return QDF_STATUS_SUCCESS; |
| } |
| |
| QDF_STATUS |
| target_if_direct_buf_rx_get_ring_params(struct wlan_objmgr_pdev *pdev, |
| struct module_ring_params *param, |
| uint8_t mod_id, uint8_t srng_id) |
| { |
| struct direct_buf_rx_pdev_obj *dbr_pdev_obj; |
| struct direct_buf_rx_module_param *dbr_mod_param; |
| |
| if (!pdev) { |
| direct_buf_rx_err("pdev context passed is null"); |
| return QDF_STATUS_E_INVAL; |
| } |
| |
| dbr_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj |
| (pdev, WLAN_TARGET_IF_COMP_DIRECT_BUF_RX); |
| |
| if (!dbr_pdev_obj) { |
| direct_buf_rx_err("dir buf rx object is null"); |
| return QDF_STATUS_E_FAILURE; |
| } |
| |
| if ((mod_id >= DBR_MODULE_MAX) || (srng_id >= DBR_SRNG_NUM)) { |
| direct_buf_rx_err("invalid params, mod id %d, srng id %d", |
| mod_id, srng_id); |
| return QDF_STATUS_E_INVAL; |
| } |
| |
| dbr_mod_param = &dbr_pdev_obj->dbr_mod_param[mod_id][srng_id]; |
| param->num_bufs = dbr_mod_param->dbr_ring_cfg->num_ptr; |
| param->buf_size = dbr_mod_param->dbr_ring_cfg->buf_size; |
| |
| return QDF_STATUS_SUCCESS; |
| } |