Browse Source

qcacld-3.0: Add support for DP QMI WFDS client

Add support for QMI client for WiFi Driver
Service (WFDS) in DP component.

Change-Id: Id0a8a51c32aa9f058e57e622b3ad65d405806148
CRs-Fixed: 3328386
Yeshwanth Sriram Guntuka 2 years ago
parent
commit
bff1e3aa36

+ 4 - 0
Kbuild

@@ -2574,6 +2574,10 @@ WLAN_DP_COMP_OBJS += $(DP_COMP_CORE_DIR)/wlan_dp_fisa_rx.o
 WLAN_DP_COMP_OBJS += $(DP_COMP_CORE_DIR)/wlan_dp_rx_fst.o
 endif
 
+ifeq ($(CONFIG_FEATURE_DIRECT_LINK), y)
+WLAN_DP_COMP_OBJS += $(DP_COMP_CORE_DIR)/wlan_dp_wfds.o
+endif
+
 $(call add-wlan-objs,dp_comp,$(WLAN_DP_COMP_OBJS))
 
 #######################################################

+ 3 - 0
components/dp/core/inc/wlan_dp_priv.h

@@ -38,6 +38,7 @@
 #include <i_qdf_net_stats.h>
 #include <qdf_types.h>
 #include "htc_api.h"
+#include "wlan_dp_wfds.h"
 
 #ifndef NUM_TX_RX_HISTOGRAM
 #define NUM_TX_RX_HISTOGRAM 128
