Browse Source

qcacld-3.0: Add bearer switch WMI interface changes

When there are more than one audio transport mediums
are available, there is a possibility to switch the
audio transport medium from one medium to another
medium.
To provide this support to switch the audio transport
medium, and to indicate the status of the bearer
switch to fw, add WMI interface changes.

Change-Id: I236e2d9a954191c104d56d286332ace644190e6e
CRs-Fixed: 3653962
Ashish Kumar Dhanotiya 1 year ago
parent
commit
793694f8f7

+ 9 - 2
Kbuild

@@ -1637,9 +1637,13 @@ MLME_OBJS += $(WFA_TGT_IF_DIR)/src/target_if_wfa_testcmd.o \
 ####### LL_SAP #######
 LL_SAP_DIR := components/umac/mlme/sap/ll_sap
 LL_SAP_OS_IF_DIR := os_if/mlme/sap/ll_sap
+LL_SAP_TARGET_IF_DIR := components/target_if/sap/ll_sap
+LL_SAP_WMI_DIR := components/wmi/
 
 LL_SAP_INC := -I$(WLAN_ROOT)/$(LL_SAP_DIR)/dispatcher/inc \
-		-I$(WLAN_ROOT)/$(LL_SAP_OS_IF_DIR)/inc
+		-I$(WLAN_ROOT)/$(LL_SAP_OS_IF_DIR)/inc \
+		-I$(WLAN_ROOT)/$(LL_SAP_TARGET_IF_DIR)/inc \
+		-I$(WLAN_ROOT)/$(LL_SAP_WMI_DIR)/inc
 
 MLME_INC += $(LL_SAP_INC)
 
@@ -1649,7 +1653,10 @@ MLME_OBJS += $(LL_SAP_DIR)/dispatcher/src/wlan_ll_sap_ucfg_api.o \
 		$(LL_SAP_DIR)/core/src/wlan_ll_sap_main.o \
 		$(LL_SAP_DIR)/core/src/wlan_ll_lt_sap_main.o \
 		$(LL_SAP_DIR)/core/src/wlan_ll_lt_sap_bearer_switch.o \
-		$(LL_SAP_OS_IF_DIR)/src/os_if_ll_sap.o
+		$(LL_SAP_OS_IF_DIR)/src/os_if_ll_sap.o \
+		$(LL_SAP_TARGET_IF_DIR)/src/target_if_ll_sap.o \
+		$(LL_SAP_WMI_DIR)/src/wmi_unified_ll_sap_api.o \
+		$(LL_SAP_WMI_DIR)/src/wmi_unified_ll_sap_tlv.o
 endif
 
 $(call add-wlan-objs,mlme,$(MLME_OBJS))

+ 55 - 0
components/target_if/sap/ll_sap/inc/target_if_ll_sap.h

