瀏覽代碼

qcacmn: Notify callbacks post link switch with status

Introduce new enum to hold the reason for invoking link switch
notify callback.

Notification happens in the following scenarios:
    a) On FW request received in host before serialization.
    b) Once link switch is serialized before link switch disconnect.
    c) On link switch complete but before removed from serialization.

Change-Id: Id502db935ccc3835ab8bb8fab8d89276abe0a243
CRs-Fixed: 3606668
Vinod Kumar Pirla 1 年之前
父節點
當前提交
dcb8808eb6

+ 33 - 4
umac/mlo_mgr/inc/wlan_mlo_mgr_link_switch.h

@@ -96,6 +96,7 @@ enum wlan_mlo_link_switch_reason {
  * enum mlo_link_switch_req_state - Enum to maintain the current state of
  * link switch request.
  * @MLO_LINK_SWITCH_STATE_IDLE: The last link switch request is inactive
+ * @MLO_LINK_SWITCH_STATE_INIT: Link switch is in pre-start state.
  * @MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK: Current link disconnect
  *                                              in progress.
  * @MLO_LINK_SWITCH_STATE_SET_MAC_ADDR: MAC address update in progress
@@ -107,6 +108,7 @@ enum wlan_mlo_link_switch_reason {
  */
 enum mlo_link_switch_req_state {
 	MLO_LINK_SWITCH_STATE_IDLE,
+	MLO_LINK_SWITCH_STATE_INIT,
 	MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK,
 	MLO_LINK_SWITCH_STATE_SET_MAC_ADDR,
 	MLO_LINK_SWITCH_STATE_CONNECT_NEW_LINK,
@@ -117,7 +119,6 @@ enum mlo_link_switch_req_state {
 /**
  * struct wlan_mlo_link_switch_req - Data Structure because of link switch
  * request
- * @restore_vdev_flag: VDEV Flag to be restored post link switch.
  * @vdev_id: VDEV Id of the link which is under link switch
  * @curr_ieee_link_id: Current link id of the ML link
  * @new_ieee_link_id: Link id of the link to which going to link switched
@@ -126,10 +127,10 @@ enum mlo_link_switch_req_state {
  * @new_phymode: Phy mode of link switch link
  * @state: Current state of link switch
  * @reason: Link switch reason
+ * @restore_vdev_flag: VDEV Flag to be restored post link switch.
  * @link_switch_ts: Link switch timestamp
  */
 struct wlan_mlo_link_switch_req {
-	bool restore_vdev_flag;
 	uint8_t vdev_id;
 	uint8_t curr_ieee_link_id;
 	uint8_t new_ieee_link_id;
@@ -138,6 +139,7 @@ struct wlan_mlo_link_switch_req {
 	uint32_t new_phymode;
 	enum mlo_link_switch_req_state state;
 	enum wlan_mlo_link_switch_reason reason;
+	bool restore_vdev_flag;
 	qdf_time_t link_switch_ts;
 };
 
@@ -402,6 +404,7 @@ bool mlo_mgr_is_link_switch_in_progress(struct wlan_objmgr_vdev *vdev);
  * of link switch
  * @vdev: VDEV object manager
  * @lswitch_req: Link switch request params from FW
+ * @notify_reason: Reason for link switch notification
  *
  * The link switch notifier callback to MLO manager invoked before starting
  * link switch disconnect
@@ -409,7 +412,8 @@ bool mlo_mgr_is_link_switch_in_progress(struct wlan_objmgr_vdev *vdev);
  * Return: QDF_STATUS
  */
 QDF_STATUS mlo_mgr_link_switch_notification(struct wlan_objmgr_vdev *vdev,
-					    struct wlan_mlo_link_switch_req *lswitch_req);
+					    struct wlan_mlo_link_switch_req *lswitch_req,
+					    enum wlan_mlo_link_switch_notify_reason notify_reason);
 
 /**
  * mlo_mgr_is_link_switch_on_assoc_vdev() - API to query whether link switch
@@ -459,6 +463,23 @@ QDF_STATUS mlo_mgr_ser_link_switch_cmd(struct wlan_objmgr_vdev *vdev,
  */
 void mlo_mgr_remove_link_switch_cmd(struct wlan_objmgr_vdev *vdev);
 
+/**
+ * mlo_mgr_link_switch_notify() - API to notify registered link switch notify
+ * callbacks.
+ * @vdev: VDEV object manager
+ * @req: Link switch request params from FW.
+ *
+ * The API calls all the registered link switch notifiers with appropriate
+ * reason for notifications. Callback handlers to take necessary action based
+ * on the reason.
+ * If any callback returns error API will return error or else success.
+ *
+ * Return: QDF_STATUS.
+ */
+QDF_STATUS
+mlo_mgr_link_switch_notify(struct wlan_objmgr_vdev *vdev,
+			   struct wlan_mlo_link_switch_req *req);
+
 /**
  * mlo_mgr_link_switch_validate_request() - Validate link switch request
  * received from FW.
@@ -623,7 +644,8 @@ mlo_mgr_is_link_switch_in_progress(struct wlan_objmgr_vdev *vdev)
 
 static inline QDF_STATUS
 mlo_mgr_link_switch_notification(struct wlan_objmgr_vdev *vdev,
-				 struct wlan_mlo_link_switch_req *lswitch_req)
+				 struct wlan_mlo_link_switch_req *lswitch_req,
+				 enum wlan_mlo_link_switch_notify_reason notify_reason)
 {
 	return QDF_STATUS_E_NOSUPPORT;
 }
@@ -652,6 +674,13 @@ mlo_mgr_remove_link_switch_cmd(struct wlan_objmgr_vdev *vdev)
 {
 }
 
+static inline QDF_STATUS
+mlo_mgr_link_switch_notify(struct wlan_objmgr_vdev *vdev,
+			   struct wlan_mlo_link_switch_req *req)
+{
+	return QDF_STATUS_E_NOSUPPORT;
+}
+
 static inline QDF_STATUS
 mlo_mgr_link_switch_validate_request(struct wlan_objmgr_vdev *vdev,
 				     struct wlan_mlo_link_switch_req *req)

+ 21 - 1
umac/mlo_mgr/inc/wlan_mlo_mgr_public_structs.h

@@ -208,9 +208,29 @@ struct mlo_state_params {
 
 #endif
 
+/**
+ * enum wlan_mlo_link_switch_notify_reason - Enum for link switch notifier
+ *                                           callback trigger reason.
+ * @MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_PRE_SER: Prior to start of
+ *                                                   link switch and prior to
+ *                                                   serializing link switch.
+ * @MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_POST_SER: Prior to link switch start
+ *                                                    but link switch is
+ *                                                    serialized
+ * @MLO_LINK_SWITCH_NOTIFY_REASON_STOP_FAILURE: Link switch failure notify
+ * @MLO_LINK_SWITCH_NOTIFY_REASON_STOP_SUCCESS: Link switch success notify
+ */
+enum wlan_mlo_link_switch_notify_reason {
+	MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_PRE_SER,
+	MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_POST_SER,
+	MLO_LINK_SWITCH_NOTIFY_REASON_STOP_FAILURE,
+	MLO_LINK_SWITCH_NOTIFY_REASON_STOP_SUCCESS,
+};
+
 typedef QDF_STATUS
 (*mlo_mgr_link_switch_notifier_cb)(struct wlan_objmgr_vdev *vdev,
-				   struct wlan_mlo_link_switch_req *lswitch_req);
+				   struct wlan_mlo_link_switch_req *lswitch_req,
+				   enum wlan_mlo_link_switch_notify_reason notify_reason);
 
 #ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE
 /*

+ 118 - 41
umac/mlo_mgr/src/wlan_mlo_mgr_link_switch.c

@@ -274,7 +274,7 @@ bool mlo_mgr_is_link_switch_in_progress(struct wlan_objmgr_vdev *vdev)
 		return false;
 
 	state = mlo_mgr_link_switch_get_curr_state(mlo_dev_ctx);
-	return (state != MLO_LINK_SWITCH_STATE_IDLE);
+	return (state > MLO_LINK_SWITCH_STATE_INIT);
 }
 
 bool mlo_mgr_is_link_switch_on_assoc_vdev(struct wlan_objmgr_vdev *vdev)
@@ -302,6 +302,9 @@ mlo_mgr_link_switch_trans_next_state(struct wlan_mlo_dev_context *mlo_dev_ctx)
 	cur_state = mlo_dev_ctx->link_ctx->last_req.state;
 	switch (cur_state) {
 	case MLO_LINK_SWITCH_STATE_IDLE:
+		next_state = MLO_LINK_SWITCH_STATE_INIT;
+		break;
+	case MLO_LINK_SWITCH_STATE_INIT:
 		next_state = MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK;
 		break;
 	case MLO_LINK_SWITCH_STATE_DISCONNECT_CURR_LINK:
@@ -317,7 +320,7 @@ mlo_mgr_link_switch_trans_next_state(struct wlan_mlo_dev_context *mlo_dev_ctx)
 		next_state = MLO_LINK_SWITCH_STATE_IDLE;
 		break;
 	case MLO_LINK_SWITCH_STATE_ABORT_TRANS:
-		next_state = MLO_LINK_SWITCH_STATE_ABORT_TRANS;
+		next_state = cur_state;
 		status = QDF_STATUS_E_PERM;
 		mlo_debug("State transition not allowed");
 		break;
@@ -376,8 +379,9 @@ mlo_mgr_reset_roam_state_for_link_vdev(struct wlan_objmgr_vdev *vdev,
 {}
 #endif
 
-QDF_STATUS mlo_mgr_link_switch_notification(struct wlan_objmgr_vdev *vdev,
-					    struct wlan_mlo_link_switch_req *lswitch_req)
+static QDF_STATUS
+mlo_mgr_link_switch_osif_notification(struct wlan_objmgr_vdev *vdev,
+				      struct wlan_mlo_link_switch_req *lswitch_req)
 {
 	uint8_t idx;
 	uint16_t vdev_count;
@@ -410,6 +414,9 @@ QDF_STATUS mlo_mgr_link_switch_notification(struct wlan_objmgr_vdev *vdev,
 		lswitch_req->restore_vdev_flag = false;
 
 		status = cb(assoc_vdev, wlan_vdev_get_id(vdev));
+		if (QDF_IS_STATUS_ERROR(status))
+			mlo_debug("OSIF deflink restore failed");
+
 		return status;
 	}
 
@@ -440,6 +447,20 @@ QDF_STATUS mlo_mgr_link_switch_notification(struct wlan_objmgr_vdev *vdev,
 	return status;
 }
 
+QDF_STATUS
+mlo_mgr_link_switch_notification(struct wlan_objmgr_vdev *vdev,
+				 struct wlan_mlo_link_switch_req *lswitch_req,
+				 enum wlan_mlo_link_switch_notify_reason notify_reason)
+{
+	QDF_STATUS status;
+
+	if (notify_reason == MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_PRE_SER)
+		return QDF_STATUS_SUCCESS;
+
+	status = mlo_mgr_link_switch_osif_notification(vdev, lswitch_req);
+	return status;
+}
+
 QDF_STATUS mlo_mgr_link_switch_init(struct wlan_mlo_dev_context *ml_dev)
 {
 	ml_dev->link_ctx =
@@ -536,8 +557,11 @@ QDF_STATUS mlo_mgr_link_switch_disconnect_done(struct wlan_objmgr_vdev *vdev,
 	}
 
 	status = wlan_vdev_mlme_send_set_mac_addr(mac_addr, mld_addr, vdev);
-	if (QDF_IS_STATUS_ERROR(status))
+	if (QDF_IS_STATUS_ERROR(status)) {
+		mlo_debug("VDEV %d set MAC addr FW request failed",
+			  req->vdev_id);
 		mlo_mgr_remove_link_switch_cmd(vdev);
+	}
 
 	return status;
 }
@@ -586,6 +610,12 @@ QDF_STATUS mlo_mgr_link_switch_set_mac_addr_resp(struct wlan_objmgr_vdev *vdev,
 							req->curr_ieee_link_id,
 							req->new_ieee_link_id,
 							req->vdev_id);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		mlo_debug("VDEV %d OSIF MAC addr update failed %d",
+			  req->vdev_id, status);
+		mlo_mgr_remove_link_switch_cmd(vdev);
+		return status;
+	}
 
 	status = mlo_mgr_link_switch_trans_next_state(vdev->mlo_dev_ctx);
 	if (QDF_IS_STATUS_ERROR(status)) {
@@ -674,34 +704,48 @@ void mlo_mgr_link_switch_connect_done(struct wlan_objmgr_vdev *vdev,
 	mlo_mgr_remove_link_switch_cmd(vdev);
 }
 
+static enum wlan_mlo_link_switch_notify_reason
+mlo_mgr_link_switch_get_notify_reason(struct wlan_objmgr_vdev *vdev)
+{
+	enum mlo_link_switch_req_state curr_state;
+	enum wlan_mlo_link_switch_notify_reason notify_reason;
+
+	curr_state = mlo_mgr_link_switch_get_curr_state(vdev->mlo_dev_ctx);
+	switch (curr_state) {
+	case MLO_LINK_SWITCH_STATE_IDLE:
+		notify_reason = MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_PRE_SER;
+		break;
+	case MLO_LINK_SWITCH_STATE_INIT:
+		notify_reason =
+			MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_POST_SER;
+		break;
+	case MLO_LINK_SWITCH_STATE_COMPLETE_SUCCESS:
+		notify_reason = MLO_LINK_SWITCH_NOTIFY_REASON_STOP_SUCCESS;
+		break;
+	default:
+		notify_reason = MLO_LINK_SWITCH_NOTIFY_REASON_STOP_FAILURE;
+		break;
+	}
+
+	return notify_reason;
+}
+
 static QDF_STATUS
 mlo_mgr_start_link_switch(struct wlan_objmgr_vdev *vdev,
 			  struct wlan_serialization_command *cmd)
 {
-	int i;
 	QDF_STATUS status = QDF_STATUS_E_INVAL;
 	uint8_t vdev_id, old_link_id, new_link_id;
-	struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
-	struct mlo_link_switch_context *link_ctx = vdev->mlo_dev_ctx->link_ctx;
-	struct wlan_mlo_link_switch_req *req = &link_ctx->last_req;
+	struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx;
+	struct wlan_mlo_link_switch_req *req = &mlo_dev_ctx->link_ctx->last_req;
 	struct qdf_mac_addr bssid;
 
-	if (!mlo_mgr_ctx) {
-		mlo_err("Global mlo mgr NULL");
-		return status;
-	}
-
 	vdev_id = wlan_vdev_get_id(vdev);
 	old_link_id = req->curr_ieee_link_id;
 	new_link_id = req->new_ieee_link_id;
 
 	mlo_debug("VDEV %d start link switch", vdev_id);
-	if (!wlan_cm_is_vdev_connected(vdev) ||
-	    wlan_vdev_get_link_id(vdev) != old_link_id) {
-		mlo_err("Link switch req link id mismatch, curr link id %d",
-			wlan_vdev_get_link_id(vdev));
-		return status;
-	}
+	mlo_mgr_link_switch_trans_next_state(mlo_dev_ctx);
 
 	if (!wlan_cm_is_vdev_connected(vdev)) {
 		mlo_err("VDEV %d not in connected state", vdev_id);
@@ -716,19 +760,12 @@ mlo_mgr_start_link_switch(struct wlan_objmgr_vdev *vdev,
 	if (QDF_IS_STATUS_ERROR(status))
 		return status;
 
-	for (i = 0; i < WLAN_UMAC_COMP_ID_MAX; i++) {
-		if (!mlo_mgr_ctx->lswitch_notifier[i].in_use)
-			continue;
-
-		status = mlo_mgr_ctx->lswitch_notifier[i].cb(vdev, req);
-		if (QDF_IS_STATUS_ERROR(status)) {
-			mlme_err("Link switch start rejected by %d", i);
-			return status;
-		}
-	}
+	status = mlo_mgr_link_switch_notify(vdev, req);
+	if (QDF_IS_STATUS_ERROR(status))
+		return status;
 
 	wlan_vdev_mlme_set_mlo_link_switch_in_progress(vdev);
-	status = mlo_mgr_link_switch_trans_next_state(vdev->mlo_dev_ctx);
+	status = mlo_mgr_link_switch_trans_next_state(mlo_dev_ctx);
 	if (QDF_IS_STATUS_ERROR(status))
 		return status;
 
@@ -747,6 +784,7 @@ mlo_mgr_ser_link_switch_cb(struct wlan_serialization_command *cmd,
 {
 	struct wlan_objmgr_vdev *vdev;
 	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct wlan_mlo_link_switch_req *req;
 
 	if (!cmd) {
 		mlo_err("cmd is NULL, reason: %d", reason);
@@ -755,9 +793,15 @@ mlo_mgr_ser_link_switch_cb(struct wlan_serialization_command *cmd,
 	}
 
 	vdev = cmd->vdev;
+	req = &vdev->mlo_dev_ctx->link_ctx->last_req;
+
 	switch (reason) {
 	case WLAN_SER_CB_ACTIVATE_CMD:
 		status = mlo_mgr_start_link_switch(vdev, cmd);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			mlo_mgr_link_switch_trans_abort_state(vdev->mlo_dev_ctx);
+			status = mlo_mgr_link_switch_notify(vdev, req);
+		}
 		break;
 	case WLAN_SER_CB_RELEASE_MEM_CMD:
 		mlo_mgr_link_switch_complete(vdev);
@@ -779,25 +823,18 @@ mlo_mgr_ser_link_switch_cb(struct wlan_serialization_command *cmd,
 
 void mlo_mgr_remove_link_switch_cmd(struct wlan_objmgr_vdev *vdev)
 {
-	QDF_STATUS status;
 	struct wlan_serialization_queued_cmd_info cmd_info;
 	enum mlo_link_switch_req_state cur_state;
 	uint8_t vdev_id = wlan_vdev_get_id(vdev);
 	struct wlan_mlo_link_switch_req *req;
 
-	req = &vdev->mlo_dev_ctx->link_ctx->last_req;
-	if (req->restore_vdev_flag) {
-		status = mlo_mgr_link_switch_notification(vdev, req);
-		if (QDF_IS_STATUS_ERROR(status)) {
-			mlo_err("Failed to restore deflink in OSIF");
-			req->restore_vdev_flag = false;
-		}
-	}
-
 	cur_state = mlo_mgr_link_switch_get_curr_state(vdev->mlo_dev_ctx);
 	if (cur_state == MLO_LINK_SWITCH_STATE_IDLE)
 		return;
 
+	req = &vdev->mlo_dev_ctx->link_ctx->last_req;
+	mlo_mgr_link_switch_notify(vdev, req);
+
 	cmd_info.cmd_id = (vdev_id << 16) + (req->new_ieee_link_id << 8) +
 			  (req->curr_ieee_link_id);
 	cmd_info.req_type = WLAN_SER_CANCEL_NON_SCAN_CMD;
@@ -851,6 +888,39 @@ QDF_STATUS mlo_mgr_ser_link_switch_cmd(struct wlan_objmgr_vdev *vdev,
 	return QDF_STATUS_SUCCESS;
 }
 
+QDF_STATUS mlo_mgr_link_switch_notify(struct wlan_objmgr_vdev *vdev,
+				      struct wlan_mlo_link_switch_req *req)
+{
+	int8_t i;
+	QDF_STATUS status, ret_status = QDF_STATUS_SUCCESS;
+	enum wlan_mlo_link_switch_notify_reason notify_reason;
+	struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx();
+
+	if (!mlo_mgr_ctx) {
+		mlo_err("Global mlo mgr NULL");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	notify_reason = mlo_mgr_link_switch_get_notify_reason(vdev);
+	for (i = 0; i < WLAN_UMAC_COMP_ID_MAX; i++) {
+		if (!mlo_mgr_ctx->lswitch_notifier[i].in_use)
+			continue;
+
+		status = mlo_mgr_ctx->lswitch_notifier[i].cb(vdev, req,
+							     notify_reason);
+		if (QDF_IS_STATUS_SUCCESS(status))
+			continue;
+
+		mlo_debug("Link switch notify %d failed in %d",
+			  notify_reason, i);
+		ret_status = status;
+		if (notify_reason == MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_PRE_SER)
+			break;
+	}
+
+	return ret_status;
+}
+
 QDF_STATUS
 mlo_mgr_link_switch_validate_request(struct wlan_objmgr_vdev *vdev,
 				     struct wlan_mlo_link_switch_req *req)
@@ -892,6 +962,13 @@ mlo_mgr_link_switch_validate_request(struct wlan_objmgr_vdev *vdev,
 		return status;
 	}
 
+	/* Notify callers on the new link switch request before serializing */
+	status = mlo_mgr_link_switch_notify(vdev, req);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		mlo_err("Link switch rejected in pre-serialize notify");
+		return status;
+	}
+
 	return QDF_STATUS_SUCCESS;
 }