@@ -367,11 +368,13 @@ enum RX_OFFLOAD {
  * @dp_ctx: pointer to DP psoc priv context
  * @lpass_ep_id: LPASS data msg service endpoint id
  * @direct_link_refill_ring_hdl: Direct Link refill ring handle
+ * @dl_wfds: pointer to direct link WFDS context
  */
 struct dp_direct_link_context {
 	struct wlan_dp_psoc_context *dp_ctx;
 	HTC_ENDPOINT_ID lpass_ep_id;
 	struct dp_srng *direct_link_refill_ring_hdl;
+	struct dp_direct_link_wfds_context *dl_wfds;
 };
 #endif
 

+ 155 - 0
components/dp/core/inc/wlan_dp_wfds.h

@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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 _WLAN_DP_WFDS_H_
+#define _WLAN_DP_WFDS_H_
+
+#ifdef FEATURE_DIRECT_LINK
+
+#include "qdf_atomic.h"
+#include "wlan_dp_priv.h"
+#include "wlan_qmi_public_struct.h"
+#include "wlan_qmi_wfds_api.h"
+
+/**
+ * enum dp_wfds_msg - WFDS message type
+ * @DP_WFDS_REQ_MEM_IND_MSG: Memory request indication message
+ * @DP_WFDS_IPCC_MAP_N_CFG_IND_MSG: IPCC map and configure indication message
+ * @DP_WFDS_MSG_MAX: not a real value just a placeholder for max
+ */
+enum dp_wfds_msg {
+	DP_WFDS_REQ_MEM_IND_MSG,
+	DP_WFDS_IPCC_MAP_N_CFG_IND_MSG,
+	DP_WFDS_MSG_MAX,
+};
+
+/**
+ * enum dp_wfds_state - Datapath WFDS state
+ * @DP_WFDS_SVC_DISCONNECTED: service disconnected
+ * @DP_WFDS_SVC_CONNECTED: service connected
+ * @DP_WFDS_SVC_CONFIG_DONE: configuration msg handshake done
+ * @DP_WFDS_SVC_MEM_CONFIG_DONE: memory handshake with server done
+ * @DP_WFDS_SVC_IPCC_MAP_N_CFG_DONE: IPCC map and cfg handshake completed
+ */
+enum dp_wfds_state {
+	DP_WFDS_SVC_DISCONNECTED,
+	DP_WFDS_SVC_CONNECTED,
+	DP_WFDS_SVC_CONFIG_DONE,
+	DP_WFDS_SVC_MEM_CONFIG_DONE,
+	DP_WFDS_SVC_IPCC_MAP_N_CFG_DONE,
+};
+
+/**
+ * enum dp_wfds_event_type  - Datapath WFDS event type
+ * @DP_WFDS_NEW_SERVER: QMI new server event
+ * @DP_WFDS_MEM_REQ: QMI memory request event
+ * @DP_WFDS_IPCC_MAP_N_CFG: QMI IPCC map and configure event
+ */
+enum dp_wfds_event_type {
+	DP_WFDS_NEW_SERVER,
+	DP_WFDS_MEM_REQ,
+	DP_WFDS_IPCC_MAP_N_CFG,
+};
+
+/**
+ * struct dp_wfds_event - DP QMI event structure
+ * @list_node: node used for adding/deleting to a list
+ * @wfds_evt_type: QMI event type
+ * @data: Pointer to event data
+ */
+struct dp_wfds_event {
+	qdf_list_node_t list_node;
+	enum dp_wfds_event_type wfds_evt_type;
+	void *data;
+};
+
+/**
+ * struct dp_direct_link_wfds_context - DP Direct Link WFDS context structure
+ * @direct_link_ctx: direct link context
+ * @wfds_work: work to be scheduled on QMI event
+ * @wfds_wq: QMI workqueue
+ * @wfds_event_list_lock: spinlock for event list access
+ * @wfds_event_list: QMI event list
+ * @wfds_state: QMI state
+ * @num_mem_arenas: Number of memory arenas requested by QMI server
+ * @mem_arena_pages: Pointer to array of mem multi page structure for arenas
+ * @ipcc_dma_addr: ipcc dma address
+ */
+struct dp_direct_link_wfds_context {
+	struct dp_direct_link_context *direct_link_ctx;
+	qdf_work_t wfds_work;
+	qdf_workqueue_t *wfds_wq;
+	qdf_spinlock_t wfds_event_list_lock;
+	qdf_list_t wfds_event_list;
+	qdf_atomic_t wfds_state;
+	uint32_t num_mem_arenas;
+	struct qdf_mem_multi_page_t *mem_arena_pages;
+	uint32_t ipcc_dma_addr;
+};
+
+/**
+ * dp_wfds_handle_request_mem_ind() - Process request memory indication received
+ *  from QMI server
+ * @mem_msg: pointer to memory request indication message
+ *
+ * Return: None
+ */
+void
+dp_wfds_handle_request_mem_ind(struct wlan_qmi_wfds_mem_ind_msg *mem_msg);
+
+/**
+ * dp_wfds_handle_ipcc_map_n_cfg_ind() - Process IPCC map and configure
+ *  indication received from QMI server
+ * @ipcc_msg: pointer to IPCC map and configure indication message
+ *
+ * Return: None
+ */
+void
+dp_wfds_handle_ipcc_map_n_cfg_ind(struct wlan_qmi_wfds_ipcc_map_n_cfg_ind_msg *ipcc_msg);
+
+/**
+ * dp_wfds_new_server() - New server callback triggered when service is up.
+ *  Connect to the service as part of this call.
+ *
+ * Return: QDF status
+ */
+QDF_STATUS dp_wfds_new_server(void);
+
+/**
+ * dp_wfds_del_server() - Del server callback triggered when service is
+ *  down.
+ *
+ * Return: None
+ */
+void dp_wfds_del_server(void);
+
+/**
+ * dp_wfds_init() - Initialize DP WFDS context
+ * @direct_link_ctx: DP Direct Link context
+ *
+ * Return: QDF status
+ */
+QDF_STATUS dp_wfds_init(struct dp_direct_link_context *direct_link_ctx);
+
+/**
+ * dp_wfds_deinit() - Deinitialize DP WFDS context
+ * @direct_link_ctx: DP Direct Link context
+ *
+ * Return: None
+ */
+void dp_wfds_deinit(struct dp_direct_link_context *direct_link_ctx);
+#endif
+#endif

+ 9 - 0
components/dp/core/src/wlan_dp_main.c

@@ -1693,6 +1693,14 @@ QDF_STATUS dp_direct_link_init(struct wlan_dp_psoc_context *dp_ctx)
 		return status;
 	}
 
+	status = dp_wfds_init(dp_direct_link_ctx);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		dp_err("Failed to initialize QMI for Direct Link");
+		dp_direct_link_refill_ring_deinit(dp_ctx->dp_direct_link_ctx);
+		qdf_mem_free(dp_direct_link_ctx);
+		return status;
+	}
+
 	dp_ctx->dp_direct_link_ctx = dp_direct_link_ctx;
 
 	return status;
@@ -1706,6 +1714,7 @@ void dp_direct_link_deinit(struct wlan_dp_psoc_context *dp_ctx)
 	if (!dp_ctx->dp_direct_link_ctx)
 		return;
 
+	dp_wfds_deinit(dp_ctx->dp_direct_link_ctx);
 	dp_direct_link_refill_ring_deinit(dp_ctx->dp_direct_link_ctx);
 
 	qdf_mem_free(dp_ctx->dp_direct_link_ctx);

+ 532 - 0
components/dp/core/src/wlan_dp_wfds.c

