Kaynağa Gözat

qcacmn: Save quiet status to sta context of MLO mgr

Save quiet status of indicated link to sta contect of MLO mgr. Any link
should check quiet status of MLO connection, then decide whether it
can trigger inactivity to FW or not.

Change-Id: Ic294bbe6452030b6cae495ca0dd3e504416e2c9e
CRs-Fixed: 3117825
Bing Sun 3 yıl önce
ebeveyn
işleme
7ee4663048

+ 16 - 0
umac/cmn_services/obj_mgr/inc/wlan_objmgr_vdev_obj.h

@@ -1795,4 +1795,20 @@ wlan_objmgr_vdev_trace_del_ref_list(struct wlan_objmgr_vdev *vdev)
 QDF_STATUS wlan_vdev_get_bss_peer_mac(struct wlan_objmgr_vdev *vdev,
 				      struct qdf_mac_addr *bss_peer_mac);
 
+#ifdef WLAN_FEATURE_11BE_MLO
+/**
+ * wlan_vdev_get_bss_peer_mld_mac() - to get bss peer mld mac address
+ * @vdev: pointer to vdev
+ * @mld_mac: pointer to mld mac address
+ *
+ * This API is used to get mld mac address of peer.
+ *
+ * Context: Any context.
+ *
+ * Return: QDF_STATUS based on overall success
+ */
+QDF_STATUS wlan_vdev_get_bss_peer_mld_mac(struct wlan_objmgr_vdev *vdev,
+					  struct qdf_mac_addr *mld_mac);
+#endif
+
 #endif /* _WLAN_OBJMGR_VDEV_OBJ_H_*/

+ 29 - 1
umac/cmn_services/obj_mgr/src/wlan_objmgr_vdev_obj.c

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-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
@@ -1439,3 +1439,31 @@ QDF_STATUS wlan_vdev_get_bss_peer_mac(struct wlan_objmgr_vdev *vdev,
 
 	return QDF_STATUS_SUCCESS;
 }
+
+#ifdef WLAN_FEATURE_11BE_MLO
+QDF_STATUS wlan_vdev_get_bss_peer_mld_mac(struct wlan_objmgr_vdev *vdev,
+					  struct qdf_mac_addr *mld_mac)
+{
+	struct wlan_objmgr_peer *peer;
+
+	if (!vdev) {
+		obj_mgr_err("vdev is null");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_MLME_OBJMGR_ID);
+	if (!peer) {
+		obj_mgr_err("not able to find bss peer for vdev %d",
+			    wlan_vdev_get_id(vdev));
+		return QDF_STATUS_E_INVAL;
+	}
+	wlan_peer_obj_lock(peer);
+	qdf_mem_copy(mld_mac->bytes, wlan_peer_mlme_get_mldaddr(peer),
+		     QDF_MAC_ADDR_SIZE);
+	wlan_peer_obj_unlock(peer);
+
+	wlan_objmgr_peer_release_ref(peer, WLAN_MLME_OBJMGR_ID);
+
+	return QDF_STATUS_SUCCESS;
+}
+#endif

+ 33 - 0
umac/cmn_services/utils/inc/wlan_utility.h

@@ -342,6 +342,39 @@ struct wlan_channel *wlan_vdev_get_active_channel
 bool wlan_get_connected_vdev_by_bssid(struct wlan_objmgr_pdev *pdev,
 				      uint8_t *bssid, uint8_t *vdev_id);
 
