Quellcode durchsuchen

qcacmn: Handle CSA in MLO sta partner link before it is up

Before MLO sta partner link is up, FW can't indicate CSA event to host.
For this case, host need save csa parameters and process it when MLO
sta partner link is up.

Change-Id: Id1803f32787002e020c6899ec72e428feb765b7f
CRs-Fixed: 3082438
Bing Sun vor 3 Jahren
Ursprung
Commit
bdbcc9ddf0

+ 38 - 0
umac/cmn_services/cmn_defs/inc/wlan_cmn_ieee80211.h

@@ -3249,4 +3249,42 @@ wlan_parse_oce_ap_tx_pwr_ie(uint8_t *mbo_oce_ie, int8_t *ap_tx_pwr_dbm)
 
 	return false;
 }
+
+/**
+ * enum mlme_csa_event_ies_present_flag - IE present flag in CSA event
+ * @MLME_CSA_IE_PRESENT: CSA IE is present
+ * @MLME_XCSA_IE_PRESENT: extend CSA IE is present
+ * @MLME_WBW_IE_PRESENT: wide bandwidth channel switch IE is present
+ * @MLME_CSWRAP_IE_EXTENDED_PRESENT: channel switch wrapper IE is present
+ */
+enum mlme_csa_event_ies_present_flag {
+	MLME_CSA_IE_PRESENT    = 0x00000001,
+	MLME_XCSA_IE_PRESENT   = 0x00000002,
+	MLME_WBW_IE_PRESENT    = 0x00000004,
+	MLME_CSWRAP_IE_EXTENDED_PRESENT = 0x00000008,
+};
+
+/**
+ * struct csa_offload_params - STA CSA offload request parameters
+ * @channel: channel
+ * @switch_mode: switch mode
+ * @sec_chan_offset: secondary channel offset
+ * @new_ch_width: new channel width
+ * @new_ch_freq_seg1: channel center freq 1
+ * @new_ch_freq_seg2: channel center freq 2
+ * @ies_present_flag: BIT MAP of MLME_CSA_EVENT_IES_PRESENT_FLAG
+ * @bssid: BSSID which triggers CSA
+ */
+struct csa_offload_params {
+	uint8_t channel;
+	uint32_t csa_chan_freq;
+	uint8_t switch_mode;
+	uint8_t sec_chan_offset;
+	uint8_t new_ch_width;
+	uint8_t new_op_class;
+	uint8_t new_ch_freq_seg1;
+	uint8_t new_ch_freq_seg2;
+	uint32_t ies_present_flag;
+	struct qdf_mac_addr bssid;
+};
 #endif /* _WLAN_CMN_IEEE80211_DEFS_H_ */

+ 4 - 2
umac/mlme/vdev_mgr/core/src/vdev_mlme_sm.c

@@ -1790,13 +1790,15 @@ static bool mlme_vdev_subst_up_active_event(void *ctx, uint16_t event,
 		mlme_vdev_update_beacon(vdev_mlme, BEACON_INIT,
 					event_data_len, event_data);
 		if (mlme_vdev_up_send(vdev_mlme, event_data_len,
-				      event_data) != QDF_STATUS_SUCCESS)
+				      event_data) != QDF_STATUS_SUCCESS) {
 			mlme_vdev_sm_deliver_event(vdev_mlme,
 						   WLAN_VDEV_SM_EV_UP_FAIL,
 						   event_data_len, event_data);
-		else
+		} else {
 			mlme_vdev_notify_up_complete(vdev_mlme, event_data_len,
 						     event_data);
+			mlme_vdev_up_active_notify_mlo_mgr(vdev_mlme);
+		}
 		status = true;
 		break;
 

+ 21 - 0
umac/mlme/vdev_mgr/core/src/vdev_mlme_sm.h

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
+ * 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
@@ -25,6 +26,7 @@
 
 #ifdef WLAN_FEATURE_11BE_MLO
 #include <wlan_mlo_mgr_ap.h>
+#include <wlan_mlo_mgr_sta.h>
 #endif
 #include <wlan_dfs_utils_api.h>
 
@@ -677,6 +679,20 @@ static inline void mlme_vdev_down_cmpl_notify_mlo_mgr(
 	if (wlan_vdev_mlme_is_mlo_ap(vdev_mlme->vdev))
 		mlo_ap_link_down_cmpl_notify(vdev_mlme->vdev);
 }
