浏览代码

qcacmn: Abort connection for next candidate if SAP stop/start is pending

In the case of STA/CLI + STA/CLI, if an STA/CLI is in connecting state
and a disconnect is received on any other STA/CLI, the disconnect can
timeout waiting for the connection on the first STA/CLI to get completed.
This is because the connection is a blocking serialization command and
it can try multiple candidates and thus can take up to 30+ sec to
complete.

Same way if an SAP/GO has a start/stop command or peer disconnect in
pending queue, the delay is processing it can cause timeouts and other
issues.

So abort the next connection attempt if any of the vdev is waiting
for vdev operation to avoid timeouts.

Change-Id: I6570b8213c9008d8fea26febb49d0e40d9180d12
CRs-Fixed: 3354561
abhinav kumar 2 年之前
父节点
当前提交
19ae8a535e

+ 12 - 0
umac/cmn_services/serialization/inc/wlan_serialization_api.h

@@ -532,6 +532,18 @@ wlan_serialization_pdev_scan_status(struct wlan_objmgr_pdev *pdev);
 bool wlan_serialization_is_cmd_present_in_pending_queue(
 		struct wlan_objmgr_psoc *psoc,
 		struct wlan_serialization_command *cmd);
+
+/**
+ * wlan_ser_is_non_scan_cmd_type_in_vdev_queue() - check if a non scan cmd
+ * type is present in pending vdev queue, without checking the cmd id
+ * @vdev: vdev on which cmd need to be check
+ * @cmd_type: command type to check
+ *
+ * Return: true or false
+ */
+bool wlan_ser_is_non_scan_cmd_type_in_vdev_queue(struct wlan_objmgr_vdev *vdev,
+				enum wlan_serialization_cmd_type cmd_type);
+
 /**
  * wlan_serialization_is_cmd_present_in_active_queue() - Return if the command
  *			is already present in active queue

+ 57 - 0
umac/cmn_services/serialization/src/wlan_serialization_api.c

@@ -75,6 +75,63 @@ error:
 	return status;
 }
 
+bool wlan_ser_is_non_scan_cmd_type_in_vdev_queue(struct wlan_objmgr_vdev *vdev,
+				enum wlan_serialization_cmd_type cmd_type)
+{
+	bool found = false;
+	qdf_list_t *queue;
+	struct wlan_objmgr_pdev *pdev;
+	struct wlan_ser_pdev_obj *ser_pdev_obj;
+	struct wlan_ser_vdev_obj *ser_vdev_obj;
+	struct wlan_serialization_pdev_queue *pdev_queue;
+
+	if (!vdev) {
+		ser_err("invalid cmd");
+		goto error;
+	}
+
+	if (cmd_type < WLAN_SER_CMD_NONSCAN) {
+		ser_err("invalid cmd type %d", cmd_type);
+		goto error;
+	}
+
+	pdev = wlan_vdev_get_pdev(vdev);
+	if (!pdev) {
+		ser_err("invalid pdev");
+		goto error;
+	}
+
+	ser_pdev_obj = wlan_serialization_get_pdev_obj(pdev);
+	if (!ser_pdev_obj) {
+		ser_err("invalid ser pdev obj");
+		goto error;
+	}
+
+	pdev_queue = wlan_serialization_get_pdev_queue_obj(ser_pdev_obj,
+							   cmd_type);
+	if (!pdev_queue) {
+		ser_err("pdev_queue is invalid");
+		goto error;
+	}
+	ser_vdev_obj = wlan_serialization_get_vdev_obj(vdev);
+	if (!ser_vdev_obj) {
+		ser_err("invalid ser vdev obj");
+		goto error;
+	}
+
+	wlan_serialization_acquire_lock(&pdev_queue->pdev_queue_lock);
+	queue = wlan_serialization_get_list_from_vdev_queue(ser_vdev_obj,
+							    cmd_type, false);
+	if (wlan_serialization_find_cmd(queue, WLAN_SER_MATCH_CMD_TYPE_VDEV,
+					NULL, cmd_type, NULL, vdev,
+					WLAN_SER_VDEV_NODE))
+		found = true;
+
+	wlan_serialization_release_lock(&pdev_queue->pdev_queue_lock);
+error:
+	return found;
+}
+
 bool wlan_serialization_is_cmd_present_in_active_queue(
 		struct wlan_objmgr_psoc *psoc,
 		struct wlan_serialization_command *cmd)

+ 73 - 30
umac/mlme/connection_mgr/core/src/wlan_cm_connect.c

@@ -761,41 +761,65 @@ static inline QDF_STATUS cm_set_fils_key(struct cnx_mgr *cm_ctx,
 }
 #endif /* WLAN_FEATURE_FILS_SK */
 