+/**
+ * wlan_get_connected_vdev_from_psoc_by_bssid() - check/get any vdev
+ *                                                connected on bssid
+ * @psoc: psoc object
+ * @bssid: bssid to be checked
+ * @vdev_id: vdev id
+ *
+ * This function will loop through all the vdev in psoc and find/return the
+ * vdev which is connected to bssid provided.
+ *
+ * Return: bool
+ */
+bool wlan_get_connected_vdev_from_psoc_by_bssid(struct wlan_objmgr_psoc *psoc,
+						uint8_t *bssid,
+						uint8_t *vdev_id);
+
+#ifdef WLAN_FEATURE_11BE_MLO
+/**
+ * wlan_get_connected_vdev_by_mld_addr() - check/get any vdev
+ *                                         connected on mld mac
+ * @psoc: psoc object
+ * @mld_mac: mld mac to be checked
+ * @vdev_id: vdev id
+ *
+ * This function will loop through all the vdev in psoc and find/return the
+ * first vdev which is connected to mld mac provided.
+ *
+ * Return: bool
+ */
+bool wlan_get_connected_vdev_by_mld_addr(struct wlan_objmgr_psoc *psoc,
+					 uint8_t *mld_mac, uint8_t *vdev_id);
+#endif
+
 /**
  * wlan_util_stats_get_rssi() - API to get rssi in dbm
  * @db2dbm_enabled: If db2dbm capability is enabled

+ 78 - 4
umac/cmn_services/utils/src/wlan_utility.c

@@ -569,13 +569,12 @@ static void wlan_get_connected_vdev_handler(struct wlan_objmgr_psoc *psoc,
 	}
 }
 
-bool wlan_get_connected_vdev_by_bssid(struct wlan_objmgr_pdev *pdev,
-				      uint8_t *bssid, uint8_t *vdev_id)
+bool wlan_get_connected_vdev_from_psoc_by_bssid(struct wlan_objmgr_psoc *psoc,
+						uint8_t *bssid,
+						uint8_t *vdev_id)
 {
-	struct wlan_objmgr_psoc *psoc;
 	struct wlan_check_bssid_context context;
 
-	psoc = wlan_pdev_get_psoc(pdev);
 	qdf_mem_zero(&context, sizeof(struct wlan_check_bssid_context));
 	qdf_mem_copy(context.bssid.bytes, bssid, QDF_MAC_ADDR_SIZE);
 	wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP,
@@ -587,8 +586,83 @@ bool wlan_get_connected_vdev_by_bssid(struct wlan_objmgr_pdev *pdev,
 	return context.connected;
 }
 
+bool wlan_get_connected_vdev_by_bssid(struct wlan_objmgr_pdev *pdev,
+				      uint8_t *bssid, uint8_t *vdev_id)
+{
+	return wlan_get_connected_vdev_from_psoc_by_bssid(
+			wlan_pdev_get_psoc(pdev), bssid, vdev_id);
+}
+
 qdf_export_symbol(wlan_get_connected_vdev_by_bssid);
 
+#ifdef WLAN_FEATURE_11BE_MLO
+/**
+ * struct wlan_check_mld_addr_context - mld mac addr check context
+ * @mld_addr: mld_addrto be checked
+ * @connected: connected by vdev or not
+ * @vdev_id: vdev id of connected vdev
+ */
+struct wlan_check_mld_addr_context {
+	struct qdf_mac_addr mld_addr;
+	bool connected;
+	uint8_t vdev_id;
+};
+
+/**
+ * wlan_get_connected_mlo_dev_ctx_handler() - check vdev connected on mld mac
+ * @psoc: psoc object
+ * @obj: vdev object
+ * @args: handler context
+ *
+ * This function will check whether vdev is connected on mld mac or not and
+ * update the result to handler context accordingly.
+ *
+ * Return: void
+ */
+static void wlan_get_connected_mlo_dev_ctx_handler(
+			struct wlan_objmgr_psoc *psoc,
+			void *obj, void *args)
+{
+	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)obj;
+	struct wlan_check_mld_addr_context *context =
+				(struct wlan_check_mld_addr_context *)args;
+	struct qdf_mac_addr bss_peer_mld_mac;
+	enum QDF_OPMODE op_mode;
+
+	if (context->connected)
+		return;
+	op_mode = wlan_vdev_mlme_get_opmode(vdev);
+	if (op_mode != QDF_STA_MODE && op_mode != QDF_P2P_CLIENT_MODE)
+		return;
+	if (wlan_vdev_is_up(vdev) != QDF_STATUS_SUCCESS)
+		return;
+	if (QDF_IS_STATUS_ERROR(wlan_vdev_get_bss_peer_mld_mac(
+					vdev, &bss_peer_mld_mac)))
+		return;
+	if (qdf_is_macaddr_equal(&bss_peer_mld_mac, &context->mld_addr)) {
+		context->connected = true;
+		context->vdev_id = wlan_vdev_get_id(vdev);
+	}
+}
+
+bool wlan_get_connected_vdev_by_mld_addr(struct wlan_objmgr_psoc *psoc,
+					 uint8_t *mld_mac, uint8_t *vdev_id)
+{
+	struct wlan_check_mld_addr_context context;
+
+	qdf_mem_zero(&context, sizeof(struct wlan_check_mld_addr_context));
+	qdf_copy_macaddr(&context.mld_addr, (struct qdf_mac_addr *)mld_mac);
+	wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP,
+				     wlan_get_connected_mlo_dev_ctx_handler,
+				     &context, true, WLAN_MLME_OBJMGR_ID);
+
+	if (context.connected)
+		*vdev_id = context.vdev_id;
+
+	return context.connected;
+}
+#endif
+
 static void wlan_pdev_chan_match(struct wlan_objmgr_pdev *pdev, void *object,
 				 void *arg)
 {

+ 7 - 0
umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h

@@ -2096,6 +2096,8 @@ struct wlan_lmac_if_dfs_rx_ops {
  *                                  command
  * @vdev_mgr_set_max_channel_switch_time: Set max channel switch time for the
  * given vdev list.
+ * @vdev_mgr_quiet_offload: handle quiet status for given link mac addr or
+ * mld addr and link id.
  */
 struct wlan_lmac_if_mlme_rx_ops {
 	QDF_STATUS (*vdev_mgr_start_response)(
@@ -2132,6 +2134,11 @@ struct wlan_lmac_if_mlme_rx_ops {
 	void (*vdev_mgr_set_max_channel_switch_time)
 		(struct wlan_objmgr_psoc *psoc,
 		 uint32_t *vdev_ids, uint32_t num_vdevs);
+#ifdef WLAN_FEATURE_11BE_MLO
+	QDF_STATUS (*vdev_mgr_quiet_offload)(
+			struct wlan_objmgr_psoc *psoc,
+			struct vdev_sta_quiet_event *quiet_event);
+#endif
 };
 
 #ifdef WLAN_SUPPORT_GREEN_AP

+ 16 - 1
umac/mlme/vdev_mgr/dispatcher/inc/wlan_vdev_mgr_tgt_if_rx_defs.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-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
@@ -177,4 +177,19 @@ struct multi_vdev_restart_resp {
 	qdf_bitmap(vdev_id_bmap, WLAN_UMAC_PSOC_MAX_VDEVS);
 };
 
+#ifdef WLAN_FEATURE_11BE_MLO
+/**
+ * struct vdev_sta_quiet_event - mlo sta quiet offload structure
+ * @mld_mac: AP mld mac address
+ * @link_mac: AP link mac address
+ * @link_id: Link id associated with AP
+ * @quiet_status: WMI_QUIET_EVENT_FLAG: quiet start or stop
+ */
+struct vdev_sta_quiet_event {
+	struct qdf_mac_addr mld_mac;
+	struct qdf_mac_addr link_mac;
+	uint8_t link_id;
+	bool quiet_status;
+};
+#endif
 #endif /* __WLAN_VDEV_MGR_TGT_IF_RX_DEFS_H__ */

+ 13 - 0
umac/mlme/vdev_mgr/dispatcher/inc/wlan_vdev_mgr_utils_api.h

@@ -168,4 +168,17 @@ int wlan_util_vdev_mgr_get_cac_timeout_for_vdev(struct wlan_objmgr_vdev *vdev);
 void wlan_util_vdev_mgr_set_cac_timeout_for_vdev(struct wlan_objmgr_vdev *vdev,
 						 uint32_t new_chan_cac_ms);
 #endif /* MOBILE_DFS_SUPPORT */
+
+#ifdef WLAN_FEATURE_11BE_MLO
+/**
+ * wlan_util_vdev_mgr_quiet_offload() - set quiet status for given link
+ * @psoc: pointer to psoc
+ * @quiet_event: pointer to struct vdev_sta_quiet_event
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS wlan_util_vdev_mgr_quiet_offload(
+				struct wlan_objmgr_psoc *psoc,
+				struct vdev_sta_quiet_event *quiet_event);
+#endif /* WLAN_FEATURE_11BE_MLO */
 #endif /* __WLAN_VDEV_MGR_UTILS_API_H__ */

+ 22 - 0
umac/mlme/vdev_mgr/dispatcher/src/wlan_vdev_mgr_tgt_if_rx_api.c

@@ -327,6 +327,27 @@ static void tgt_vdev_mgr_set_max_channel_switch_time(
 	}
 }
 
+#ifdef WLAN_FEATURE_11BE_MLO
+static QDF_STATUS
+tgt_vdev_mgr_quiet_offload_handler(struct wlan_objmgr_psoc *psoc,
+				   struct vdev_sta_quiet_event *quiet_event)
+{
+	return wlan_util_vdev_mgr_quiet_offload(psoc, quiet_event);
+}
+
+static inline void tgt_vdev_mgr_reg_quiet_offload(
+				struct wlan_lmac_if_mlme_rx_ops *mlme_rx_ops)
+{
+	mlme_rx_ops->vdev_mgr_quiet_offload =
+				tgt_vdev_mgr_quiet_offload_handler;
+}
+#else
+static inline void tgt_vdev_mgr_reg_quiet_offload(
+				struct wlan_lmac_if_mlme_rx_ops *mlme_rx_ops)
+{
+}
+#endif
+
 void tgt_vdev_mgr_register_rx_ops(struct wlan_lmac_if_rx_ops *rx_ops)
 {
 	struct wlan_lmac_if_mlme_rx_ops *mlme_rx_ops = &rx_ops->mops;
@@ -351,4 +372,5 @@ void tgt_vdev_mgr_register_rx_ops(struct wlan_lmac_if_rx_ops *rx_ops)
 		tgt_vdev_mgr_set_max_channel_switch_time;
 	tgt_psoc_reg_wakelock_info_rx_op(&rx_ops->mops);
 	tgt_vdev_mgr_reg_set_mac_address_response(mlme_rx_ops);
+	tgt_vdev_mgr_reg_quiet_offload(mlme_rx_ops);
 }

+ 63 - 0
umac/mlme/vdev_mgr/dispatcher/src/wlan_vdev_mgr_utils_api.c

@@ -33,6 +33,10 @@
 #ifndef MOBILE_DFS_SUPPORT
 #include <wlan_dfs_utils_api.h>
 #endif /* MOBILE_DFS_SUPPORT */
+#ifdef WLAN_FEATURE_11BE_MLO
+#include <wlan_utility.h>
+#include <wlan_mlo_mgr_sta.h>
+#endif
 
 static QDF_STATUS vdev_mgr_config_ratemask_update(
 				struct vdev_mlme_obj *mlme_obj,
@@ -807,3 +811,62 @@ wlan_utils_get_vdev_remaining_channel_switch_time(struct wlan_objmgr_vdev *vdev)
 	return (remaining_chan_switch_time > 0) ?
 		remaining_chan_switch_time : 0;
 }
+
+#ifdef WLAN_FEATURE_11BE_MLO
+QDF_STATUS wlan_util_vdev_mgr_quiet_offload(
+				struct wlan_objmgr_psoc *psoc,
+				struct vdev_sta_quiet_event *quiet_event)
+{
+	uint8_t vdev_id;
+	bool connected;
+	struct wlan_objmgr_vdev *vdev;
+
+	if (qdf_is_macaddr_zero(&quiet_event->mld_mac) &&
+	    qdf_is_macaddr_zero(&quiet_event->link_mac)) {
+		mlme_err("mld_mac and link mac are invalid");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (!qdf_is_macaddr_zero(&quiet_event->mld_mac)) {
+		connected = wlan_get_connected_vdev_by_mld_addr(
+				psoc, quiet_event->mld_mac.bytes, &vdev_id);
+		if (!connected) {
+			mlme_err("Can't find vdev with mld " QDF_MAC_ADDR_FMT,
+				 QDF_MAC_ADDR_REF(quiet_event->mld_mac.bytes));
+			return QDF_STATUS_E_INVAL;
+		}
+		vdev = wlan_objmgr_get_vdev_by_id_from_psoc(
+				psoc, vdev_id, WLAN_MLME_OBJMGR_ID);
+		if (!vdev) {
+			mlme_err("Null vdev");
+			return QDF_STATUS_E_INVAL;
+		}
+		if (wlan_vdev_mlme_is_mlo_vdev(vdev))
+			mlo_sta_save_quiet_status(vdev->mlo_dev_ctx,
+						  quiet_event->link_id,
+						  quiet_event->quiet_status);
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
+	} else if (!qdf_is_macaddr_zero(&quiet_event->link_mac)) {
+		connected = wlan_get_connected_vdev_from_psoc_by_bssid(
+				psoc, quiet_event->link_mac.bytes, &vdev_id);
+		if (!connected) {
+			mlme_err("Can't find vdev with BSSID" QDF_MAC_ADDR_FMT,
+				 QDF_MAC_ADDR_REF(quiet_event->link_mac.bytes));
+			return QDF_STATUS_E_INVAL;
+		}
+		vdev = wlan_objmgr_get_vdev_by_id_from_psoc(
+				psoc, vdev_id, WLAN_MLME_OBJMGR_ID);
+		if (!vdev) {
+			mlme_err("Null vdev");
+			return QDF_STATUS_E_INVAL;
+		}
+		if (wlan_vdev_mlme_is_mlo_vdev(vdev))
+			mlo_sta_save_quiet_status(vdev->mlo_dev_ctx,
+						  wlan_vdev_get_link_id(vdev),
+						  quiet_event->quiet_status);
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID);
+	}
+
+	return QDF_STATUS_SUCCESS;
+}
+#endif /* WLAN_FEATURE_11BE_MLO */

+ 13 - 0
umac/mlo_mgr/inc/wlan_mlo_mgr_public_structs.h

@@ -176,6 +176,18 @@ struct wlan_mlo_key_mgmt {
 	uint32_t gtk;
 };
 
+/*
+ * struct mlo_sta_quiet_status - MLO sta quiet status
+ * @link_id: link id
+ * @quiet_status: true if corresponding ap in quiet status
+ * @valid_status: true if mlo_sta_quiet_status is filled
+ */
+struct mlo_sta_quiet_status {
+	uint8_t link_id;
+	bool quiet_status;
+	bool valid_status;
+};
+
 /*
  * struct wlan_mlo_sta - MLO sta additional info
  * @wlan_connect_req_links: list of vdevs selected for connection with the MLAP
@@ -197,6 +209,7 @@ struct wlan_mlo_sta {
 	qdf_mutex_t copied_conn_req_lock;
 #endif
 	struct element_info assoc_rsp;
+	struct mlo_sta_quiet_status mlo_quiet_status[WLAN_UMAC_MLO_MAX_VDEVS];
 };
 
 /*

+ 42 - 1
umac/mlo_mgr/inc/wlan_mlo_mgr_sta.h

@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2021-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
@@ -390,6 +390,47 @@ mlo_get_chan_freq_by_bssid(struct wlan_objmgr_pdev *pdev,
  */
 void mlo_get_assoc_rsp(struct wlan_objmgr_vdev *vdev,
 		       struct element_info *assoc_rsp_frame);
+
+/**
+ * mlo_sta_save_quiet_status - save quiet status for given link of mlo station
+ * @mlo_dev_ctx: mlo context
+ * @link_id: link id
+ * @quiet_status: True if quiet starts. False if quiet stopps.
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS mlo_sta_save_quiet_status(struct wlan_mlo_dev_context *mlo_dev_ctx,
+				     uint8_t link_id,
+				     bool quiet_status);
+
+/**
+ * mlo_is_sta_in_quiet_status - is the link of given mlo sta is in quiet status
+ * @mlo_dev_ctx: mlo context
+ * @link_id: link id
+ *
+ * Return: true if the link of given mlo sta is in quiet status
+ */
+bool mlo_is_sta_in_quiet_status(struct wlan_mlo_dev_context *mlo_dev_ctx,
+				uint8_t link_id);
+
+/**
+ * mlo_is_sta_inactivity_allowed_with_quiet() - Is link OK to force inactivity
+ *                                              based on current quiet status
+ *                                              of mlo connection
+ * @psoc: pointer to psoc
+ * @vdev_id_list: vdev id list
+ * @num_mlo: number of mlo vdev
+ * @mlo_idx: list of index of vdev_id_list if it is vdev id of mlo vdev
+ * @affected_links: number of links to be set inactivity
+ * @affected_list: list of vdev id to be set inactivity
+ *
+ * Return: true if any link not in mlo_vdev_list is not in quiet mode
+ */
+bool mlo_is_sta_inactivity_allowed_with_quiet(struct wlan_objmgr_psoc *psoc,
+					      uint8_t *vdev_id_list,
+					      uint8_t num_mlo, uint8_t *mlo_idx,
+					      uint8_t affected_links,
+					      uint8_t *affected_list);
 #else
 static inline
 QDF_STATUS mlo_connect(struct wlan_objmgr_vdev *vdev,

+ 129 - 0
umac/mlo_mgr/src/wlan_mlo_mgr_sta.c

@@ -1174,4 +1174,133 @@ void mlo_get_assoc_rsp(struct wlan_objmgr_vdev *vdev,
 
 	*assoc_rsp_frame = sta_ctx->assoc_rsp;
 }
+
+QDF_STATUS mlo_sta_save_quiet_status(struct wlan_mlo_dev_context *mlo_dev_ctx,
+				     uint8_t link_id,
+				     bool quiet_status)
+{
+	struct wlan_mlo_sta *sta_ctx;
+	int i;
+	bool find_free_buffer = false;
+	int free_idx;
+
+	if (!mlo_dev_ctx) {
+		mlo_err("invalid mlo_dev_ctx");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	mlo_dev_lock_acquire(mlo_dev_ctx);
+	sta_ctx = mlo_dev_ctx->sta_ctx;
+	if (!sta_ctx) {
+		mlo_err("invalid sta_ctx");
+		mlo_dev_lock_release(mlo_dev_ctx);
+		return QDF_STATUS_E_INVAL;
+	}
+	for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_quiet_status); i++) {
+		if (!sta_ctx->mlo_quiet_status[i].valid_status) {
+			if (!find_free_buffer) {
+				free_idx = i;
+				find_free_buffer = true;
+			}
+		} else if (link_id == sta_ctx->mlo_quiet_status[i].link_id) {
+			sta_ctx->mlo_quiet_status[i].quiet_status =
+							quiet_status;
+			mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d quiet status update %d",
+				  QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes),
+				  link_id, quiet_status);
+			mlo_dev_lock_release(mlo_dev_ctx);
+			return QDF_STATUS_SUCCESS;
+		}
+	}
+	if (!find_free_buffer) {
+		mlo_err("no free buffer for link id %d to save quiet_status",
+			link_id);
+		mlo_dev_lock_release(mlo_dev_ctx);
+		return QDF_STATUS_E_INVAL;
+	}
+	sta_ctx->mlo_quiet_status[free_idx].quiet_status = quiet_status;
+	sta_ctx->mlo_quiet_status[free_idx].link_id = link_id;
+	sta_ctx->mlo_quiet_status[free_idx].valid_status = true;
+
+	mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d in quiet status %d",
+		  QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes),
+		  link_id, quiet_status);
+	mlo_dev_lock_release(mlo_dev_ctx);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+bool mlo_is_sta_in_quiet_status(struct wlan_mlo_dev_context *mlo_dev_ctx,
+				uint8_t link_id)
+{
+	struct wlan_mlo_sta *sta_ctx;
+	int i;
+	bool quiet_status = false;
+
+	if (!mlo_dev_ctx) {
+		mlo_err("invalid mlo_dev_ctx");
+		return quiet_status;
+	}
+
+	mlo_dev_lock_acquire(mlo_dev_ctx);
+	sta_ctx = mlo_dev_ctx->sta_ctx;
+	if (!sta_ctx) {
+		mlo_err("invalid sta_ctx");
+		mlo_dev_lock_release(mlo_dev_ctx);
+		return quiet_status;
+	}
+	for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_quiet_status); i++) {
+		if (sta_ctx->mlo_quiet_status[i].valid_status &&
+		    link_id == sta_ctx->mlo_quiet_status[i].link_id) {
+			quiet_status =
+				sta_ctx->mlo_quiet_status[i].quiet_status;
+			break;
+		}
+	}
+	mlo_dev_lock_release(mlo_dev_ctx);
+
+	return quiet_status;
+}
+
+bool mlo_is_sta_inactivity_allowed_with_quiet(struct wlan_objmgr_psoc *psoc,
+					      uint8_t *vdev_id_list,
+					      uint8_t num_mlo, uint8_t *mlo_idx,
+					      uint8_t affected_links,
+					      uint8_t *affected_list)
+{
+	uint8_t i, j;
+	struct wlan_objmgr_vdev *vdev;
+	bool allowed = false;
+
+	for (i = 0; i < num_mlo; i++) {
+		for (j = 0; j < affected_links; j++) {
+			if (vdev_id_list[mlo_idx[i]] == affected_list[j])
+				break;
+		}
+		if (j != affected_links)
+			continue;
+		/* find vdev not in affected_list */
+		vdev = wlan_objmgr_get_vdev_by_id_from_psoc(
+				psoc, vdev_id_list[mlo_idx[i]],
+				WLAN_IF_MGR_ID);
+		if (!vdev) {
+			mlo_err("invalid vdev for id %d",
+				vdev_id_list[mlo_idx[i]]);
+			continue;
+		}
+
+		/* for not affected vdev, check the vdev is in quiet or not*/
+		allowed = !mlo_is_sta_in_quiet_status(
+				vdev->mlo_dev_ctx, wlan_vdev_get_link_id(vdev));
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_IF_MGR_ID);
+		if (allowed) {
+			mlo_debug("vdev id %d link id %d is not in quiet, allow partner link to trigger inactivity",
+				  wlan_vdev_get_id(vdev),
+				  wlan_vdev_get_link_id(vdev));
+			break;
+		}
+	}
+
+	return allowed;
+}
 #endif