@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2023 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.
+ */
+
+/**
+ * DOC: contains ll_lt_sap declarations specific to the bearer
+ * switch functionalities
+ */
+#include "wlan_ll_sap_public_structs.h"
+
+/**
+ * target_if_ll_sap_register_tx_ops() - register ll_lt_sap tx ops
+ * @tx_ops: pointer to ll_sap tx ops
+ *
+ * Return: None
+ */
+void target_if_ll_sap_register_tx_ops(struct wlan_ll_sap_tx_ops *tx_ops);
+
+/**
+ * target_if_ll_sap_register_rx_ops() - register ll_lt_sap rx ops
+ * @rx_ops: pointer to ll_sap rx ops
+ *
+ * Return: None
+ */
+void target_if_ll_sap_register_rx_ops(struct wlan_ll_sap_rx_ops *rx_ops);
+
+/**
+ * target_if_ll_sap_register_events() - register ll_lt_sap fw event handlers
+ * @psoc: pointer to psoc
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS target_if_ll_sap_register_events(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * target_if_ll_sap_deregister_events() - deregister ll_lt_sap fw event handlers
+ * @psoc: pointer to psoc
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+target_if_ll_sap_deregister_events(struct wlan_objmgr_psoc *psoc);
+

+ 149 - 0
components/target_if/sap/ll_sap/src/target_if_ll_sap.c

@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2023 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 "target_if.h"
+#include "target_if_ll_sap.h"
+#include "wlan_ll_sap_public_structs.h"
+#include "wmi_unified_ll_sap_api.h"
+#include "../../umac/mlme/sap/ll_sap/core/src/wlan_ll_sap_main.h"
+#include "wlan_ll_sap_api.h"
+
+/**
+ * target_if_send_audio_transport_switch_resp() - Send audio transport switch
+ * response to fw
+ * @psoc: pointer to psoc
+ * @req_type: Bearer switch request type
+ * @status: Status of the bearer switch request
+ *
+ * Return: pointer to tx ops
+ */
+static QDF_STATUS target_if_send_audio_transport_switch_resp(
+					struct wlan_objmgr_psoc *psoc,
+					enum bearer_switch_req_type req_type,
+					enum bearer_switch_status status)
+{
+	struct wmi_unified *wmi_handle;
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		target_if_err("wmi_handle is null.");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	return wmi_unified_audio_transport_switch_resp_send(wmi_handle,
+							    req_type, status);
+}
+
+static int target_if_send_audio_transport_switch_req_event_handler(
+							ol_scn_t scn,
+							uint8_t *event,
+							uint32_t len)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct ll_sap_psoc_priv_obj *psoc_ll_sap_obj;
+	enum bearer_switch_req_type req_type;
+	struct wmi_unified *wmi_handle;
+	struct wlan_ll_sap_rx_ops *rx_ops;
+	QDF_STATUS qdf_status;
+
+	psoc = target_if_get_psoc_from_scn_hdl(scn);
+	if (!psoc) {
+		target_if_err("psoc is null");
+		return -EINVAL;
+	}
+
+	wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
+	if (!wmi_handle) {
+		target_if_err("wmi_handle is null");
+		return -EINVAL;
+	}
+
+	psoc_ll_sap_obj = wlan_objmgr_psoc_get_comp_private_obj(
+							psoc,
+							WLAN_UMAC_COMP_LL_SAP);
+
+	if (!psoc_ll_sap_obj) {
+		target_if_err("psoc_ll_sap_obj is null");
+		return -EINVAL;
+	}
+
+	rx_ops = &psoc_ll_sap_obj->rx_ops;
+	if (!rx_ops || !rx_ops->audio_transport_switch_req) {
+		target_if_err("Invalid ll_sap rx ops");
+		return -EINVAL;
+	}
+
+	qdf_status = wmi_extract_audio_transport_switch_req_event(wmi_handle,
+								  event, len,
+								  &req_type);
+	if (QDF_IS_STATUS_ERROR(qdf_status)) {
+		target_if_err("parsing of event failed, %d", qdf_status);
+		return -EINVAL;
+	}
+	rx_ops->audio_transport_switch_req(psoc, req_type);
+
+	return 0;
+}
+
+void
+target_if_ll_sap_register_tx_ops(struct wlan_ll_sap_tx_ops *tx_ops)
+{
+	tx_ops->send_audio_transport_switch_resp =
+		target_if_send_audio_transport_switch_resp;
+}
+
+void
+target_if_ll_sap_register_rx_ops(struct wlan_ll_sap_rx_ops *rx_ops)
+{
+	rx_ops->audio_transport_switch_req =
+		wlan_ll_sap_fw_bearer_switch_req;
+}
+
+QDF_STATUS
+target_if_ll_sap_register_events(struct wlan_objmgr_psoc *psoc)
+{
+	QDF_STATUS ret;
+	wmi_unified_t handle = get_wmi_unified_hdl_from_psoc(psoc);
+
+	if (!handle) {
+		target_if_err("handle is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	ret = wmi_unified_register_event_handler(
+			handle,
+			wmi_audio_transport_switch_type_event_id,
+			target_if_send_audio_transport_switch_req_event_handler,
+			WMI_RX_SERIALIZER_CTX);
+	return ret;
+}
+
+QDF_STATUS
+target_if_ll_sap_deregister_events(struct wlan_objmgr_psoc *psoc)
+{
+	QDF_STATUS ret;
+	wmi_unified_t handle = get_wmi_unified_hdl_from_psoc(psoc);
+
+	if (!handle) {
+		target_if_err("handle is NULL");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	ret = wmi_unified_unregister_event_handler(
+			handle,
+			wmi_audio_transport_switch_type_event_id);
+	return ret;
+}

+ 68 - 9
components/umac/mlme/sap/ll_sap/core/src/wlan_ll_lt_sap_bearer_switch.c

@@ -81,6 +81,46 @@ bool __ll_lt_sap_is_bs_req_valid(struct wlan_bearer_switch_request *bs_req,
 	return true;
 }
 
+/**
+ * ll_lt_sap_deliver_audio_transport_switch_resp_to_fw() - Deliver audio
+ * transport switch response to FW
+ * @vdev: Vdev on which the request is received
+ * @req_type: Transport switch type for which the response is received
+ * @status: Status of the response
+ *
+ * Return: None
+ */
+static void
+ll_lt_sap_deliver_audio_transport_switch_resp_to_fw(
+					struct wlan_objmgr_vdev *vdev,
+					enum bearer_switch_req_type req_type,
+					enum bearer_switch_status status)
+{
+	struct wlan_objmgr_psoc *psoc;
+	struct ll_sap_psoc_priv_obj *psoc_ll_sap_obj;
+	struct wlan_ll_sap_tx_ops *tx_ops;
+
+	psoc = wlan_vdev_get_psoc(vdev);
+
+	psoc_ll_sap_obj = wlan_objmgr_psoc_get_comp_private_obj(
+						psoc,
+						WLAN_UMAC_COMP_LL_SAP);
+
+	if (!psoc_ll_sap_obj) {
+		ll_sap_err("psoc_ll_sap_obj is null");
+		return;
+	}
+
+	tx_ops = &psoc_ll_sap_obj->tx_ops;
+
+	if (!tx_ops->send_audio_transport_switch_resp) {
+		ll_sap_err("deliver_audio_transport_switch_resp op is NULL");
+		return;
+	}
+
+	tx_ops->send_audio_transport_switch_resp(psoc, req_type, status);
+}
+
 /**
  * bs_req_timeout_cb() - Callback which will be invoked on bearer switch req
  * timeout
@@ -245,7 +285,11 @@ ll_lt_sap_bs_increament_ref_count(struct bearer_switch_info *bs_ctx,
 	uint32_t total_ref_count;
 
 	total_ref_count = qdf_atomic_inc_return(&bs_ctx->total_ref_count);
-	ref_count = qdf_atomic_inc_return(&bs_ctx->ref_count[bs_req->vdev_id][bs_req->source]);
+	if (bs_req->source == BEARER_SWITCH_REQ_FW)
+		ref_count = qdf_atomic_inc_return(&bs_ctx->fw_ref_count);
+	else
+		ref_count = qdf_atomic_inc_return(
+			&bs_ctx->ref_count[bs_req->vdev_id][bs_req->source]);
 
 	ll_sap_nofl_debug(BS_PREFIX_FMT "req_vdev %d src %d ref_count %d Total ref count %d",
 			  BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev),
@@ -276,16 +320,27 @@ ll_lt_sap_bs_decreament_ref_count(struct bearer_switch_info *bs_ctx,
 	 * module did not requested for wlan to non wlan transition earlier, so
 	 * reject this operation.
 	 */
-	if (!qdf_atomic_read(&bs_ctx->ref_count[bs_req->vdev_id][bs_req->source])) {
+	if (bs_req->source == BEARER_SWITCH_REQ_FW) {
+		if (!qdf_atomic_read(&bs_ctx->fw_ref_count)) {
+			ll_sap_debug(BS_PREFIX_FMT "ref_count is zero for FW",
+				     BS_PREFIX_REF(
+						wlan_vdev_get_id(bs_ctx->vdev),
+						bs_req->request_id));
+			return QDF_STATUS_E_INVAL;
+		}
+		ref_count = qdf_atomic_dec_return(&bs_ctx->fw_ref_count);
+	} else if (!qdf_atomic_read(
+			&bs_ctx->ref_count[bs_req->vdev_id][bs_req->source])) {
 		ll_sap_debug(BS_PREFIX_FMT "req_vdev %d src %d ref_count is zero",
 			     BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev),
 					   bs_req->request_id),
 			     bs_req->vdev_id, bs_req->source);
 		return QDF_STATUS_E_INVAL;
+	} else {
+		ref_count = qdf_atomic_dec_return(
+			&bs_ctx->ref_count[bs_req->vdev_id][bs_req->source]);
 	}
 	total_ref_count = qdf_atomic_dec_return(&bs_ctx->total_ref_count);
-	ref_count = qdf_atomic_dec_return(&bs_ctx->ref_count[bs_req->vdev_id][bs_req->source]);
-
 	ll_sap_nofl_debug(BS_PREFIX_FMT "req_vdev %d src %d ref_count %d Total ref count %d",
 			  BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev),
 					bs_req->request_id),