-static void cm_get_vdev_id_from_bssid(struct wlan_objmgr_pdev *pdev,
-				   void *object, void *arg)
+/**
+ * cm_get_vdev_id_with_active_vdev_op() - Get vdev id from serialization
+ * pending queue for which disconnect or connect is ongoing
+ * @pdev: pdev common object
+ * @object: vdev object
+ * @arg: vdev operation search arg
+ *
+ * Return: None
+ */
+static void cm_get_vdev_id_with_active_vdev_op(struct wlan_objmgr_pdev *pdev,
+					       void *object, void *arg)
 {
-	uint8_t *vdev_id = arg;
+	struct vdev_op_search_arg *vdev_arg = arg;
 	struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object;
+	uint8_t vdev_id = wlan_vdev_get_id(vdev);
+	enum QDF_OPMODE opmode = wlan_vdev_mlme_get_opmode(vdev);
 
-	if (!vdev_id)
+	if (!vdev_arg)
 		return;
 
-	if (!(wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE ||
-	      wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_CLIENT_MODE))
+	/* Avoid same vdev id check */
+	if (vdev_arg->current_vdev_id == vdev_id)
 		return;
 
-	if (cm_is_vdev_disconnecting(vdev))
-		*vdev_id = wlan_vdev_get_id(vdev);
+	if (opmode == QDF_STA_MODE || opmode == QDF_P2P_CLIENT_MODE) {
+		if (cm_is_vdev_disconnecting(vdev))
+			vdev_arg->sta_cli_vdev_id = vdev_id;
+		return;
+	}
+
+	if (opmode == QDF_SAP_MODE || opmode == QDF_P2P_GO_MODE) {
+		/* Check if START/STOP AP OP is in progress */
+		if (wlan_ser_is_non_scan_cmd_type_in_vdev_queue(vdev,
+					WLAN_SER_CMD_VDEV_START_BSS) ||
+		    wlan_ser_is_non_scan_cmd_type_in_vdev_queue(vdev,
+					WLAN_SER_CMD_VDEV_STOP_BSS))
+			vdev_arg->sap_go_vdev_id = vdev_id;
+		return;
+	}
 }
 
 /**
- * cm_is_any_other_vdev_disconnecting() - check whether any other vdev is in
- * disconnecting state
+ * cm_is_any_other_vdev_connecting_disconnecting() - check whether any other
+ * vdev is in waiting for vdev operations (connect/disconnect or start/stop AP)
  * @cm_ctx: connection manager context
  * @cm_req: Connect request.
  *
- * As Connect is a blocking call this API will make sure the disconnect
- * doesn't timeout on any vdev and thus make sure that PEER/VDEV SM are cleaned
- * before vdev delete is sent.
+ * As Connect is a blocking call this API will make sure the vdev operations on
+ * other vdev doesn't starve
  *
- * Return : true if disconnection is on any vdev_id
+ * Return : true if any other vdev has pending operation
  */