@@ -0,0 +1,532 @@
+/*
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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 "wlan_dp_wfds.h"
+#include "hif.h"
+#include "hal_api.h"
+#include "dp_types.h"
+#include "dp_rx.h"
+#include "pld_common.h"
+#include "wlan_objmgr_psoc_obj.h"
+
+static struct dp_direct_link_wfds_context *gp_dl_wfds_ctx;
+
+/**
+ * dp_wfds_send_config_msg() - Send config message to WFDS QMI server
+ * @dl_wfds: Direct Link WFDS context
+ *
+ * Return: QDF status
+ */
+static QDF_STATUS
+dp_wfds_send_config_msg(struct dp_direct_link_wfds_context *dl_wfds)
+{
+	struct dp_direct_link_context *direct_link_ctx =
+					dl_wfds->direct_link_ctx;
+	struct wlan_qmi_wfds_config_req_msg *info;
+	struct dp_soc *dp_soc =
+		wlan_psoc_get_dp_handle(dl_wfds->direct_link_ctx->dp_ctx->psoc);
+	struct hif_opaque_softc *hif_ctx;
+	qdf_device_t qdf_dev;
+	void *hal_soc;
+	struct hal_mem_info mem_info = {0};
+	struct hif_direct_link_ce_info ce_info[QMI_WFDS_CE_MAX_SRNG] = {0};
+	QDF_STATUS status;
+	struct hif_ce_ring_info *srng_info;
+	struct hal_srng_params srng_params = {0};
+	hal_ring_handle_t refill_ring;
+	uint8_t i;
+
+	qdf_dev = dl_wfds->direct_link_ctx->dp_ctx->qdf_dev;
+
+	if (!dp_soc || !dp_soc->hif_handle || !qdf_dev)
+		return QDF_STATUS_E_FAILURE;
+
+	hif_ctx = dp_soc->hif_handle;
+
+	hal_soc = hif_get_hal_handle(hif_ctx);
+	if (!hal_soc)
+		return QDF_STATUS_E_FAILURE;
+
+	hal_get_meminfo(hal_soc, &mem_info);
+
+	info = qdf_mem_malloc(sizeof(*info));
+	if (!info)
+		return QDF_STATUS_E_NOMEM;
+
+	info->shadow_rdptr_mem_paddr =
+				(uint64_t)mem_info.shadow_rdptr_mem_paddr;
+	info->shadow_rdptr_mem_size = sizeof(uint32_t) * HAL_SRNG_ID_MAX;
+	info->shadow_wrptr_mem_paddr =
+				(uint64_t)mem_info.shadow_wrptr_mem_paddr;
+	info->shadow_wrptr_mem_size = sizeof(uint32_t) * HAL_MAX_LMAC_RINGS;
+	info->pcie_bar_pa = (uint64_t)mem_info.dev_base_paddr;
+
+	info->ce_info_len = QMI_WFDS_CE_MAX_SRNG;
+	status = hif_get_direct_link_ce_srng_info(hif_ctx, ce_info,
+						  QMI_WFDS_CE_MAX_SRNG);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		dp_err("Direct Link CE srng info get failed");
+		qdf_mem_free(info);
+		return status;
+	}
+
+	for (i = 0; i < QMI_WFDS_CE_MAX_SRNG; i++) {
+		info->ce_info[i].ce_id = ce_info[i].ce_id;
+		info->ce_info[i].ce_dir = ce_info[i].pipe_dir;
+
+		srng_info = &ce_info[i].ring_info;
+		info->ce_info[i].srng_info.ring_id = srng_info->ring_id;
+		info->ce_info[i].srng_info.dir = srng_info->ring_dir;
+		info->ce_info[i].srng_info.num_entries = srng_info->num_entries;
+		info->ce_info[i].srng_info.entry_size = srng_info->entry_size;
+		info->ce_info[i].srng_info.ring_base_paddr =
+						     srng_info->ring_base_paddr;
+		info->ce_info[i].srng_info.hp_paddr = srng_info->hp_paddr;
+		info->ce_info[i].srng_info.tp_paddr = srng_info->tp_paddr;
+	}
+
+	refill_ring = direct_link_ctx->direct_link_refill_ring_hdl->hal_srng;
+	hal_get_srng_params(hal_soc, refill_ring, &srng_params);
+	info->rx_refill_ring.ring_id = srng_params.ring_id;
+	info->rx_refill_ring.dir =
+		(srng_params.ring_dir == HAL_SRNG_SRC_RING) ?
+		QMI_WFDS_SRNG_SOURCE_RING : QMI_WFDS_SRNG_DESTINATION_RING;
+	info->rx_refill_ring.num_entries = srng_params.num_entries;
+	info->rx_refill_ring.entry_size = srng_params.entry_size;
+	info->rx_refill_ring.ring_base_paddr = srng_params.ring_base_paddr;
+
+	info->rx_refill_ring.hp_paddr =
+				hal_srng_get_hp_addr(hal_soc, refill_ring);
+	info->rx_refill_ring.tp_paddr =
+				hal_srng_get_tp_addr(hal_soc, refill_ring);
+
+	info->rx_pkt_tlv_len = dp_soc->rx_pkt_tlv_size;
+	info->rx_rbm = dp_rx_get_rx_bm_id(dp_soc);
+	info->pci_slot = pld_get_pci_slot(qdf_dev->dev);
+	qdf_assert(info.pci_slot >= 0);
+	info->lpass_ep_id = direct_link_ctx->lpass_ep_id;
+
+	status = wlan_qmi_wfds_send_config_msg(direct_link_ctx->dp_ctx->psoc,
+					       info);
+	qdf_mem_free(info);
+
+	if (QDF_IS_STATUS_ERROR(status)) {
+		dp_err("Configuration message send failed %d", status);
+		return status;
+	}
+
+	qdf_atomic_set(&dl_wfds->wfds_state,
+		       DP_WFDS_SVC_CONFIG_DONE);
+
+	return status;
+}
+
+/**
+ * dp_wfds_req_mem_msg() - Send Request Memory message to QMI server
+ * @dl_wfds: Direct Link QMI context
+ *
+ * Return: QDF status
+ */
+static QDF_STATUS
+dp_wfds_req_mem_msg(struct dp_direct_link_wfds_context *dl_wfds)
+{
+	struct wlan_qmi_wfds_mem_req_msg *info;
+	struct dp_soc *dp_soc =
+		wlan_psoc_get_dp_handle(dl_wfds->direct_link_ctx->dp_ctx->psoc);
+	struct hif_opaque_softc *hif_ctx;
+	QDF_STATUS status;
+	struct qdf_mem_multi_page_t *pages;
+	uint16_t num_pages;
+	uint8_t i;
+
+	if (!dl_wfds || !dp_soc || !dp_soc->hif_handle)
+		return QDF_STATUS_E_NOSUPPORT;
+
+	hif_ctx = dp_soc->hif_handle;
+
+	info = qdf_mem_malloc(sizeof(*info));
+	if (!info)
+		return QDF_STATUS_E_NOMEM;
+
+	info->mem_arena_page_info_len = dl_wfds->num_mem_arenas;
+	for (i = 0; i < dl_wfds->num_mem_arenas; i++) {
+		if (i == QMI_WFDS_MEM_ARENA_CE_RX_MSG_BUFFERS) {
+			uint64_t *dma_addr = NULL;
+
+			num_pages =
+			    hif_get_direct_link_ce_dest_srng_buffers(hif_ctx,
+								     &dma_addr);
+			qdf_assert(dma_addr);
+
+			info->mem_arena_page_info[i].num_entries_per_page = 1;
+			info->mem_arena_page_info[i].page_dma_addr_len =
+								      num_pages;
+			while (num_pages--)
+				info->mem_arena_page_info[i].page_dma_addr[num_pages] =
+							dma_addr[num_pages];
+
+			qdf_mem_free(dma_addr);
+			continue;
+		}
+
+		num_pages = dl_wfds->mem_arena_pages[i].num_pages;
+		pages = &dl_wfds->mem_arena_pages[i];
+
+		info->mem_arena_page_info[i].num_entries_per_page =
+		       dl_wfds->mem_arena_pages[i].num_element_per_page;
+		info->mem_arena_page_info[i].page_dma_addr_len = num_pages;
+
+		while (num_pages--)
+			info->mem_arena_page_info[i].page_dma_addr[num_pages] =
+					pages->dma_pages[num_pages].page_p_addr;
+	}
+
+	status = wlan_qmi_wfds_send_req_mem_msg(
+					dl_wfds->direct_link_ctx->dp_ctx->psoc,
+					info);
+	qdf_mem_free(info);
+
+	if (QDF_IS_STATUS_ERROR(status)) {
+		dp_err("Memory request message send failed %d", status);
+		return status;
+	}
+
+	qdf_atomic_set(&dl_wfds->wfds_state,
+		       DP_WFDS_SVC_MEM_CONFIG_DONE);
+
+	return status;
+}
+
+/**
+ * dp_wfds_ipcc_map_n_cfg_msg() - Send the IPCC map and configure message
+ *  to QMI server
+ * @dlink_wfds: Direct Link QMI context
+ *
+ * Return: QDF status
+ */
+static QDF_STATUS
+dp_wfds_ipcc_map_n_cfg_msg(struct dp_direct_link_wfds_context *dlink_wfds)
+{
+	struct wlan_qmi_wfds_ipcc_map_n_cfg_req_msg info = {0};
+	QDF_STATUS status;
+
+	info.status = QMI_WFDS_STATUS_SUCCESS;
+
+	status = wlan_qmi_wfds_ipcc_map_n_cfg_msg(
+				dlink_wfds->direct_link_ctx->dp_ctx->psoc,
+				&info);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		dp_err("IPCC map n cfg message send failed %d", status);
+		return status;
+	}
+
+	qdf_atomic_set(&dlink_wfds->wfds_state,
+		       DP_WFDS_SVC_IPCC_MAP_N_CFG_DONE);
+
+	return status;
+}
+
+/**
+ * dp_wfds_work() - DP WFDS work handler
+ * @arg: direct link QMI context
+ *
+ * Return: None
+ */
+static void dp_wfds_work(void *arg)
+{
+	struct dp_direct_link_wfds_context *dl_wfds = arg;
+	struct dp_wfds_event *wfds_evt;
+
+	dp_debug("entry");
+
+	qdf_spinlock_acquire(&dl_wfds->wfds_event_list_lock);
+	while ((wfds_evt =
+		qdf_list_first_entry_or_null(&dl_wfds->wfds_event_list,
+					     struct dp_wfds_event,
+					     list_node))) {
+		qdf_list_remove_node(&dl_wfds->wfds_event_list,
+				     &wfds_evt->list_node);
+		qdf_spinlock_release(&dl_wfds->wfds_event_list_lock);
+
+		switch (wfds_evt->wfds_evt_type) {
+		case DP_WFDS_NEW_SERVER:
+			dp_wfds_send_config_msg(dl_wfds);
+			break;
+		case DP_WFDS_MEM_REQ:
+			dp_wfds_req_mem_msg(dl_wfds);
+			break;
+		case DP_WFDS_IPCC_MAP_N_CFG:
+			dp_wfds_ipcc_map_n_cfg_msg(dl_wfds);
+			break;
+		default:
+			break;
+		}
+
+		qdf_mem_free(wfds_evt);
+
+		qdf_spinlock_acquire(&dl_wfds->wfds_event_list_lock);
+	}
+	qdf_spinlock_release(&dl_wfds->wfds_event_list_lock);
+
+	dp_debug("exit");
+}
+
+/**
+ * dp_wfds_event_post() - Post WFDS event to be processed in worker context
+ * @dl_wfds: Direct Link QMI context
+ * @wfds_evt_type: QMI event type
+ * @data: pointer to QMI data
+ *
+ * Return: QDF status
+ */
+static QDF_STATUS
+dp_wfds_event_post(struct dp_direct_link_wfds_context *dl_wfds,
+		   enum dp_wfds_event_type wfds_evt_type, void *data)
+{
+	struct dp_wfds_event *wfds_evt;
+
+	wfds_evt = qdf_mem_malloc(sizeof(*wfds_evt));
+	if (!wfds_evt)
+		return QDF_STATUS_E_NOMEM;
+
+	wfds_evt->wfds_evt_type = wfds_evt_type;
+	wfds_evt->data = data;
+
+	qdf_spinlock_acquire(&dl_wfds->wfds_event_list_lock);
+	qdf_list_insert_back(&dl_wfds->wfds_event_list,
+			     &wfds_evt->list_node);
+	qdf_spinlock_release(&dl_wfds->wfds_event_list_lock);
+
+	qdf_queue_work(0, dl_wfds->wfds_wq, &dl_wfds->wfds_work);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+void
+dp_wfds_handle_request_mem_ind(struct wlan_qmi_wfds_mem_ind_msg *mem_msg)
+{
+	struct dp_direct_link_wfds_context *dl_wfds = gp_dl_wfds_ctx;
+	qdf_device_t qdf_ctx = dl_wfds->direct_link_ctx->dp_ctx->qdf_dev;
+	uint8_t i;
+
+	if (!dl_wfds || !qdf_ctx)
+		return;
+
+	dp_debug("Received request mem indication from QMI server");
+
+	dl_wfds->num_mem_arenas = mem_msg->mem_arena_info_len;
+	dl_wfds->mem_arena_pages =
+		qdf_mem_malloc(sizeof(*dl_wfds->mem_arena_pages) *
+			       mem_msg->mem_arena_info_len);
+	if (!dl_wfds->mem_arena_pages)
+		return;
+
+	for (i = 0; i < dl_wfds->num_mem_arenas; i++) {
+		if (i == QMI_WFDS_MEM_ARENA_CE_RX_MSG_BUFFERS)
+			continue;
+
+		qdf_mem_multi_pages_alloc(qdf_ctx,
+					 &dl_wfds->mem_arena_pages[i],
+					 mem_msg->mem_arena_info[i].entry_size,
+					 mem_msg->mem_arena_info[i].num_entries,
+					 0, false);
+		if (!dl_wfds->mem_arena_pages[i].num_pages) {
+			while (--i >= 0 &&
+			       dl_wfds->mem_arena_pages[i].num_pages)
+				qdf_mem_multi_pages_free(qdf_ctx,
+					&dl_wfds->mem_arena_pages[i],
+					0, false);
+
+			qdf_mem_free(dl_wfds->mem_arena_pages);
+			dl_wfds->mem_arena_pages = NULL;
+			dl_wfds->num_mem_arenas = 0;
+
+			return;
+		}
+	}
+
+	dp_wfds_event_post(dl_wfds, DP_WFDS_MEM_REQ, NULL);
+}
+
+void
+dp_wfds_handle_ipcc_map_n_cfg_ind(struct wlan_qmi_wfds_ipcc_map_n_cfg_ind_msg *ipcc_msg)
+{
+	struct dp_direct_link_wfds_context *dl_wfds = gp_dl_wfds_ctx;
+	qdf_device_t qdf_ctx = dl_wfds->direct_link_ctx->dp_ctx->qdf_dev;
+	struct dp_soc *dp_soc =
+		wlan_psoc_get_dp_handle(dl_wfds->direct_link_ctx->dp_ctx->psoc);
+	struct hif_opaque_softc *hif_ctx;
+	uint8_t i;
+
+	if (!dl_wfds || !qdf_ctx || !dp_soc || !dp_soc->hif_handle)
+		return;
+
+	hif_ctx = dp_soc->hif_handle;
+
+	dp_debug("Received IPCC map n cfg indication from QMI server");
+
+	/*
+	 * IPCC Address for all the CE srngs will be the same and only the
+	 * IPCC data will differ.
+	 */
+	pld_smmu_map(qdf_ctx->dev, ipcc_msg->ipcc_ce_info[0].ipcc_trig_addr,
+		     &dl_wfds->ipcc_dma_addr, sizeof(uint32_t));
+
+	for (i = 0; i < ipcc_msg->ipcc_ce_info_len; i++)
+		hif_set_irq_config_by_ceid(hif_ctx,
+				      ipcc_msg->ipcc_ce_info[i].ce_id,
+				      dl_wfds->ipcc_dma_addr,
+				      ipcc_msg->ipcc_ce_info[i].ipcc_trig_data);
+
+	dp_wfds_event_post(dl_wfds, DP_WFDS_IPCC_MAP_N_CFG, NULL);
+}
+
+QDF_STATUS dp_wfds_new_server(void)
+{
+	struct dp_direct_link_wfds_context *dl_wfds = gp_dl_wfds_ctx;
+
+	if (!dl_wfds)
+		return QDF_STATUS_E_INVAL;
+
+	qdf_atomic_set(&dl_wfds->wfds_state, DP_WFDS_SVC_CONNECTED);
+
+	dp_debug("Connected to WFDS QMI service, state: 0x%lx",
+		 qdf_atomic_read(&dl_wfds->wfds_state));
+
+	return dp_wfds_event_post(dl_wfds, DP_WFDS_NEW_SERVER, NULL);
+}
+
+void dp_wfds_del_server(void)
+{
+	struct dp_direct_link_wfds_context *dl_wfds = gp_dl_wfds_ctx;
+	qdf_device_t qdf_ctx = dl_wfds->direct_link_ctx->dp_ctx->qdf_dev;
+	enum dp_wfds_state dl_wfds_state;
+	uint8_t i;
+
+	if (!dl_wfds || !qdf_ctx)
+		return;
+
+	dp_debug("WFDS QMI server exiting");
+
+	dl_wfds_state = qdf_atomic_read(&dl_wfds->wfds_state);
+	qdf_atomic_set(&dl_wfds->wfds_state,
+		       DP_WFDS_SVC_DISCONNECTED);
+
+	if (dl_wfds_state >= DP_WFDS_SVC_IPCC_MAP_N_CFG_DONE &&
+	    dl_wfds->ipcc_dma_addr)
+		pld_smmu_unmap(qdf_ctx->dev, dl_wfds->ipcc_dma_addr,
+			       sizeof(uint32_t));
+
+	if (dl_wfds_state >= DP_WFDS_SVC_MEM_CONFIG_DONE) {
+		for (i = 0; i < dl_wfds->num_mem_arenas; i++) {
+			if (!dl_wfds->mem_arena_pages[i].num_pages)
+				continue;
+
+			qdf_mem_multi_pages_free(qdf_ctx,
+					&dl_wfds->mem_arena_pages[i],
+					0, false);
+		}
+
+		qdf_mem_free(dl_wfds->mem_arena_pages);
+		dl_wfds->mem_arena_pages = NULL;
+		dl_wfds->num_mem_arenas = 0;
+	}
+}
+
+QDF_STATUS dp_wfds_init(struct dp_direct_link_context *dp_direct_link_ctx)
+{
+	struct dp_direct_link_wfds_context *dl_wfds;
+	QDF_STATUS status;
+
+	dl_wfds = qdf_mem_malloc(sizeof(*dl_wfds));
+	if (!dl_wfds) {
+		status = QDF_STATUS_E_NOMEM;
+		goto out;
+	}
+
+	qdf_spinlock_create(&dl_wfds->wfds_event_list_lock);
+	qdf_list_create(&dl_wfds->wfds_event_list, 0);
+
+	status = qdf_create_work(0, &dl_wfds->wfds_work,
+				 dp_wfds_work, dl_wfds);
+	if (status != QDF_STATUS_SUCCESS) {
+		dp_err("DP QMI work create failed");
+		goto wfds_work_create_fail;
+	}
+
+	dl_wfds->wfds_wq = qdf_alloc_unbound_workqueue("dp_wfds_wq");
+	if (!dl_wfds->wfds_wq) {
+		dp_err("DP QMI workqueue allocate failed");
+		goto wfds_wq_alloc_fail;
+	}
+
+	qdf_atomic_set(&dl_wfds->wfds_state,
+		       DP_WFDS_SVC_DISCONNECTED);
+
+	status = wlan_qmi_wfds_init(dp_direct_link_ctx->dp_ctx->psoc);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		dp_err("WFDS QMI initialization failed %d", status);
+		goto qmi_wfds_init_fail;
+	}
+
+	dp_direct_link_ctx->dl_wfds = dl_wfds;
+	dl_wfds->direct_link_ctx = dp_direct_link_ctx;
+	gp_dl_wfds_ctx = dl_wfds;
+	dp_debug("WFDS QMI init successful");
+
+	return status;
+
+qmi_wfds_init_fail:
+	qdf_flush_workqueue(0, dl_wfds->wfds_wq);
+	qdf_destroy_workqueue(0, dl_wfds->wfds_wq);
+
+wfds_wq_alloc_fail:
+	qdf_flush_work(&dl_wfds->wfds_work);
+	qdf_destroy_work(0, &dl_wfds->wfds_work);
+
+wfds_work_create_fail:
+	qdf_spinlock_destroy(&dl_wfds->wfds_event_list_lock);
+	qdf_list_destroy(&dl_wfds->wfds_event_list);
+	qdf_mem_free(dl_wfds);
+
+out:
+	return status;
+}
+
+void dp_wfds_deinit(struct dp_direct_link_context *dp_direct_link_ctx)
+{
+	struct dp_direct_link_wfds_context *dl_wfds;
+
+	if (!dp_direct_link_ctx)
+		return;
+
+	dl_wfds = dp_direct_link_ctx->dl_wfds;
+
+	dp_debug("WFDS QMI deinit");
+
+	qdf_flush_workqueue(0, dl_wfds->wfds_wq);
+	qdf_destroy_workqueue(0, dl_wfds->wfds_wq);
+
+	qdf_flush_work(&dl_wfds->wfds_work);
+	qdf_destroy_work(0, &dl_wfds->wfds_work);
+
+	qdf_spinlock_destroy(&dl_wfds->wfds_event_list_lock);
+	qdf_list_destroy(&dl_wfds->wfds_event_list);
+
+	wlan_qmi_wfds_deinit(dp_direct_link_ctx->dp_ctx->psoc);
+	gp_dl_wfds_ctx = NULL;
+
+	qdf_mem_free(dl_wfds);
+}