@@ -850,11 +905,6 @@ ll_lt_sap_handle_bs_to_non_wlan_in_wlan_state(
 		ll_sap_err(BS_PREFIX_FMT "Failed to start timer",
 			   BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev),
 					 bs_req->request_id));
-	/*
-	 * Todo, upon receiving response for non-wlan request, deliver event
-	 * WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN_COMPLETED from the vendor command
-	 * path
-	 */
 }
 
 /**
@@ -957,6 +1007,12 @@ ll_lt_sap_handle_bs_to_wlan_timeout(
 {
 	bs_sm_transition_to(bs_ctx, BEARER_WLAN);
 
+	if (bs_req->source == BEARER_SWITCH_REQ_FW)
+		ll_lt_sap_deliver_audio_transport_switch_resp_to_fw(
+							bs_ctx->vdev,
+							bs_req->req_type,
+							WLAN_BS_STATUS_TIMEOUT);
+
 	bs_ctx->last_status = QDF_STATUS_E_TIMEOUT;
 
 	ll_lt_sap_switch_to_non_wlan_from_wlan(bs_ctx);
@@ -1717,6 +1773,9 @@ ll_lt_sap_deliver_audio_transport_switch_resp(
 				enum bearer_switch_req_type req_type,
 				enum bearer_switch_status status)
 {
+	ll_lt_sap_deliver_audio_transport_switch_resp_to_fw(vdev, req_type,
+							   status);
+
 	if (req_type == WLAN_BS_REQ_TO_NON_WLAN)
 		ll_lt_sap_deliver_non_wlan_audio_transport_switch_resp(
 								vdev,

+ 46 - 6
components/umac/mlme/sap/ll_sap/core/src/wlan_ll_sap_main.c

@@ -18,30 +18,60 @@
 #include <wlan_objmgr_global_obj.h>
 #include "qca_vendor.h"
 #include "wlan_ll_lt_sap_main.h"
+#include "target_if_ll_sap.h"
 
 struct ll_sap_ops *global_ll_sap_ops;
 
 static QDF_STATUS ll_sap_psoc_obj_created_notification(struct wlan_objmgr_psoc *psoc, void *arg_list)
 {
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct ll_sap_psoc_priv_obj *ll_sap_psoc_obj;
+
+	ll_sap_psoc_obj = qdf_mem_malloc(sizeof(*ll_sap_psoc_obj));
+	if (!ll_sap_psoc_obj)
+		return QDF_STATUS_E_NOMEM;
+
+	status = wlan_objmgr_psoc_component_obj_attach(psoc,
+						       WLAN_UMAC_COMP_LL_SAP,
+						       ll_sap_psoc_obj,
+						       QDF_STATUS_SUCCESS);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		ll_sap_err("ll_sap obj attach with psoc failed");
+		goto ll_sap_psoc_obj_fail;
+	}
+
+	target_if_ll_sap_register_tx_ops(&ll_sap_psoc_obj->tx_ops);
+	target_if_ll_sap_register_rx_ops(&ll_sap_psoc_obj->rx_ops);
 
 	ll_sap_debug("ll sap psoc object created");
 
-	/* attach ll_sap_psoc object which will contain cfg items,
-	 * tx and rx ops
-	 */
+	return status;
+
+ll_sap_psoc_obj_fail:
+	qdf_mem_free(ll_sap_psoc_obj);
+
 	return status;
 }
 
 static QDF_STATUS ll_sap_psoc_obj_destroyed_notification(struct wlan_objmgr_psoc *psoc, void *arg_list)
 {
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct ll_sap_psoc_priv_obj *ll_sap_psoc_obj;
+
+	ll_sap_psoc_obj =
+		wlan_objmgr_psoc_get_comp_private_obj(psoc,
+						      WLAN_UMAC_COMP_LL_SAP);
+
+	status = wlan_objmgr_psoc_component_obj_detach(psoc,
+						       WLAN_UMAC_COMP_LL_SAP,
+						       ll_sap_psoc_obj);
+	if (QDF_IS_STATUS_ERROR(status))
+		ll_sap_err("ll_sap detach failed");
+
+	qdf_mem_free(ll_sap_psoc_obj);
 
 	ll_sap_debug("ll sap psoc object destroyed");
 
-	/* detach ll_sap_psoc object which will contain cfg items,
-	 * tx and rx ops
-	 */
 	return status;
 }
 
