summaryrefslogtreecommitdiff
path: root/target_if
diff options
context:
space:
mode:
authorSathish Kumar <ksathis@codeaurora.org>2017-12-19 00:13:03 +0530
committersnandini <snandini@codeaurora.org>2017-12-21 15:26:13 -0800
commitc34484f2a214591e8895d15a6524d81faeae8fa7 (patch)
tree0fe3551f5113b0c0e19d5d123bfdbfd208062486 /target_if
parent26190a142e6e98af1273c22c5e0f1bb0b063e2e3 (diff)
downloadqca-wfi-host-cmn-c34484f2a214591e8895d15a6524d81faeae8fa7.tar.gz
qcacmn: Direct Buffer Rx framework to facilitate DMA between tgt & host
Direct Buffer Receive provides the driver with a mechanism by which target can transfer information directly into host memory via DMA. In the Direct DMA mechanism, target will transfer information directly into host memory via DMA. Host will allocate DMA target buffers and place their addresses in one or more rings (circular buffers) to be read by the target. Host will determine the features that will be utilizing the Direct DMA service through the service bitmap obtained from the target through service available event. Host will also determine the Direct DMA capabilities such as the minimum number of pointers, minimum buffer size and minimum alignment for the DMA buffers through a separate TLV part of the extended service ready event. Host with the help of service and the DMA capabilities received, will initialize and configure the ring of DMA buffers to be shared with the target. Once the rings are initialized, host will send a WMI command to inform the target of their locations. Target responds to the host with an acknowledgment event for the shared configuration. When the host requests for the data captured, target will read the destination addresses from the rings configured and use the addresses to perform DMA transfer. When a single or multiple DMA transfers are complete, target will notify the host via a WMI event. This WMI event will include information on the number of DMA transfers completed, and the associated addresses of the buffer that was used to transfer the data. When the host has finished processing the contents of the DMA buffer, it will replenish the ring and place the buffer back on the appropriate ring to make it re-usable. Change-Id: I7542036636e62701839ef36beafb463909001853 CRs-Fixed: 2127045
Diffstat (limited to 'target_if')
-rw-r--r--target_if/direct_buf_rx/inc/target_if_direct_buf_rx_api.h96
-rw-r--r--target_if/direct_buf_rx/src/target_if_direct_buf_rx_api.c155
-rw-r--r--target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.c972
-rw-r--r--target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.h225
4 files changed, 1448 insertions, 0 deletions
diff --git a/target_if/direct_buf_rx/inc/target_if_direct_buf_rx_api.h b/target_if/direct_buf_rx/inc/target_if_direct_buf_rx_api.h
new file mode 100644
index 000000000..412a98d6b
--- /dev/null
+++ b/target_if/direct_buf_rx/inc/target_if_direct_buf_rx_api.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2017 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.
+ */
+
+#ifndef _TARGET_IF_DIRECT_BUF_RX_API_H_
+#define _TARGET_IF_DIRECT_BUF_RX_API_H_
+
+#include "qdf_nbuf.h"
+#include "qdf_atomic.h"
+
+#define direct_buf_rx_log(level, args...) \
+ QDF_TRACE(QDF_MODULE_ID_DIRECT_BUF_RX, level, ## args)
+#define direct_buf_rx_logfl(level, format, args...) \
+ direct_buf_rx_log(level, FL(format), ## args)
+#define direct_buf_alert(format, args...) \
+ direct_buf_rx_logfl(QDF_TRACE_LEVEL_FATAL, format, ## args)
+#define direct_buf_rx_err(format, args...) \
+ direct_buf_rx_logfl(QDF_TRACE_LEVEL_ERROR, format, ## args)
+#define direct_buf_rx_warn(format, args...) \
+ direct_buf_rx_logfl(QDF_TRACE_LEVEL_WARN, format, ## args)
+#define direct_buf_rx_notice(format, args...) \
+ direct_buf_rx_logfl(QDF_TRACE_LEVEL_INFO, format, ## args)
+#define direct_buf_rx_info(format, args...) \
+ direct_buf_rx_logfl(QDF_TRACE_LEVEL_INFO_HIGH, format, ## args)
+#define direct_buf_rx_debug(format, args...) \
+ direct_buf_rx_logfl(QDF_TRACE_LEVEL_DEBUG, format, ## args)
+#define direct_buf_rx_enter() \
+ direct_buf_rx_logfl(QDF_TRACE_LEVEL_DEBUG, "enter")
+#define direct_buf_rx_exit() \
+ direct_buf_rx_logfl(QDF_TRACE_LEVEL_DEBUG, "exit")
+
+struct wlan_objmgr_psoc;
+struct wlan_lmac_if_tx_ops;
+
+/**
+ * struct direct_buf_rx_data - direct buffer rx data
+ * @dbr_len: Length of the buffer DMAed
+ * @vaddr: Virtual address of the buffer that has DMAed data
+ */
+struct direct_buf_rx_data {
+ size_t dbr_len;
+ void *vaddr;
+};
+
+/**
+ * direct_buf_rx_attach: Function to initialize direct buf rx module
+ * @psoc: pointer to psoc object
+ *
+ * Return: QDF status of operation
+ */
+QDF_STATUS direct_buf_rx_attach(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * direct_buf_rx_detach: Function to deinitialize direct buf rx module
+ * @psoc: pointer to psoc object
+ *
+ * Return: QDF status of operation
+ */
+QDF_STATUS direct_buf_rx_detach(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * direct_buf_rx_psoc_obj_fill: Fill hal_soc,osdev in direct buf rx psoc obj
+ * @psoc: pointer to psoc object
+ * @hal_soc: Opaque HAL SOC handle
+ * @osdev: QDF os device handle
+ *
+ * Return: QDF status of operation
+ */
+QDF_STATUS direct_buf_rx_psoc_obj_fill(struct wlan_objmgr_psoc *psoc,
+ void *hal_soc, qdf_device_t osdev);
+
+/**
+ * target_if_direct_buf_rx_register_tx_ops: Register tx ops for direct buffer
+ * rx module
+ * @tx_ops: pointer to lmac interface tx ops
+ *
+ * Return: None
+ */
+void target_if_direct_buf_rx_register_tx_ops(
+ struct wlan_lmac_if_tx_ops *tx_ops);
+
+#endif /* _TARGET_IF_DIRECT_BUF_RX_API_H_ */
diff --git a/target_if/direct_buf_rx/src/target_if_direct_buf_rx_api.c b/target_if/direct_buf_rx/src/target_if_direct_buf_rx_api.c
new file mode 100644
index 000000000..13aee3c24
--- /dev/null
+++ b/target_if/direct_buf_rx/src/target_if_direct_buf_rx_api.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2017 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 <qdf_status.h>
+#include <target_if_direct_buf_rx_api.h>
+#include <wlan_objmgr_cmn.h>
+#include <wlan_objmgr_global_obj.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <wlan_objmgr_cmn.h>
+#include "target_if_direct_buf_rx_main.h"
+
+QDF_STATUS direct_buf_rx_attach(struct wlan_objmgr_psoc *psoc)
+{
+ QDF_STATUS status;
+
+ status = target_if_direct_buf_rx_psoc_obj_create(psoc);
+
+ if (QDF_IS_STATUS_ERROR(status)) {
+ direct_buf_rx_err("Failed to create psoc priv obj");
+ return status;
+ }
+
+ status = wlan_objmgr_register_pdev_create_handler(
+ WLAN_TARGET_IF_COMP_DIRECT_BUF_RX,
+ target_if_direct_buf_rx_pdev_create_handler,
+ NULL);
+
+ if (QDF_IS_STATUS_ERROR(status)) {
+ direct_buf_rx_err("Failed to register pdev create handler");
+ goto dbr_destroy_psoc_handler;
+ }
+
+ status = wlan_objmgr_register_pdev_destroy_handler(
+ WLAN_TARGET_IF_COMP_DIRECT_BUF_RX,
+ target_if_direct_buf_rx_pdev_destroy_handler,
+ NULL);
+
+ if (QDF_IS_STATUS_ERROR(status)) {
+ direct_buf_rx_err("Failed to register pdev destroy handler");
+ goto dbr_unreg_pdev_create;
+ }
+
+ status = target_if_direct_buf_rx_register_events(psoc);
+
+ if (QDF_IS_STATUS_ERROR(status)) {
+ direct_buf_rx_err("Direct Buffer RX register events failed");
+ goto dbr_unreg_pdev_destroy;
+ }
+
+ direct_buf_rx_info("Direct Buffer RX pdev,psoc create and destroy handlers registered");
+
+ return QDF_STATUS_SUCCESS;
+
+dbr_unreg_pdev_destroy:
+ status = wlan_objmgr_unregister_pdev_destroy_handler(
+ WLAN_TARGET_IF_COMP_DIRECT_BUF_RX,
+ target_if_direct_buf_rx_pdev_destroy_handler,
+ NULL);
+
+dbr_unreg_pdev_create:
+ status = wlan_objmgr_unregister_pdev_create_handler(
+ WLAN_TARGET_IF_COMP_DIRECT_BUF_RX,
+ target_if_direct_buf_rx_pdev_create_handler,
+ NULL);
+
+dbr_destroy_psoc_handler:
+ status = target_if_direct_buf_rx_psoc_obj_destroy(psoc);
+
+ return QDF_STATUS_E_FAILURE;
+}
+qdf_export_symbol(direct_buf_rx_attach);
+
+QDF_STATUS direct_buf_rx_detach(struct wlan_objmgr_psoc *psoc)
+{
+ QDF_STATUS status;
+
+ status = target_if_direct_buf_rx_unregister_events(psoc);
+
+ if (QDF_IS_STATUS_ERROR(status))
+ direct_buf_rx_err("Direct Buffer RX unregister events failed");
+
+ status = wlan_objmgr_unregister_pdev_destroy_handler(
+ WLAN_TARGET_IF_COMP_DIRECT_BUF_RX,
+ target_if_direct_buf_rx_pdev_destroy_handler,
+ NULL);
+
+ if (QDF_IS_STATUS_ERROR(status))
+ direct_buf_rx_err("Failed to unregister pdev destroy handler");
+
+ status = wlan_objmgr_unregister_pdev_create_handler(
+ WLAN_TARGET_IF_COMP_DIRECT_BUF_RX,
+ target_if_direct_buf_rx_pdev_create_handler,
+ NULL);
+
+ if (QDF_IS_STATUS_ERROR(status))
+ direct_buf_rx_err("Failed to unregister pdev create handler");
+
+ status = target_if_direct_buf_rx_psoc_obj_destroy(psoc);
+
+ if (QDF_IS_STATUS_ERROR(status))
+ direct_buf_rx_err("Failed to destroy psoc priv obj");
+
+ direct_buf_rx_info("Direct Buffer RX pdev,psoc create and destroy handlers unregistered");
+
+ return status;
+}
+qdf_export_symbol(direct_buf_rx_detach);
+
+QDF_STATUS direct_buf_rx_psoc_obj_fill(struct wlan_objmgr_psoc *psoc,
+ void *hal_soc, qdf_device_t osdev)
+{
+ struct direct_buf_rx_psoc_obj *dbr_psoc_obj;
+
+ if (hal_soc == NULL || osdev == NULL) {
+ direct_buf_rx_err("hal soc or osdev is null");
+ return QDF_STATUS_E_INVAL;
+ }
+
+ dbr_psoc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc,
+ WLAN_TARGET_IF_COMP_DIRECT_BUF_RX);
+
+ direct_buf_rx_info("Dbr psoc obj %pK", dbr_psoc_obj);
+
+ if (dbr_psoc_obj == NULL) {
+ direct_buf_rx_err("dir buf rx psoc obj is null");
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ dbr_psoc_obj->hal_soc = hal_soc;
+ dbr_psoc_obj->osdev = osdev;
+
+ return QDF_STATUS_SUCCESS;
+}
+
+void target_if_direct_buf_rx_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
+{
+ tx_ops->dbr_tx_ops.direct_buf_rx_module_register =
+ target_if_direct_buf_rx_module_register;
+}
+qdf_export_symbol(target_if_direct_buf_rx_register_tx_ops);
diff --git a/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.c b/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.c
new file mode 100644
index 000000000..3b1f90f77
--- /dev/null
+++ b/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.c
@@ -0,0 +1,972 @@
+/*
+ * Copyright (c) 2017 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 "wmi_unified_api.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 <wlan_objmgr_psoc_service_ready_api.h>
+
+static uint8_t get_num_dbr_modules_per_pdev(struct wlan_objmgr_pdev *pdev)
+{
+ struct wlan_objmgr_psoc *psoc;
+ struct wlan_objmgr_psoc_ext_service_ready_param *ext_svc_param;
+ struct wlan_psoc_host_dbr_ring_caps *dbr_ring_cap;
+ uint8_t num_dbr_ring_caps, cap_idx, pdev_id, num_modules;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+
+ if (psoc == NULL) {
+ direct_buf_rx_err("psoc is null");
+ return 0;
+ }
+
+ ext_svc_param = &psoc->ext_service_param;
+ num_dbr_ring_caps = ext_svc_param->service_ext_param.num_dbr_ring_caps;
+ dbr_ring_cap = ext_svc_param->dbr_ring_cap;
+ 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_objmgr_psoc_ext_service_ready_param *ext_svc_param;
+ 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;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+
+ if (psoc == NULL) {
+ direct_buf_rx_err("psoc is null");
+ return QDF_STATUS_E_INVAL;
+ }
+
+ ext_svc_param = &psoc->ext_service_param;
+ num_dbr_ring_caps = ext_svc_param->service_ext_param.num_dbr_ring_caps;
+ dbr_ring_cap = ext_svc_param->dbr_ring_cap;
+ pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev);
+
+ 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 == NULL) {
+ direct_buf_rx_err("pdev context passed is null");
+ return QDF_STATUS_E_INVAL;
+ }
+
+ psoc = wlan_pdev_get_psoc(pdev);
+
+ if (psoc == NULL) {
+ 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 == NULL) {
+ direct_buf_rx_err("Failed to allocate dir buf rx pdev obj");
+ return QDF_STATUS_E_NOMEM;
+ }
+
+ direct_buf_rx_info("Dbr pdev obj %pK", dbr_pdev_obj);
+
+ num_modules = get_num_dbr_modules_per_pdev(pdev);
+ direct_buf_rx_info("Number of modules = %d pdev %d", num_modules,
+ wlan_objmgr_pdev_get_pdev_id(pdev));
+ dbr_pdev_obj->num_modules = num_modules;
+ dbr_pdev_obj->dbr_mod_param = qdf_mem_malloc(num_modules *
+ sizeof(struct direct_buf_rx_module_param));
+
+ if (dbr_pdev_obj->dbr_mod_param == NULL) {
+ direct_buf_rx_err("Failed to allocate dir buf rx mod param");
+ qdf_mem_free(dbr_pdev_obj);
+ return QDF_STATUS_E_NOMEM;
+ }
+
+ 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);
+ goto attach_error;
+ }
+
+ return QDF_STATUS_SUCCESS;
+
+attach_error:
+ qdf_mem_free(dbr_pdev_obj->dbr_mod_param);
+ qdf_mem_free(dbr_pdev_obj);
+
+ return status;
+}
+
+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;
+
+ if (pdev == NULL) {
+ 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 == NULL) {
+ 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++)
+ target_if_deinit_dbr_ring(pdev, dbr_pdev_obj, mod_idx);
+
+ 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_obj_create(
+ struct wlan_objmgr_psoc *psoc)
+{
+ struct direct_buf_rx_psoc_obj *dbr_psoc_obj;
+ QDF_STATUS status;
+
+ direct_buf_rx_enter();
+
+ if (psoc == NULL) {
+ 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) {
+ direct_buf_rx_err("failed to alloc dir buf rx psoc obj");
+ return QDF_STATUS_E_NOMEM;
+ }
+
+ direct_buf_rx_info("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_obj_destroy(
+ struct wlan_objmgr_psoc *psoc)
+{
+ 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, uint8_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;
+ 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;
+
+ 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 == NULL) {
+ 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", 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 != NULL);
+ 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);
+ direct_buf_rx_info("Cookie = %d", cookie);
+ direct_buf_rx_info("dw_lo = %x dw_hi = %x", dw_lo, dw_hi);
+ *ring_entry = (uint64_t)dw_hi << 32 | dw_lo;
+ direct_buf_rx_info("Valid ring entry");
+ 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)
+{
+ uint8_t idx;
+ void *buf, *buf_aligned;
+ 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++) {
+ buf = qdf_mem_malloc(dbr_ring_cap->min_buf_size +
+ dbr_ring_cap->min_buf_align - 1);
+ if (!buf) {
+ direct_buf_rx_err("dir buf rx ring buf alloc failed");
+ return QDF_STATUS_E_NOMEM;
+ }
+ dbr_buf_pool[idx].vaddr = buf;
+ buf_aligned = (void *)(uintptr_t)qdf_roundup(
+ (uint64_t)(uintptr_t)buf, DBR_RING_BASE_ALIGN);
+ dbr_buf_pool[idx].offset = buf_aligned - buf;
+ dbr_buf_pool[idx].cookie = idx;
+ status = target_if_dbr_replenish_ring(pdev, mod_param,
+ buf_aligned, idx);
+ if (QDF_IS_STATUS_ERROR(status)) {
+ direct_buf_rx_err("replenish failed with status : %d",
+ status);
+ qdf_mem_free(buf);
+ 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 == NULL) {
+ direct_buf_rx_err("dir buf rx psoc object is null");
+ 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_info("Max Entries = %d", max_entries);
+ direct_buf_rx_info("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_info("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) {
+ direct_buf_rx_err("dir buf rx buf pool alloc failed");
+ 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_info("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_info("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, 0,
+ wlan_objmgr_pdev_get_pdev_id(pdev), &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_info("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) {
+ direct_buf_rx_err("Ring cap alloc failed");
+ 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) {
+ direct_buf_rx_err("Ring config alloc failed");
+ 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;
+
+ 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;
+ wmi_hdl = pdev->tgt_if_handle;
+ 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 = wlan_objmgr_pdev_get_pdev_id(pdev);
+ /* 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_NUM_RESP_PER_EVENT;
+ dbr_cfg_req.event_timeout_ms = DBR_EVENT_TIMEOUT_IN_MS;
+ direct_buf_rx_info("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)
+{
+ QDF_STATUS status = QDF_STATUS_SUCCESS;
+ struct direct_buf_rx_module_param *mod_param;
+
+ direct_buf_rx_info("Init DBR ring for module %d", mod_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]);
+
+ if (!mod_param) {
+ direct_buf_rx_err("dir buf rx module param is null");
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ direct_buf_rx_info("mod_param %pK", mod_param);
+
+ mod_param->mod_id = mod_id+1;
+
+ /* 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);
+ return status;
+}
+
+QDF_STATUS target_if_direct_buf_rx_module_register(
+ struct wlan_objmgr_pdev *pdev, uint8_t mod_id,
+ int (*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;
+
+ if (pdev == NULL) {
+ direct_buf_rx_err("pdev context passed is null");
+ return QDF_STATUS_E_INVAL;
+ }
+
+ if (dbr_rsp_handler == NULL) {
+ 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 == NULL) {
+ direct_buf_rx_err("dir buf rx object is null");
+ return QDF_STATUS_E_FAILURE;
+ }
+ direct_buf_rx_info("Dbr pdev obj %pK", dbr_pdev_obj);
+
+ dbr_pdev_obj->dbr_mod_param[mod_id].dbr_rsp_handler =
+ dbr_rsp_handler;
+
+ status = target_if_init_dbr_ring(pdev, dbr_pdev_obj,
+ (enum DBR_MODULE)mod_id);
+
+ 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_err("Incorrect paddr found on cookie slot");
+ return NULL;
+}
+
+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 == NULL) {
+ 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);
+ direct_buf_rx_info("Cookie = %d", *cookie);
+ dbr_data->vaddr = target_if_dbr_vaddr_lookup(mod_param, paddr, *cookie);
+ direct_buf_rx_info("Vaddr look up = %x", 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;
+}
+
+static int target_if_direct_buf_rx_rsp_event_handler(ol_scn_t scn,
+ uint8_t *data_buf,
+ uint32_t data_len)
+{
+ int ret;
+ 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;
+
+ 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;
+ }
+
+ if (wmi_extract_dbr_buf_release_fixed(GET_WMI_HDL_FROM_PSOC(psoc),
+ 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_info("Num buf release entry = %d",
+ dbr_rsp.num_buf_release_entry);
+
+ pdev = wlan_objmgr_get_pdev_by_id(psoc, dbr_rsp.pdev_id,
+ WLAN_DIRECT_BUF_RX_ID);
+ if (!pdev) {
+ direct_buf_rx_err("pdev 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 == NULL) {
+ direct_buf_rx_err("dir buf rx object is null");
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ mod_param = &(dbr_pdev_obj->dbr_mod_param[dbr_rsp.mod_id-1]);
+
+ if (!mod_param) {
+ direct_buf_rx_err("dir buf rx module param is null");
+ 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));
+
+ for (i = 0; i < dbr_rsp.num_buf_release_entry; i++) {
+ if (wmi_extract_dbr_buf_release_entry(
+ GET_WMI_HDL_FROM_PSOC(psoc), data_buf, i,
+ &dbr_rsp.dbr_entries[i]) != QDF_STATUS_SUCCESS) {
+ direct_buf_rx_err("Unable to extract DBR buf entry %d",
+ i+1);
+ 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");
+ return QDF_STATUS_E_FAILURE;
+ }
+ ret = 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("dir buf rx ring replenish failed");
+ return QDF_STATUS_E_FAILURE;
+ }
+ }
+
+ 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)
+{
+ uint8_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_info("dbr_ring_cfg %pK, dbr_ring_cap %pK dbr_buf_pool %pK",
+ dbr_ring_cfg, dbr_ring_cap, dbr_buf_pool);
+
+ for (idx = 0; idx < dbr_ring_cfg->num_ptr - 1; idx++) {
+ direct_buf_rx_info("dbr buf pool unmap and free for ptr %d",
+ 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 == NULL) {
+ direct_buf_rx_err("dir buf rx psoc object is null");
+ return QDF_STATUS_E_FAILURE;
+ }
+ direct_buf_rx_info("dbr_psoc_obj %pK", dbr_psoc_obj);
+
+ dbr_ring_cfg = mod_param->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_info("dbr buf pool %pK", dbr_buf_pool);
+ target_if_dbr_deinit_ring(pdev, mod_param);
+ qdf_mem_free(dbr_buf_pool);
+ 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)
+{
+ struct direct_buf_rx_module_param *mod_param;
+ struct direct_buf_rx_ring_cap *dbr_ring_cap;
+ QDF_STATUS status;
+
+ direct_buf_rx_enter();
+ mod_param = &(dbr_pdev_obj->dbr_mod_param[mod_id]);
+
+ if (!mod_param) {
+ direct_buf_rx_err("dir buf rx module param is null");
+ return QDF_STATUS_E_FAILURE;
+ }
+ direct_buf_rx_info("mod_param %pK", mod_param);
+
+ dbr_ring_cap = mod_param->dbr_ring_cap;
+ direct_buf_rx_info("dbr_ring_cap %pK", dbr_ring_cap);
+ target_if_dbr_deinit_srng(pdev, mod_param);
+ qdf_mem_free(dbr_ring_cap);
+ dbr_ring_cap = NULL;
+ qdf_mem_free(mod_param);
+ mod_param = NULL;
+
+ return status;
+}
+
+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_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_err("register event handler failed: err %d", ret);
+ return QDF_STATUS_E_INVAL;
+ }
+
+ 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_HDL_FROM_PSOC(psoc),
+ wmi_dma_buf_release_event_id);
+
+ return QDF_STATUS_SUCCESS;
+}
diff --git a/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.h b/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.h
new file mode 100644
index 000000000..385f2b760
--- /dev/null
+++ b/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2017 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.
+ */
+
+#ifndef _TARGET_IF_DIRECT_BUF_RX_MAIN_H_
+#define _TARGET_IF_DIRECT_BUF_RX_MAIN_H_
+
+#include "qdf_types.h"
+#include "qdf_status.h"
+
+struct wlan_objmgr_psoc;
+struct wlan_lmac_if_tx_ops;
+struct direct_buf_rx_data;
+
+#define DBR_RING_BASE_ALIGN 8
+#define DBR_EVENT_TIMEOUT_IN_MS 1
+#define DBR_NUM_RESP_PER_EVENT 1
+
+/**
+ * enum DBR_MODULE - Enum containing the modules supporting direct buf rx
+ * @DBR_MODULE_SPECTRAL: Module ID for Spectral
+ * @DBR_MODULE_MAX: Max module ID
+ */
+enum DBR_MODULE {
+ DBR_MODULE_SPECTRAL = 1,
+ DBR_MODULE_MAX,
+};
+
+/**
+ * struct direct_buf_rx_info - direct buffer rx operation info struct
+ * @cookie: SW cookie used to get the virtual address
+ * @paddr: Physical address pointer for DMA operation
+ * @vaddr: Virtual address pointer
+ * @offset: Offset of aligned address from unaligned
+ */
+struct direct_buf_rx_buf_info {
+ uint32_t cookie;
+ qdf_dma_addr_t paddr;
+ void *vaddr;
+ uint8_t offset;
+};
+
+/**
+ * struct direct_buf_rx_ring_cfg - DMA ring config parameters
+ * @num_ptr: Depth or the number of physical address pointers in the ring
+ * @ring_alloc_size: Size of the HAL ring
+ * @base_paddr_unaligned: base physical addr unaligned
+ * @base_vaddr_unaligned: base virtual addr unaligned
+ * @base_paddr_aligned: base physical addr aligned
+ * @base_vaddr_aligned: base virtual addr unaligned
+ * @head_idx_addr: head index addr
+ * @tail_idx_addr: tail index addr
+ * @srng: HAL srng context
+ */
+struct direct_buf_rx_ring_cfg {
+ uint32_t num_ptr;
+ uint32_t ring_alloc_size;
+ qdf_dma_addr_t base_paddr_unaligned;
+ void *base_vaddr_unaligned;
+ qdf_dma_addr_t base_paddr_aligned;
+ void *base_vaddr_aligned;
+ qdf_dma_addr_t head_idx_addr;
+ qdf_dma_addr_t tail_idx_addr;
+ void *srng;
+ uint32_t buf_size;
+};
+
+/**
+ * struct direct_buf_rx_ring_cap - DMA ring capabilities
+ * @ring_elems_min: Minimum number of pointers in the ring
+ * @min_buf_size: Minimum size of each buffer entry in the ring
+ * @min_buf_align: Minimum alignment of the addresses in the ring
+ */
+struct direct_buf_rx_ring_cap {
+ uint32_t ring_elems_min;
+ uint32_t min_buf_size;
+ uint32_t min_buf_align;
+};
+
+/**
+ * struct direct_buf_rx_module_param - DMA module param
+ * @mod_id: Module ID
+ * @dbr_ring_cap: Pointer to direct buf rx ring capabilities struct
+ * @dbr_ring_cfg: Pointer to direct buf rx ring config struct
+ * @dbr_buf_pool: Pointer to direct buf rx buffer pool struct
+ * @dbr_rsp_handler: Pointer to direct buf rx response handler for the module
+ */
+struct direct_buf_rx_module_param {
+ enum DBR_MODULE mod_id;
+ struct direct_buf_rx_ring_cap *dbr_ring_cap;
+ struct direct_buf_rx_ring_cfg *dbr_ring_cfg;
+ struct direct_buf_rx_buf_info *dbr_buf_pool;
+ int (*dbr_rsp_handler)(struct wlan_objmgr_pdev *pdev,
+ struct direct_buf_rx_data *dbr_data);
+};
+
+/**
+ * struct direct_buf_rx_pdev_obj - Direct Buf RX pdev object struct
+ * @num_modules: Number of modules registered to DBR for the pdev
+ * @dbr_mod_param: Pointer to direct buf rx module param struct
+ */
+struct direct_buf_rx_pdev_obj {
+ uint32_t num_modules;
+ struct direct_buf_rx_module_param *dbr_mod_param;
+};
+
+/**
+ * struct direct_buf_rx_psoc_obj - Direct Buf RX psoc object struct
+ * @hal_soc: Opaque HAL SOC handle
+ * @osdev: QDF os device handle
+ */
+struct direct_buf_rx_psoc_obj {
+ void *hal_soc;
+ qdf_device_t osdev;
+};
+
+/**
+ * target_if_direct_buf_rx_register_events: Register WMI events to direct
+ * buffer rx module
+ * @psoc: pointer to psoc object
+ *
+ * Return : QDF status of operation
+ */
+QDF_STATUS target_if_direct_buf_rx_register_events(
+ struct wlan_objmgr_psoc *psoc);
+
+/**
+ * target_if_direct_buf_rx_unregister_events: Unregister WMI events to direct
+ * buffer rx module
+ * @psoc: pointer to psoc object
+ *
+ * Return : QDF status of operation
+ */
+QDF_STATUS target_if_direct_buf_rx_unregister_events(
+ struct wlan_objmgr_psoc *psoc);
+
+/**
+ * target_if_direct_buf_rx_pdev_create_handler: Handler to be invoked for
+ * direct buffer rx module during
+ * pdev object create
+ * @pdev: pointer to pdev object
+ * @data: pointer to data
+ *
+ * Return : QDF status of operation
+ */
+QDF_STATUS target_if_direct_buf_rx_pdev_create_handler(
+ struct wlan_objmgr_pdev *pdev, void *data);
+
+/**
+ * target_if_direct_buf_rx_pdev_destroy_handler: Handler to be invoked for
+ * direct buffer rx module during
+ * pdev object destroy
+ * @pdev: pointer to pdev object
+ * @data: pointer to data
+ *
+ * Return : QDF status of operation
+ */
+QDF_STATUS target_if_direct_buf_rx_pdev_destroy_handler(
+ struct wlan_objmgr_pdev *pdev, void *data);
+
+/**
+ * target_if_direct_buf_rx_psoc_obj_create: Handler invoked for
+ * direct buffer rx module during
+ * attach
+ * @pdev: pointer to psoc object
+ *
+ * Return : QDF status of operation
+ */
+QDF_STATUS target_if_direct_buf_rx_psoc_obj_create(
+ struct wlan_objmgr_psoc *psoc);
+
+/**
+ * target_if_direct_buf_rx_psoc_obj_destroy: Handler invoked for
+ * direct buffer rx module during
+ * detach
+ * @pdev: pointer to psoc object
+ *
+ * Return : QDF status of operation
+ */
+QDF_STATUS target_if_direct_buf_rx_psoc_obj_destroy(
+ struct wlan_objmgr_psoc *psoc);
+
+/**
+ * target_if_deinit_dbr_ring: Function to deinitialize buffers and ring
+ * allocated for direct buffer rx module
+ * @pdev: pointer to pdev object
+ * @dbr_pdev_obj: pointer to direct buffer rx module pdev obj
+ * @mod_id: module id indicating the module using direct buffer rx framework
+ *
+ * Return : QDF status of operation
+ */
+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);
+/**
+ * target_if_direct_buf_rx_module_register: Function to register to direct
+ * buffer rx module
+ * @pdev: pointer to pdev object
+ * @mod_id: module id indicating the module using direct buffer rx framework
+ * @dbr_rsp_handler: function pointer pointing to the response handler to be
+ * invoked for the module registering to direct buffer rx
+ * module
+ *
+ * Return: QDF status of operation
+ */
+QDF_STATUS target_if_direct_buf_rx_module_register(
+ struct wlan_objmgr_pdev *pdev, uint8_t mod_id,
+ int (*dbr_rsp_handler)(struct wlan_objmgr_pdev *pdev,
+ struct direct_buf_rx_data *dbr_data));
+
+#endif /* _TARGET_IF_DIRECT_BUF_RX_MAIN_H_ */