+ 58 - 0
components/dp/dispatcher/inc/wlan_dp_ucfg_api.h

@@ -34,6 +34,7 @@
 #include <wlan_dp_public_struct.h>
 #include <cdp_txrx_misc.h>
 #include "wlan_dp_objmgr.h"
+#include "wlan_qmi_public_struct.h"
 
 #define DP_IGNORE_NUD_FAIL                      0
 #define DP_DISCONNECT_AFTER_NUD_FAIL            1
@@ -1358,6 +1359,42 @@ QDF_STATUS ucfg_dp_direct_link_init(struct wlan_objmgr_psoc *psoc);
  * Return: None
  */
 void ucfg_dp_direct_link_deinit(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * ucfg_dp_wfds_handle_request_mem_ind() - Process request memory indication
+ *  received from QMI server
+ * @mem_msg: pointer to memory request indication message
+ *
+ * Return: None
+ */
+void
+ucfg_dp_wfds_handle_request_mem_ind(struct wlan_qmi_wfds_mem_ind_msg *mem_msg);
+
+/**
+ * ucfg_dp_wfds_handle_ipcc_map_n_cfg_ind() - Process IPCC map and configure
+ *  indication received from QMI server
+ * @ipcc_msg: pointer to IPCC map and configure indication message
+ *
+ * Return: None
+ */
+void
+ucfg_dp_wfds_handle_ipcc_map_n_cfg_ind(struct wlan_qmi_wfds_ipcc_map_n_cfg_ind_msg *ipcc_msg);
+
+/**
+ * ucfg_dp_wfds_new_server() - New server callback triggered when service is up.
+ *  Connect to the service as part of this call.
+ *
+ * Return: QDF status
+ */
+QDF_STATUS ucfg_dp_wfds_new_server(void);
+
+/**
+ * ucfg_dp_wfds_del_server() - Del server callback triggered when service is
+ *  down.
+ *
+ * Return: None
+ */
+void ucfg_dp_wfds_del_server(void);
 #else
 static inline
 QDF_STATUS ucfg_dp_direct_link_init(struct wlan_objmgr_psoc *psoc)
@@ -1369,5 +1406,26 @@ static inline
 void ucfg_dp_direct_link_deinit(struct wlan_objmgr_psoc *psoc)
 {
 }
+
+#ifdef QMI_WFDS
+static inline void
+ucfg_dp_wfds_handle_request_mem_ind(struct wlan_qmi_wfds_mem_ind_msg *mem_msg)
+{
+}
+
+static inline void
+ucfg_dp_wfds_handle_ipcc_map_n_cfg_ind(struct wlan_qmi_wfds_ipcc_map_n_cfg_ind_msg *ipcc_msg)
+{
+}
+
+static inline QDF_STATUS ucfg_dp_wfds_new_server(void)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline void ucfg_dp_wfds_del_server(void)
+{
+}
+#endif
 #endif
 #endif /* _WLAN_DP_UCFG_API_H_ */

+ 22 - 0
components/dp/dispatcher/src/wlan_dp_ucfg_api.c

@@ -2350,4 +2350,26 @@ void ucfg_dp_direct_link_deinit(struct wlan_objmgr_psoc *psoc)
 
 	dp_direct_link_deinit(dp_ctx);
 }