@@ -238,3 +268,13 @@ struct ll_sap_ops *ll_sap_get_osif_cbk(void)
 {
 	return global_ll_sap_ops;
 }
+
+QDF_STATUS ll_sap_psoc_enable(struct wlan_objmgr_psoc *psoc)
+{
+	return target_if_ll_sap_register_events(psoc);
+}
+
+QDF_STATUS ll_sap_psoc_disable(struct wlan_objmgr_psoc *psoc)
+{
+	return target_if_ll_sap_deregister_events(psoc);
+}

+ 26 - 0
components/umac/mlme/sap/ll_sap/core/src/wlan_ll_sap_main.h

@@ -36,6 +36,16 @@
 #define ll_sap_nofl_debug(params...) \
 	QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_LL_SAP, params)
 
+/**
+ * struct ll_sap_psoc_priv_obj - ll_sap private psoc obj
+ * @tx_ops: Tx ops registered with Target IF interface
+ * @rx_ops: Rx  ops registered with Target IF interface
+ */
+struct ll_sap_psoc_priv_obj {
+	struct wlan_ll_sap_tx_ops tx_ops;
+	struct wlan_ll_sap_rx_ops rx_ops;
+};
+
 /**
  * struct ll_sap_vdev_priv_obj - ll sap private vdev obj
  * @bearer_switch_ctx: Bearer switch context
@@ -102,4 +112,20 @@ void ll_sap_unregister_os_if_cb(void);
  */
 struct ll_sap_ops *ll_sap_get_osif_cbk(void);
 
+/**
+ * ll_sap_psoc_enable() - Enable ll_lt_sap psoc
+ * @psoc: objmgr psoc pointer
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ll_sap_psoc_enable(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * ll_sap_psoc_disable() - Disable ll_lt_sap psoc
+ * @psoc: objmgr psoc pointer
+ *
+ * Return: None
+ */
+QDF_STATUS ll_sap_psoc_disable(struct wlan_objmgr_psoc *psoc);
+
 #endif /* _WLAN_LL_SAP_MAIN_H_ */

+ 10 - 0
components/umac/mlme/sap/ll_sap/dispatcher/inc/wlan_ll_sap_api.h

@@ -162,6 +162,16 @@ wlan_get_ll_lt_sap_restart_freq(struct wlan_objmgr_pdev *pdev,
 				uint8_t vdev_id,
 				enum sap_csa_reason_code *csa_reason);
 