+
+/**
+ * mlme_vdev_up_active_notify_mlo_mgr - notify mlo link is up active
+ * @vdev_mlme_obj:  VDEV MLME comp object
+ *
+ * Return: VOID.
+ */
+static inline void mlme_vdev_up_active_notify_mlo_mgr(
+					struct vdev_mlme_obj *vdev_mlme)
+{
+	if ((wlan_vdev_mlme_get_opmode(vdev_mlme->vdev) == QDF_STA_MODE) &&
+	    wlan_vdev_mlme_is_mlo_vdev(vdev_mlme->vdev))
+		mlo_sta_up_active_notify(vdev_mlme->vdev);
+}
 #else
 static inline void mlme_vdev_up_notify_mlo_mgr(struct vdev_mlme_obj *vdev_mlme)
 {
@@ -691,6 +707,11 @@ static inline void mlme_vdev_down_cmpl_notify_mlo_mgr(
 					struct vdev_mlme_obj *vdev_mlme)
 {
 }
+
+static inline void mlme_vdev_up_active_notify_mlo_mgr(
+					struct vdev_mlme_obj *vdev_mlme)
+{
+}
 #endif
 
 #ifdef VDEV_SM_LOCK_SUPPORT

+ 10 - 0
umac/mlo_mgr/inc/wlan_mlo_mgr_cmn.h

@@ -277,6 +277,16 @@ void mlo_get_ml_vdev_list(struct wlan_objmgr_vdev *vdev,
 			  uint16_t *vdev_count,
 			  struct wlan_objmgr_vdev **wlan_vdev_list);
 
+/**
+ * mlo_mlme_handle_sta_csa_param() - process saved mlo sta csa param
+ * @vdev: vdev pointer
+ * @csa_param: saved csa_param
+ *
+ * Return: None
+ */
+void mlo_mlme_handle_sta_csa_param(struct wlan_objmgr_vdev *vdev,
+				   struct csa_offload_params *csa_param);
+
 #define INVALID_HW_LINK_ID 0xFFFF
 #ifdef WLAN_MLO_MULTI_CHIP
 /**

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

@@ -176,6 +176,28 @@ struct wlan_mlo_key_mgmt {
 	uint32_t gtk;
 };
 
+/**
+ * struct mlo_sta_csa _params - CSA request parameters in mlo mgr
+ * @csa_param: csa parameters
+ * @link_id: the link index of AP which triggers CSA
+ * @mlo_csa_synced: Before vdev is up, csa information is only saved but not
+ *                  handled, and this value is false. Once vdev is up, the saved
+ *                  csa information is handled, and this value is changed to
+ *                  true. Note this value will be true if the vdev is doing
+ *                  restart.
+ * @csa_offload_event_recvd: True if WMI_CSA_HANDLING_EVENTID is already
+ *                           received. False if this is the first
+ *                           WMI_CSA_HANDLING_EVENTID.
+ * @valid_csa_param: True once csa_param is filled.
+ */
+struct mlo_sta_csa_params {
+	struct csa_offload_params csa_param;
+	uint8_t link_id;
+	bool mlo_csa_synced;
+	bool csa_offload_event_recvd;
+	bool valid_csa_param;
+};
+
 /*
  * struct mlo_sta_quiet_status - MLO sta quiet status
  * @link_id: link id
@@ -196,6 +218,7 @@ struct mlo_sta_quiet_status {
  * @copied_conn_req: original connect req
  * @copied_conn_req_lock: lock for the original connect request
  * @assoc_rsp: Raw assoc response frame
+ * @mlo_csa_param: CSA request parameters for mlo sta
  */
 struct wlan_mlo_sta {
 	qdf_bitmap(wlan_connect_req_links, WLAN_UMAC_MLO_MAX_VDEVS);
@@ -210,6 +233,7 @@ struct wlan_mlo_sta {
 #endif
 	struct element_info assoc_rsp;
 	struct mlo_sta_quiet_status mlo_quiet_status[WLAN_UMAC_MLO_MAX_VDEVS];
+	struct mlo_sta_csa_params mlo_csa_param[WLAN_UMAC_MLO_MAX_VDEVS];
 };
 
 /*
@@ -450,6 +474,7 @@ struct mlo_tgt_partner_info {
  * @mlo_mlme_ext_deauth: Callback to initiate deauth
  * @mlo_mlme_ext_clone_security_param: Callback to clone mlo security params
  * @mlo_mlme_ext_peer_process_auth: Callback to process pending auth
+ * @mlo_mlme_ext_handle_sta_csa_param: Callback to handle sta csa param
  */
 struct mlo_mlme_ext_ops {
 	QDF_STATUS (*mlo_mlme_ext_validate_conn_req)(
@@ -474,6 +499,9 @@ struct mlo_mlme_ext_ops {
 	void (*mlo_mlme_ext_peer_process_auth)(
 	      struct mlpeer_auth_params *auth_param);
 #endif
+	void (*mlo_mlme_ext_handle_sta_csa_param)(
+				struct wlan_objmgr_vdev *vdev,
+				struct csa_offload_params *csa_param);
 };
 
 /* maximum size of vdev bitmap array for MLO link set active command */

+ 48 - 0
umac/mlo_mgr/inc/wlan_mlo_mgr_sta.h

@@ -431,6 +431,47 @@ bool mlo_is_sta_inactivity_allowed_with_quiet(struct wlan_objmgr_psoc *psoc,
 					      uint8_t num_mlo, uint8_t *mlo_idx,
 					      uint8_t affected_links,
 					      uint8_t *affected_list);
+
+/**
+ * mlo_is_sta_csa_synced - Is mlo sta csa parameters are synced or not
+ *
+ * @mlo_dev_ctx: mlo context
+ * @link_id: link id
+ *
+ * Return: true if mlo sta csa parameters of given link id is synced
+ */
+bool mlo_is_sta_csa_synced(struct wlan_mlo_dev_context *mlo_dev_ctx,
+			   uint8_t link_id);
+
+/**
+ * mlo_sta_csa_save_params - Save csa parameters for mlo station
+ * @mlo_dev_ctx: mlo context
+ * @link_id: link id
+ * @csa_param: csa parameters to be saved
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS mlo_sta_csa_save_params(struct wlan_mlo_dev_context *mlo_dev_ctx,
+				   uint8_t link_id,
+				   struct csa_offload_params *csa_param);
+
+/**
+ * mlo_sta_up_active_notify - mlo sta up active notify
+ * @vdev: vdev obj mgr
+ *
+ * Return: QDF_STATUS
+ */
+QDF_STATUS mlo_sta_up_active_notify(struct wlan_objmgr_vdev *vdev);
+
+/**
+ * mlo_is_sta_csa_param_handled - Is given csa_param handled or not
+ * @vdev: vdev obj mgr
+ * @csa_param: csa parameters to be checked
+ *
+ * Return: true if given csa parameters is handled
+ */
+bool mlo_is_sta_csa_param_handled(struct wlan_objmgr_vdev *vdev,
+				  struct csa_offload_params *csa_param);
 #else
 static inline
 QDF_STATUS mlo_connect(struct wlan_objmgr_vdev *vdev,
@@ -546,5 +587,12 @@ mlo_get_assoc_rsp(struct wlan_objmgr_vdev *vdev,
 		  struct element_info *assoc_rsp_frame)
 {
 }
+
+static inline bool
+mlo_is_sta_csa_param_handled(struct wlan_objmgr_vdev *vdev,
+			     struct csa_offload_params *csa_param)
+{
+	return false;
+}
 #endif
 #endif

+ 12 - 0
umac/mlo_mgr/src/wlan_mlo_mgr_cmn.c

@@ -585,3 +585,15 @@ out:
 
 	return status;
 }
+
+void mlo_mlme_handle_sta_csa_param(struct wlan_objmgr_vdev *vdev,
+				   struct csa_offload_params *csa_param)
+{
+	struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx();
+
+	if (!mlo_ctx || !mlo_ctx->mlme_ops ||
+	    !mlo_ctx->mlme_ops->mlo_mlme_ext_handle_sta_csa_param)
+		return;
+
+	mlo_ctx->mlme_ops->mlo_mlme_ext_handle_sta_csa_param(vdev, csa_param);
+}

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

@@ -1303,4 +1303,231 @@ bool mlo_is_sta_inactivity_allowed_with_quiet(struct wlan_objmgr_psoc *psoc,
 
 	return allowed;
 }
+
+bool mlo_is_sta_csa_synced(struct wlan_mlo_dev_context *mlo_dev_ctx,
+			   uint8_t link_id)
+{
+	struct wlan_mlo_sta *sta_ctx;
+	int i;
+	bool sta_csa_synced = false;
+
+	if (!mlo_dev_ctx) {
+		mlo_err("invalid mlo_dev_ctx");
+		return sta_csa_synced;
+	}
+
+	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 sta_csa_synced;
+	}
+	for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) {
+		if (link_id == sta_ctx->mlo_csa_param[i].link_id &&
+		    (sta_ctx->mlo_csa_param[i].valid_csa_param ||
+		     sta_ctx->mlo_csa_param[i].mlo_csa_synced)) {
+			mlo_dev_lock_release(mlo_dev_ctx);
+			sta_csa_synced =
+				sta_ctx->mlo_csa_param[i].mlo_csa_synced;
+			break;
+		}
+	}
+	mlo_dev_lock_release(mlo_dev_ctx);
+
+	return sta_csa_synced;
+}
+
+QDF_STATUS mlo_sta_csa_save_params(struct wlan_mlo_dev_context *mlo_dev_ctx,
+				   uint8_t link_id,
+				   struct csa_offload_params *csa_param)
+{
+	struct wlan_mlo_sta *sta_ctx;
+	int i;
+	bool find_free_buffer = false;
+	int free_idx;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!mlo_dev_ctx) {
+		mlo_err("invalid mlo_dev_ctx");
+		status = QDF_STATUS_E_INVAL;
+		goto done;
+	}
+
+	mlo_dev_lock_acquire(mlo_dev_ctx);
+	sta_ctx = mlo_dev_ctx->sta_ctx;
+	if (!sta_ctx) {
+		mlo_err("invalid sta_ctx");
+		status = QDF_STATUS_E_INVAL;
+		goto rel_lock;
+	}
+	for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) {
+		if (!sta_ctx->mlo_csa_param[i].valid_csa_param &&
+		    !sta_ctx->mlo_csa_param[i].mlo_csa_synced) {
+			if (!find_free_buffer) {
+				free_idx = i;
+				find_free_buffer = true;
+			}
+		} else if (link_id == sta_ctx->mlo_csa_param[i].link_id) {
+			qdf_mem_copy(&sta_ctx->mlo_csa_param[i].csa_param,
+				     csa_param, sizeof(*csa_param));
+			mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d update csa",
+				  QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes),
+				  link_id);
+			goto rel_lock;
+		}
+	}
+	if (!find_free_buffer) {
+		mlo_err("no free buffer of csa param for link %d in sta_ctx",
+			link_id);
+		status = QDF_STATUS_E_INVAL;
+		goto rel_lock;
+	}
+	qdf_mem_copy(&sta_ctx->mlo_csa_param[free_idx].csa_param,
+		     csa_param, sizeof(*csa_param));
+	sta_ctx->mlo_csa_param[free_idx].link_id = link_id;
+	sta_ctx->mlo_csa_param[free_idx].valid_csa_param = true;
+	mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d RX csa",
+		  QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes),
+		  link_id);
+
+rel_lock:
+	mlo_dev_lock_release(mlo_dev_ctx);
+
+done:
+
+	return status;
+}
+
+QDF_STATUS mlo_sta_up_active_notify(struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_mlo_sta *sta_ctx;
+	struct wlan_mlo_dev_context *mlo_dev_ctx;
+	uint8_t link_id;
+	int i;
+	bool find_free_buffer = false;
+	int free_idx;
+	struct csa_offload_params csa_param;
+	struct wlan_channel *chan;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+	if (!vdev) {
+		mlo_err("invalid vdev");
+		status = QDF_STATUS_E_INVAL;
+		goto done;
+	}
+	link_id = wlan_vdev_get_link_id(vdev);
+	mlo_dev_ctx = vdev->mlo_dev_ctx;
+	if (!mlo_dev_ctx) {
+		mlo_err("invalid mlo_dev_ctx");
+		status = QDF_STATUS_E_INVAL;
+		goto done;
+	}
+	mlo_dev_lock_acquire(mlo_dev_ctx);
+	sta_ctx = mlo_dev_ctx->sta_ctx;
+	if (!sta_ctx) {
+		mlo_err("invalid sta_ctx");
+		status = QDF_STATUS_E_INVAL;
+		goto rel_lock;
+	}
+
+	for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) {
+		if (!sta_ctx->mlo_csa_param[i].valid_csa_param &&
+		    !sta_ctx->mlo_csa_param[i].mlo_csa_synced) {
+			if (!find_free_buffer) {
+				free_idx = i;
+				find_free_buffer = true;
+			}
+		} else if (link_id == sta_ctx->mlo_csa_param[i].link_id) {
+			if (sta_ctx->mlo_csa_param[i].valid_csa_param &&
+			    !sta_ctx->mlo_csa_param[i].mlo_csa_synced) {
+				mlo_debug("mld mac " QDF_MAC_ADDR_FMT " vdev id %d link id %d handle csa",
+					  QDF_MAC_ADDR_REF(
+						mlo_dev_ctx->mld_addr.bytes),
+					  wlan_vdev_get_id(vdev), link_id);
+				csa_param = sta_ctx->mlo_csa_param[i].csa_param;
+				sta_ctx->mlo_csa_param[i].mlo_csa_synced = true;
+				mlo_dev_lock_release(mlo_dev_ctx);
+				chan = wlan_vdev_mlme_get_bss_chan(vdev);
+				if (csa_param.csa_chan_freq && chan &&
+				    csa_param.csa_chan_freq != chan->ch_freq)
+					mlo_mlme_handle_sta_csa_param(
+						vdev, &csa_param);
+				goto done;
+			}
+			sta_ctx->mlo_csa_param[i].mlo_csa_synced = true;
+			goto rel_lock;
+		}
+	}
+	if (!find_free_buffer) {
+		mlo_err("no free buffer of csa param for link %d in sta_ctx",
+			link_id);
+		goto rel_lock;
+	}
+	sta_ctx->mlo_csa_param[free_idx].mlo_csa_synced = true;
+	sta_ctx->mlo_csa_param[free_idx].link_id = link_id;
+	mlo_debug("mld mac " QDF_MAC_ADDR_FMT " link id %d UP Active",
+		  QDF_MAC_ADDR_REF(mlo_dev_ctx->mld_addr.bytes),
+		  link_id);
+
+rel_lock:
+	mlo_dev_lock_release(mlo_dev_ctx);
+
+done:
+
+	return status;
+}
+
+bool mlo_is_sta_csa_param_handled(struct wlan_objmgr_vdev *vdev,
+				  struct csa_offload_params *csa_param)
+{
+	struct wlan_mlo_sta *sta_ctx;
+	struct wlan_mlo_dev_context *mlo_dev_ctx;
+	uint8_t link_id;
+	int i;
+	bool handled = false;
+
+	if (!vdev) {
+		mlo_err("invalid vdev");
+		goto done;
+	}
+	link_id = wlan_vdev_get_link_id(vdev);
+	mlo_dev_ctx = vdev->mlo_dev_ctx;
+	if (!mlo_dev_ctx) {
+		mlo_err("invalid mlo_dev_ctx");
+		goto done;
+	}
+	mlo_dev_lock_acquire(mlo_dev_ctx);
+	sta_ctx = mlo_dev_ctx->sta_ctx;
+	if (!sta_ctx) {
+		mlo_err("invalid sta_ctx");
+		goto rel_lock;
+	}
+
+	for (i = 0; i < QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param); i++) {
+		if (link_id == sta_ctx->mlo_csa_param[i].link_id &&
+		    (sta_ctx->mlo_csa_param[i].valid_csa_param ||
+		     sta_ctx->mlo_csa_param[i].mlo_csa_synced))
+			break;
+	}
+
+	if (i >= QDF_ARRAY_SIZE(sta_ctx->mlo_csa_param)) {
+		mlo_debug("mlo csa synced does not happen before csa FW event");
+		goto rel_lock;
+	}
+	if (!sta_ctx->mlo_csa_param[i].csa_offload_event_recvd) {
+		sta_ctx->mlo_csa_param[i].csa_offload_event_recvd = true;
+		if (sta_ctx->mlo_csa_param[i].valid_csa_param &&
+		    !qdf_mem_cmp(&sta_ctx->mlo_csa_param[i].csa_param,
+				 csa_param, sizeof(*csa_param)))
+			handled = true;
+	}
+
+rel_lock:
+	mlo_dev_lock_release(mlo_dev_ctx);
+
+done:
+
+	return handled;
+}
 #endif