-static bool cm_is_any_other_vdev_disconnecting(struct cnx_mgr *cm_ctx,
-					       struct cm_req *cm_req)
+static bool
+cm_is_any_other_vdev_connecting_disconnecting(struct cnx_mgr *cm_ctx,
+					      struct cm_req *cm_req)
 {
 	struct wlan_objmgr_pdev *pdev;
-	uint8_t vdev_id;
 	uint8_t cur_vdev_id = wlan_vdev_get_id(cm_ctx->vdev);
+	struct vdev_op_search_arg vdev_arg;
 
 	pdev = wlan_vdev_get_pdev(cm_ctx->vdev);
 	if (!pdev) {
@@ -804,16 +828,32 @@ static bool cm_is_any_other_vdev_disconnecting(struct cnx_mgr *cm_ctx,
 		return false;
 	}
 
-	vdev_id = WLAN_INVALID_VDEV_ID;
+	vdev_arg.current_vdev_id = cur_vdev_id;
+	vdev_arg.sap_go_vdev_id = WLAN_INVALID_VDEV_ID;
+	vdev_arg.sta_cli_vdev_id = WLAN_INVALID_VDEV_ID;
 	wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP,
-					  cm_get_vdev_id_from_bssid,
-					  &vdev_id, 0,
+					  cm_get_vdev_id_with_active_vdev_op,
+					  &vdev_arg, 0,
 					  WLAN_MLME_CM_ID);
 
-	if (vdev_id != WLAN_INVALID_VDEV_ID && vdev_id != cur_vdev_id) {
-		mlme_info(CM_PREFIX_FMT "Abort connection as vdev %d is waiting for disconnect",
+	/* For STA/CLI avoid the fist candidate itself if possible */
+	if (vdev_arg.sta_cli_vdev_id != WLAN_INVALID_VDEV_ID) {
+		mlme_info(CM_PREFIX_FMT "Abort connection as sta/cli vdev %d is disconnecting",
 			  CM_PREFIX_REF(cur_vdev_id, cm_req->cm_id),
-			  vdev_id);
+			  vdev_arg.sta_cli_vdev_id);
+		return true;
+	}
+
+	/*
+	 * For SAP/GO ops pending avoid the next candidate, this is to support
+	 * wifi sharing etc use case where we need to connect to AP in parallel
+	 * to SAP operation, so try atleast one candidate.
+	 */
+	if (cm_req->connect_req.cur_candidate &&
+	    vdev_arg.sap_go_vdev_id != WLAN_INVALID_VDEV_ID) {
+		mlme_info(CM_PREFIX_FMT "Avoid next candidate as SAP/GO vdev %d has pending vdev op",
+			  CM_PREFIX_REF(cur_vdev_id, cm_req->cm_id),
+			  vdev_arg.sap_go_vdev_id);
 		return true;
 	}
 
@@ -1050,10 +1090,9 @@ static void cm_teardown_tdls(struct wlan_objmgr_vdev *vdev)
 }
 
 #else
-
-static inline
-bool cm_is_any_other_vdev_disconnecting(struct cnx_mgr *cm_ctx,
-					struct cm_req *cm_req)
+static inline bool
+cm_is_any_other_vdev_connecting_disconnecting(struct cnx_mgr *cm_ctx,
+					      struct cm_req *cm_req)
 {
 	return false;
 }
@@ -1595,10 +1634,14 @@ static QDF_STATUS cm_get_valid_candidate(struct cnx_mgr *cm_ctx,
 	 * This can lead to vdev delete sent without vdev down/stop/peer delete
 	 * for the vdev.
 	 *
-	 * So abort the connection if any of the vdev is waiting for disconnect,
-	 * to avoid disconnect timeout.
+	 * Same way if a SAP/GO has start/stop command or peer disconnect in
+	 * pending queue, delay in processing it can cause timeouts and other
+	 * issues.
+	 *
+	 * So abort the next connection attempt if any of the vdev is waiting
+	 * for vdev operation to avoid timeouts
 	 */
-	if (cm_is_any_other_vdev_disconnecting(cm_ctx, cm_req)) {
+	if (cm_is_any_other_vdev_connecting_disconnecting(cm_ctx, cm_req)) {
 		status = QDF_STATUS_E_FAILURE;
 		goto flush_single_pmk;
 	}

+ 12 - 0
umac/mlme/connection_mgr/core/src/wlan_cm_main.h

@@ -276,6 +276,18 @@ struct cnx_mgr {
 #endif
 };
 
+/**
+ * struct vdev_op_search_arg - vdev op search arguments
+ * @current_vdev_id: current vdev id
+ * @sap_go_vdev_id: sap/go vdev id
+ * @sta_cli_vdev_id: sta/p2p client vdev id
+ */
+struct vdev_op_search_arg {
+	uint8_t current_vdev_id;
+	uint8_t sap_go_vdev_id;
+	uint8_t sta_cli_vdev_id;
+};
+
 /**
  * wlan_cm_init() - Invoke connection manager init
  * @vdev_mlme_obj:  VDEV MLME comp object