+/**
+ * wlan_ll_sap_fw_bearer_switch_req() - FW bearer switch request
+ * @psoc: Pointer to psoc object
+ * @req_type: Bearer switch request type
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+wlan_ll_sap_fw_bearer_switch_req(struct wlan_objmgr_psoc *psoc,
+				 enum bearer_switch_req_type req_type);
 #else
 static inline wlan_bs_req_id
 wlan_ll_lt_sap_bearer_switch_get_id(struct wlan_objmgr_vdev *vdev)

+ 27 - 0
components/umac/mlme/sap/ll_sap/dispatcher/inc/wlan_ll_sap_public_structs.h

@@ -47,10 +47,12 @@ enum bearer_switch_req_type {
  * @WLAN_BS_STATUS_REJECTED: Bearer switch request rejected
  * @WLAN_BS_STATUS_COMPLETED: Bearer switch request completed
  * @WLAN_BS_STATUS_INVALID: Invalid bearer switch request
+ * @WLAN_BS_STATUS_TIMEOUT: Bearer switch request timedout
  */
 enum bearer_switch_status {
 	WLAN_BS_STATUS_REJECTED = 0,
 	WLAN_BS_STATUS_COMPLETED = 1,
+	WLAN_BS_STATUS_TIMEOUT = 2,
 	WLAN_BS_STATUS_INVALID,
 };
 
@@ -152,6 +154,31 @@ struct wlan_bearer_switch_request {
 	void *arg;
 };
 
+/**
+ * struct wlan_ll_sap_tx_ops - defines southbound tx callbacks for
+ * LL_SAP (low latency sap) component
+ * @send_audio_transport_switch_resp: function pointer to indicate audio
+ * transport switch response to FW
+ */
+struct wlan_ll_sap_tx_ops {
+	QDF_STATUS (*send_audio_transport_switch_resp)(
+					struct wlan_objmgr_psoc *psoc,
+					enum bearer_switch_req_type req_type,
+					enum bearer_switch_status status);
+};
+
+/**
+ * struct wlan_ll_sap_rx_ops - defines southbound rx callbacks for
+ * LL_SAP (low latency SAP) component
+ * @audio_transport_switch_req: function pointer to indicate audio
+ * transport switch request from FW
+ */
+struct wlan_ll_sap_rx_ops {
+	QDF_STATUS (*audio_transport_switch_req)(
+					struct wlan_objmgr_psoc *psoc,
+					enum bearer_switch_req_type req_type);
+};
+
 /**
  * struct ll_sap_ops - ll_sap osif callbacks
  * @ll_sap_send_audio_transport_switch_req_cb: Send audio transport request to

+ 26 - 0
components/umac/mlme/sap/ll_sap/dispatcher/inc/wlan_ll_sap_ucfg_api.h

@@ -89,6 +89,22 @@ void ucfg_ll_sap_register_cb(struct ll_sap_ops *ll_sap_global_ops);
  */
 void ucfg_ll_sap_unregister_cb(void);
 
+/**
+ * ucfg_ll_sap_psoc_enable() - Enable ll_lt_sap psoc
+ * @psoc: objmgr psoc pointer
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_ll_sap_psoc_enable(struct wlan_objmgr_psoc *psoc);
+
+/**
+ * ucfg_ll_sap_psoc_disable() - Disable ll_lt_sap psoc
+ * @psoc: objmgr psoc pointer
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS ucfg_ll_sap_psoc_disable(struct wlan_objmgr_psoc *psoc);
+
 #else
 static inline QDF_STATUS ucfg_ll_sap_init(void)
 {
@@ -129,6 +145,16 @@ static inline void ucfg_ll_sap_unregister_cb(void)
 {
 }
 
+static inline QDF_STATUS ucfg_ll_sap_psoc_enable(struct wlan_objmgr_psoc *psoc)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline QDF_STATUS ucfg_ll_sap_psoc_disable(struct wlan_objmgr_psoc *psoc)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
 #endif /* WLAN_FEATURE_LL_LT_SAP */
 #endif /* _WLAN_LL_SAP_UCFG_API_H_ */
 

+ 41 - 0
components/umac/mlme/sap/ll_sap/dispatcher/src/wlan_ll_sap_api.c

@@ -222,3 +222,44 @@ get_new_ll_lt_sap_freq:
 		     vdev_id, chan_freq, restart_freq, *csa_reason);
 	return restart_freq;
 }