+
+void
+ucfg_dp_wfds_handle_request_mem_ind(struct wlan_qmi_wfds_mem_ind_msg *mem_msg)
+{
+	dp_wfds_handle_request_mem_ind(mem_msg);
+}
+
+void
+ucfg_dp_wfds_handle_ipcc_map_n_cfg_ind(struct wlan_qmi_wfds_ipcc_map_n_cfg_ind_msg *ipcc_msg)
+{
+	dp_wfds_handle_ipcc_map_n_cfg_ind(ipcc_msg);
+}
+
+QDF_STATUS ucfg_dp_wfds_new_server(void)
+{
+	return dp_wfds_new_server();
+}
+
+void ucfg_dp_wfds_del_server(void)
+{
+	dp_wfds_del_server();
+}
 #endif

+ 8 - 0
os_if/qmi/src/os_if_qmi_wfds.c

@@ -18,6 +18,7 @@
 #include "os_if_qmi_wifi_driver_service_v01.h"
 #include <qdf_util.h>
 #include "wlan_qmi_public_struct.h"
+#include "wlan_dp_ucfg_api.h"
 
 static struct qmi_handle qmi_wfds;
 
@@ -363,6 +364,8 @@ static void os_if_qmi_wfds_request_mem_ind_cb(struct qmi_handle *qmi_hdl,
 		mem_ind_msg.mem_arena_info[i].num_entries =
 				src_info->mem_arena_info[i].num_entries;
 	}
+
+	ucfg_dp_wfds_handle_request_mem_ind(&mem_ind_msg);
 }
 
 /*
@@ -403,6 +406,8 @@ static void os_if_wfds_ipcc_map_n_cfg_ind_cb(struct qmi_handle *qmi_hdl,
 		ipcc_ind_msg.ipcc_ce_info[i].ipcc_trig_data =
 				src_info->ipcc_ce_info[i].ipcc_trig_data;
 	}
+
+	ucfg_dp_wfds_handle_ipcc_map_n_cfg_ind(&ipcc_ind_msg);
 }
 
 /**
@@ -425,6 +430,8 @@ os_if_qmi_wfds_new_server(struct qmi_handle *qmi_hdl,
 		return qdf_status_to_os_return(status);
 	}
 
+	status = ucfg_dp_wfds_new_server();
+
 	return qdf_status_to_os_return(status);
 }
 
@@ -440,6 +447,7 @@ static void
 os_if_qmi_wfds_del_server(struct qmi_handle *qmi_hdl,
 			  struct qmi_service *qmi_svc)
 {
+	ucfg_dp_wfds_del_server();
 }
 
 static struct qmi_msg_handler qmi_wfds_msg_handler[] = {