+
+static void fw_bearer_switch_requester_cb(struct wlan_objmgr_psoc *psoc,
+					  uint8_t vdev_id,
+					  wlan_bs_req_id request_id,
+					  QDF_STATUS status,
+					  uint32_t req_value,
+					  void *request_params)
+{
+	/*
+	 * Drop this response as all the responses to the FW is always
+	 * forwarded
+	 */
+}
+
+QDF_STATUS
+wlan_ll_sap_fw_bearer_switch_req(struct wlan_objmgr_psoc *psoc,
+				 enum bearer_switch_req_type req_type)
+{
+	struct wlan_bearer_switch_request bs_request = {0};
+	QDF_STATUS status;
+	uint8_t ll_lt_sap_vdev_id;
+
+	ll_lt_sap_vdev_id = wlan_policy_mgr_get_ll_lt_sap_vdev_id(psoc);
+
+	bs_request.vdev_id = ll_lt_sap_vdev_id;
+	bs_request.request_id = ll_lt_sap_bearer_switch_get_id(psoc);
+	bs_request.req_type = req_type;
+	bs_request.source = BEARER_SWITCH_REQ_FW;
+	bs_request.requester_cb = fw_bearer_switch_requester_cb;
+
+	if (req_type == WLAN_BS_REQ_TO_WLAN)
+		status = ll_lt_sap_switch_bearer_to_wlan(psoc, &bs_request);
+
+	else
+		status = ll_lt_sap_switch_bearer_to_ble(psoc, &bs_request);
+
+	if (QDF_IS_STATUS_ERROR(status))
+		return QDF_STATUS_E_ALREADY;
+
+	return QDF_STATUS_SUCCESS;
+}

+ 10 - 0
components/umac/mlme/sap/ll_sap/dispatcher/src/wlan_ll_sap_ucfg_api.c

@@ -64,3 +64,13 @@ void ucfg_ll_sap_unregister_cb(void)
 {
 	ll_sap_unregister_os_if_cb();
 }
+
+QDF_STATUS ucfg_ll_sap_psoc_enable(struct wlan_objmgr_psoc *psoc)
+{
+	return ll_sap_psoc_enable(psoc);
+}
+
+QDF_STATUS ucfg_ll_sap_psoc_disable(struct wlan_objmgr_psoc *psoc)
+{
+	return ll_sap_psoc_disable(psoc);
+}

+ 51 - 0
components/wmi/inc/wmi_unified_ll_sap_api.h

@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2023 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 "qdf_status.h"
+#include "wlan_ll_sap_public_structs.h"
+#include "wmi_unified_param.h"
+
+#ifdef WLAN_FEATURE_LL_LT_SAP
+/**
+ * wmi_unified_audio_transport_switch_resp_send() - Send audio transport switch
+ * response to fw
+ * @wmi_hdl: WMI handle
+ * @req_type: Bearer switch request type
+ * @status: Status of the bearer switch request
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wmi_unified_audio_transport_switch_resp_send(
+					wmi_unified_t wmi_hdl,
+					enum bearer_switch_req_type req_type,
+					enum bearer_switch_status status);
+
+/**
+ * wmi_extract_audio_transport_switch_req_event() - Extract audio transport
+ * switch request from fw
+ * @wmi_handle: WMI handle
+ * @event: WMI event from fw
+ * @len: Length of the event
+ * @req_type: Type of the bearer switch request from fw
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+wmi_extract_audio_transport_switch_req_event(
+				wmi_unified_t wmi_handle,
+				uint8_t *event, uint32_t len,
+				enum bearer_switch_req_type *req_type);
+#endif

+ 46 - 0
components/wmi/src/wmi_unified_ll_sap_api.c

@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2023 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 <wmi.h>
+#include <wmi_unified_priv.h>
+#include "wmi_unified_ll_sap_api.h"
+#include "wmi_unified_param.h"
+
+QDF_STATUS wmi_unified_audio_transport_switch_resp_send(
+					wmi_unified_t wmi_hdl,
+					enum bearer_switch_req_type req_type,
+					enum bearer_switch_status status)
+{
+	if (wmi_hdl->ops->send_audio_transport_switch_resp)
+		return wmi_hdl->ops->send_audio_transport_switch_resp(wmi_hdl,
+								      req_type,
+								      status);
+
+	return QDF_STATUS_E_FAILURE;
+}
+
+QDF_STATUS
+wmi_extract_audio_transport_switch_req_event(
+				wmi_unified_t wmi_handle,
+				uint8_t *event, uint32_t len,
+				enum bearer_switch_req_type *req_type)
+{
+	if (wmi_handle->ops->extract_audio_transport_switch_req_event)
+		return wmi_handle->ops->extract_audio_transport_switch_req_event(
+					wmi_handle, event, len, req_type);
+	return QDF_STATUS_E_FAILURE;
+}
+

+ 130 - 0
components/wmi/src/wmi_unified_ll_sap_tlv.c

@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2023 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 "wmi_unified.h"
+#include "wmi_unified_param.h"
+#include <wmi_unified_priv.h>
+#include <wmi.h>
+#include "wmi_unified_ll_sap_tlv.h"
+
+static WMI_AUDIO_TRANSPORT_SWITCH_RESPONSE_STATUS
+wmi_convert_host_to_target_audio_switch_status(enum bearer_switch_status status)
+{
+	if (status == WLAN_BS_STATUS_COMPLETED)
+		return WMI_AUDIO_TRANSPORT_SWITCH_STATUS_SUCCESS;
+	else if (status == WLAN_BS_STATUS_REJECTED)
+		return WMI_AUDIO_TRANSPORT_SWITCH_STATUS_FAIL;
+	else
+		return WMI_AUDIO_TRANSPORT_SWITCH_STATUS_TIMEOUT;
+}
+
+static WMI_AUDIO_TRANSPORT_SWITCH_TYPE
+wmi_convert_host_to_target_audio_switch_type(
+					enum bearer_switch_req_type req_type)
+{
+	if (req_type == WLAN_BS_REQ_TO_NON_WLAN)
+		return WMI_AUDIO_TRANSPORT_SWITCH_TYPE_NON_WLAN;
+	else
+		return WMI_AUDIO_TRANSPORT_SWITCH_TYPE_WLAN;
+}
+
+static enum bearer_switch_req_type
+wmi_convert_target_to_host_audio_switch_type(uint32_t req_type)
+{
+	if (req_type == WMI_AUDIO_TRANSPORT_SWITCH_TYPE_NON_WLAN)
+		return WLAN_BS_REQ_TO_NON_WLAN;
+	else if (req_type == WMI_AUDIO_TRANSPORT_SWITCH_TYPE_WLAN)
+		return WLAN_BS_REQ_TO_WLAN;
+	else
+		return WLAN_BS_REQ_INVALID;
+}
+
+QDF_STATUS audio_transport_switch_resp_tlv(
+					wmi_unified_t wmi_hdl,
+					enum bearer_switch_req_type req_type,
+					enum bearer_switch_status status)
+{
+	wmi_audio_transport_switch_resp_status_cmd_fixed_param *cmd;
+	wmi_buf_t buf;
+	QDF_STATUS qdf_status;
+
+	buf = wmi_buf_alloc(wmi_hdl, sizeof(*cmd));
+	if (!buf)
+		return QDF_STATUS_E_FAILURE;
+
+	cmd = (wmi_audio_transport_switch_resp_status_cmd_fixed_param *)wmi_buf_data(buf);
+
+	WMITLV_SET_HDR(
+	&cmd->tlv_header,
+	WMITLV_TAG_STRUC_wmi_audio_transport_switch_resp_status_cmd_fixed_param,
+	WMITLV_GET_STRUCT_TLVLEN
+	(wmi_audio_transport_switch_resp_status_cmd_fixed_param));
+
+	cmd->switch_type = wmi_convert_host_to_target_audio_switch_type(
+								req_type);
+	cmd->switch_response_status =
+		wmi_convert_host_to_target_audio_switch_status(status);
+
+	wmi_nofl_debug("LL_LT_SAP Audio switch type %d status %d",
+		       cmd->switch_type, cmd->switch_response_status);
+
+	qdf_status = wmi_unified_cmd_send(
+				wmi_hdl, buf, sizeof(*cmd),
+				WMI_AUDIO_TRANSPORT_SWITCH_RESP_STATUS_CMDID);
+
+	if (QDF_IS_STATUS_ERROR(qdf_status))
+		wmi_buf_free(buf);
+
+	return qdf_status;
+}
+
+QDF_STATUS
+extract_audio_transport_switch_req_event_tlv(
+				wmi_unified_t wmi_handle,
+				uint8_t *event, uint32_t len,
+				enum bearer_switch_req_type *req_type)
+{
+	WMI_AUDIO_TRANSPORT_SWITCH_TYPE_EVENTID_param_tlvs *param_buf = NULL;
+	wmi_audio_transport_switch_type_event_fixed_param *fixed_param = NULL;
+
+	if (!event || !len) {
+		wmi_debug("Empty transport switch request event");
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	param_buf = (WMI_AUDIO_TRANSPORT_SWITCH_TYPE_EVENTID_param_tlvs *)event;
+	if (!param_buf) {
+		wmi_err("received null buf from target");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	fixed_param = (wmi_audio_transport_switch_type_event_fixed_param *)
+					param_buf->fixed_param;
+	if (!fixed_param) {
+		wmi_err("received null event data from target");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	*req_type = wmi_convert_target_to_host_audio_switch_type(
+						fixed_param->switch_type);
+
+	wmi_nofl_debug("LL_LT_SAP FW requested bearer switch to %d", *req_type);
+
+	if (*req_type == WLAN_BS_REQ_TO_WLAN)
+		return QDF_STATUS_E_INVAL;
+
+	return QDF_STATUS_SUCCESS;
+}

+ 51 - 0
components/wmi/src/wmi_unified_ll_sap_tlv.h

@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2023 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 "qdf_status.h"
+#include "wlan_ll_sap_public_structs.h"
+#include "wmi_unified_param.h"
+
+#ifdef WLAN_FEATURE_LL_LT_SAP
+/**
+ * audio_transport_switch_resp_tlv() - AUdio transport switch response tlv
+ * @wmi_hdl: WMI handle
+ * @req_type: Bearer switch request type
+ * @status: Bearer switch status
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+audio_transport_switch_resp_tlv(wmi_unified_t wmi_hdl,
+				enum bearer_switch_req_type req_type,
+				enum bearer_switch_status status);
+
+/**
+ * extract_audio_transport_switch_req_event_tlv() - AUdio transport switch
+ * request tlv
+ * @wmi_handle: WMI handle
+ * @event: Event received from the FW
+ * @len: Length of the event
+ * @req_type: Bearer switch request type
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS
+extract_audio_transport_switch_req_event_tlv(
+				wmi_unified_t wmi_handle,
+				uint8_t *event, uint32_t len,
+				enum bearer_switch_req_type *req_type);
+
+#endif

+ 21 - 1
components/wmi/src/wmi_unified_mlme_tlv.c

@@ -22,6 +22,7 @@
 #include <wmi_unified_priv.h>
 #include "wmi.h"
 #include "wlan_mlme_api.h"
+#include "wmi_unified_ll_sap_tlv.h"
 
 static QDF_STATUS csa_event_status_ind_tlv(wmi_unified_t wmi_handle,
 					   struct csa_event_status_ind params)
@@ -53,6 +54,25 @@ static QDF_STATUS csa_event_status_ind_tlv(wmi_unified_t wmi_handle,
 	return status;
 }
 
+#ifdef WLAN_FEATURE_LL_LT_SAP
+/**
+ * wmi_mlme_attach_ll_lt_sap_tlv() - attach ll_lt_sap tlv handlers
+ * @ops: wmi ops
+ *
+ * Return: void
+ */
+static void wmi_mlme_attach_ll_lt_sap_tlv(struct wmi_ops *ops)
+{
+	ops->send_audio_transport_switch_resp = audio_transport_switch_resp_tlv;
+	ops->extract_audio_transport_switch_req_event =
+				extract_audio_transport_switch_req_event_tlv;
+}
+#else
+static inline void wmi_mlme_attach_ll_lt_sap_tlv(struct wmi_ops *ops)
+{
+}
+#endif
+
 /**
  * wmi_mlme_attach_tlv() - attach MLME tlv handlers
  * @wmi_handle: wmi handle
@@ -64,5 +84,5 @@ void wmi_mlme_attach_tlv(wmi_unified_t wmi_handle)
 	struct wmi_ops *ops = wmi_handle->ops;
 
 	ops->send_csa_event_status_ind = csa_event_status_ind_tlv;
+	wmi_mlme_attach_ll_lt_sap_tlv(ops);
 }
-

+ 2 - 0
core/hdd/src/wlan_hdd_main.c

@@ -19391,10 +19391,12 @@ void hdd_component_psoc_enable(struct wlan_objmgr_psoc *psoc)
 	ucfg_tdls_psoc_enable(psoc);
 	ucfg_fwol_psoc_enable(psoc);
 	ucfg_action_oui_psoc_enable(psoc);
+	ucfg_ll_sap_psoc_enable(psoc);
 }
 
 void hdd_component_psoc_disable(struct wlan_objmgr_psoc *psoc)
 {
+	ucfg_ll_sap_psoc_disable(psoc);
 	ucfg_action_oui_psoc_disable(psoc);
 	ucfg_fwol_psoc_disable(psoc);
 	ucfg_tdls_psoc_disable(psoc);

+ 5 - 0
wlan_qcacld3_modules.bzl

@@ -247,6 +247,7 @@ _fixed_ipaths = [
     "components/target_if/pkt_capture/inc",
     "components/target_if/pmo/inc",
     "components/target_if/pmo/src",
+    "components/target_if/sap/ll_sap/inc",
     "components/target_if/tdls/inc",
     "components/target_if/wfa_config/inc",
     "components/tdls/dispatcher/inc",
@@ -263,6 +264,7 @@ _fixed_ipaths = [
     "components/wifi_pos/core/inc",
     "components/wifi_pos/dispatcher/inc",
     "components/wmi/inc",
+    "components/wmi/src",
     "core/bmi/inc",
     "core/cds/inc",
     "core/cds/src",
@@ -2109,11 +2111,14 @@ _conditional_srcs = {
     },
     "CONFIG_WLAN_FEATURE_LL_LT_SAP": {
         True: [
+            "components/target_if/sap/ll_sap/src/target_if_ll_sap.c",
             "components/umac/mlme/sap/ll_sap/dispatcher/src/wlan_ll_sap_api.c",
             "components/umac/mlme/sap/ll_sap/dispatcher/src/wlan_ll_sap_ucfg_api.c",
             "components/umac/mlme/sap/ll_sap/core/src/wlan_ll_lt_sap_bearer_switch.c",
             "components/umac/mlme/sap/ll_sap/core/src/wlan_ll_lt_sap_main.c",
             "components/umac/mlme/sap/ll_sap/core/src/wlan_ll_sap_main.c",
+            "components/wmi/src/wmi_unified_ll_sap_api.c",
+            "components/wmi/src/wmi_unified_ll_sap_tlv.c",
             "components/cmn_services/policy_mgr/src/wlan_policy_mgr_ll_sap.c",
             "os_if/mlme/sap/ll_sap/src/os_if_ll_sap.c",
         ],