Explorar o código

qcacmn: Add API for bridge vdev handing

Add APIs to populate, destroy and get bridge vdev count.

Also send bridge VDEV details in partner link info via
VDEV START command to target.

Change-Id: Iea155b09051b6724d07cf2b6052a07c1d3beb7e8
CRs-Fixed: 3567098
Shreedhar Parande %!s(int64=2) %!d(string=hai) anos
pai
achega
b4db727551

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

@@ -420,8 +420,10 @@ struct wlan_objmgr_vdev_objmgr {
 	uint16_t wlan_peer_count;
 #ifdef WLAN_FEATURE_11BE_MLO
 	qdf_atomic_t wlan_ml_peer_count;
+#ifdef WLAN_MLO_MULTI_CHIP
 	bool mlo_bridge_vdev;
 	bool mlo_central_vdev;
+#endif
 #endif
 	uint16_t max_peer_count;
 	uint32_t c_flags;
@@ -1652,6 +1654,24 @@ static inline bool wlan_vdev_mlme_is_ap(struct wlan_objmgr_vdev *vdev)
  */
 bool wlan_vdev_mlme_is_mlo_vdev(struct wlan_objmgr_vdev *vdev);
 
+#ifdef WLAN_MLO_MULTI_CHIP
+/**
+ * wlan_vdev_mlme_is_mlo_bridge_vdev() - check if it is bridge vdev
+ * @vdev: Object manager VDEV object
+ *
+ * API to get if given vdev is bridge vdev or not
+ *
+ * Return: True if it is bridge vdev, otherwise false.
+ */
+bool wlan_vdev_mlme_is_mlo_bridge_vdev(struct wlan_objmgr_vdev *vdev);
+#else
+static inline bool
+wlan_vdev_mlme_is_mlo_bridge_vdev(struct wlan_objmgr_vdev *vdev)
+{
+	return false;
+}
+#endif
+
 /**
  * wlan_vdev_mlme_is_tdls_vdev() - Determine whether the given vdev is tdls MLO
  * vdev or not

+ 10 - 0
umac/cmn_services/obj_mgr/src/wlan_objmgr_vdev_obj.c

@@ -1529,6 +1529,16 @@ bool wlan_vdev_mlme_is_mlo_vdev(struct wlan_objmgr_vdev *vdev)
 
 qdf_export_symbol(wlan_vdev_mlme_is_mlo_vdev);
 
+#ifdef WLAN_MLO_MULTI_CHIP
+bool wlan_vdev_mlme_is_mlo_bridge_vdev(struct wlan_objmgr_vdev *vdev)
+{
+	if (!vdev)
+		return false;
+
+	return vdev->vdev_objmgr.mlo_bridge_vdev;
+}
+#endif
+
 void wlan_vdev_mlme_set_epcs_flag(struct wlan_objmgr_vdev *vdev, bool flag)
 {
 	if (!vdev) {

+ 72 - 2
umac/mlme/vdev_mgr/core/src/vdev_mgr_ops.c

@@ -260,6 +260,66 @@ vdev_mgr_start_param_update_mlo_mcast(struct wlan_objmgr_vdev *vdev,
 #define vdev_mgr_start_param_update_mlo_mcast(vdev, param)
 #endif
 
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP)
+static QDF_STATUS
+mlo_ap_append_bridge_vdevs(struct wlan_objmgr_vdev *vdev,
+			   struct mlo_vdev_start_partner_links *mlo_ptr,
+			   uint8_t p_idx)
+{
+	struct wlan_objmgr_vdev *bridge_vdev_list[WLAN_UMAC_MLO_MAX_BRIDGE_VDEVS] = {NULL};
+	struct wlan_objmgr_pdev *pdev;
+	uint16_t num_links = 0;
+	uint8_t i = 0;
+
+	if (!vdev || !mlo_ptr)
+		return QDF_STATUS_E_FAILURE;
+
+	if (p_idx >= WLAN_UMAC_MLO_MAX_VDEVS)
+		return QDF_STATUS_E_FAILURE;
+
+	mlo_ap_get_bridge_vdev_list(vdev, &num_links, bridge_vdev_list);
+	if (!num_links)
+		return QDF_STATUS_SUCCESS;
+
+	if (num_links > QDF_ARRAY_SIZE(bridge_vdev_list)) {
+		mlme_err("Invalid number of VDEVs under AP-MLD num_links:%u",
+			 num_links);
+		for (i = 0; i < QDF_ARRAY_SIZE(bridge_vdev_list); i++)
+			mlo_release_vdev_ref(bridge_vdev_list[i]);
+		return QDF_STATUS_E_FAILURE;
+	}
+
+	for (i = 0; i < WLAN_UMAC_MLO_MAX_BRIDGE_VDEVS; i++) {
+		if (bridge_vdev_list[i] == vdev) {
+			mlo_release_vdev_ref(bridge_vdev_list[i]);
+			continue;
+		}
+
+		pdev = wlan_vdev_get_pdev(bridge_vdev_list[i]);
+		mlo_ptr->partner_info[p_idx].vdev_id =
+			wlan_vdev_get_id(bridge_vdev_list[i]);
+		mlo_ptr->partner_info[p_idx].hw_mld_link_id =
+			wlan_mlo_get_pdev_hw_link_id(pdev);
+		qdf_mem_copy(mlo_ptr->partner_info[p_idx].mac_addr,
+			     wlan_vdev_mlme_get_macaddr(bridge_vdev_list[i]),
+			     QDF_MAC_ADDR_SIZE);
+		mlo_release_vdev_ref(bridge_vdev_list[i]);
+		p_idx++;
+	}
+	mlo_ptr->num_links = p_idx;
+
+	return QDF_STATUS_SUCCESS;
+}
+#else
+static inline QDF_STATUS
+mlo_ap_append_bridge_vdevs(struct wlan_objmgr_vdev *vdev,
+			   struct mlo_vdev_start_partner_links *mlo_ptr,
+			   uint8_t p_idx)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 static void
 vdev_mgr_start_param_update_mlo_partner(struct wlan_objmgr_vdev *vdev,
 					struct vdev_start_params *param)
@@ -269,8 +329,13 @@ vdev_mgr_start_param_update_mlo_partner(struct wlan_objmgr_vdev *vdev,
 	struct wlan_objmgr_vdev *vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {NULL};
 	uint16_t num_links = 0;
 	uint8_t i = 0, p_idx = 0;
+	QDF_STATUS status;
+
+	if (wlan_vdev_mlme_is_mlo_bridge_vdev(vdev))
+		mlo_ap_get_vdev_list_no_flag(vdev, &num_links, vdev_list);
+	else
+		mlo_ap_get_vdev_list(vdev, &num_links, vdev_list);
 
-	mlo_ap_get_vdev_list(vdev, &num_links, vdev_list);
 	if (!num_links) {
 		mlme_err("No VDEVs under AP-MLD");
 		return;
@@ -302,6 +367,10 @@ vdev_mgr_start_param_update_mlo_partner(struct wlan_objmgr_vdev *vdev,
 		p_idx++;
 	}
 	mlo_ptr->num_links = p_idx;
+
+	status = mlo_ap_append_bridge_vdevs(vdev, mlo_ptr, p_idx);
+	if (QDF_IS_STATUS_ERROR(status))
+		mlo_err("failed to append bridge vdev to partner link list");
 }
 
 static void
@@ -316,7 +385,8 @@ vdev_mgr_start_param_update_mlo(struct vdev_mlme_obj *mlme_obj,
 		return;
 	}
 
-	if (!wlan_vdev_mlme_is_mlo_vdev(vdev))
+	if (!wlan_vdev_mlme_is_mlo_vdev(vdev) &&
+	    !wlan_vdev_mlme_is_mlo_bridge_vdev(vdev))
 		return;
 
 	param->mlo_flags.mlo_enabled = 1;

+ 4 - 0
umac/mlme/vdev_mgr/dispatcher/inc/wlan_vdev_mgr_tgt_if_tx_defs.h

@@ -650,7 +650,11 @@ struct ml_vdev_start_partner_info {
  */
 struct mlo_vdev_start_partner_links {
 	uint8_t num_links;
+#ifdef WLAN_MLO_MULTI_CHIP
+	struct ml_vdev_start_partner_info partner_info[WLAN_UMAC_MLO_MAX_VDEVS + WLAN_UMAC_MLO_MAX_BRIDGE_VDEVS];
+#else
 	struct ml_vdev_start_partner_info partner_info[WLAN_UMAC_MLO_MAX_VDEVS];
+#endif
 };
 #endif
 /**

+ 76 - 0
umac/mlo_mgr/inc/wlan_mlo_mgr_ap.h

@@ -40,6 +40,82 @@ bool mlo_ap_vdev_attach(struct wlan_objmgr_vdev *vdev,
 			uint8_t link_id,
 			uint16_t vdev_count);
 
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP)
+/**
+ * mlo_ap_get_bridge_vdev_list() - get mlo bridge vdev list
+ * @vdev: vdev pointer
+ * @vdev_count: vdev count
+ * @wlan_bridge_vdev_list: bridge vdev list
+ *
+ * This API gets all partner bridge vdevs.
+ *
+ * It takes references for all vdev's with bit set in the list. Callers
+ * of this API should properly release references before destroying the
+ * list.
+ *
+ * Return: None
+ */
+void mlo_ap_get_bridge_vdev_list(struct wlan_objmgr_vdev *vdev,
+				 uint16_t *vdev_count,
+				 struct wlan_objmgr_vdev **wlan_bridge_vdev_list);
+
+/**
+ * mlo_ap_get_bridge_vdev_count() - get mlo bridge vdev count
+ * @mld_ctx: mld context
+ * @vdev_count: vdev count
+ *
+ * This API gets count of all partner bridge vdevs
+ *
+ * Return: None
+ */
+QDF_STATUS mlo_ap_get_bridge_vdev_count(struct wlan_mlo_dev_context *mld_ctx,
+					uint16_t *vdev_count);
+
+/**
+ * mlo_ap_get_vdev_list_no_flag() - get mlo vdev list
+ * @vdev: vdev pointer
+ * @vdev_count: vdev count
+ * @wlan_vdev_list: vdev list
+ *
+ * This API gets all partner vdev's without checking for WLAN_VDEV_FEXT2_MLO.
+ *
+ * It takes references for all vdev's with bit set in the list. Callers
+ * of this API should properly release references before destroying the
+ * list.
+ *
+ * Return: None
+ */
+void mlo_ap_get_vdev_list_no_flag(struct wlan_objmgr_vdev *vdev,
+				  uint16_t *vdev_count,
+				  struct wlan_objmgr_vdev **wlan_vdev_list);
+#else
+static inline void
+mlo_ap_get_bridge_vdev_list(struct wlan_objmgr_vdev *vdev,
+			    uint16_t *vdev_count,
+			    struct wlan_objmgr_vdev **wlan_bridge_vdev_list)
+{
+}
+
+static inline QDF_STATUS
+mlo_ap_get_bridge_vdev_count(struct wlan_mlo_dev_context *mld_ctx,
+			     uint16_t *vdev_count)
+{
+	if (!vdev_count)
+		return QDF_STATUS_E_NULL_VALUE;
+
+	*vdev_count = 0;
+
+	return QDF_STATUS_SUCCESS;
+}
+
+static inline void
+mlo_ap_get_vdev_list_no_flag(struct wlan_objmgr_vdev *vdev,
+			     uint16_t *vdev_count,
+			     struct wlan_objmgr_vdev **wlan_vdev_list)
+{
+}
+#endif
+
 /**
  * mlo_ap_get_vdev_list() - get mlo vdev list
  * @vdev: vdev pointer

+ 93 - 0
umac/mlo_mgr/src/wlan_mlo_mgr_ap.c

@@ -121,6 +121,99 @@ bool mlo_ap_vdev_attach(struct wlan_objmgr_vdev *vdev,
 }
 #endif
 
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP)
+void mlo_ap_get_bridge_vdev_list(struct wlan_objmgr_vdev *vdev,
+				 uint16_t *vdev_count,
+				 struct wlan_objmgr_vdev **wlan_bridge_vdev_list)
+{
+	struct wlan_mlo_dev_context *dev_ctx;
+	int i;
+	QDF_STATUS status;
+
+	*vdev_count = 0;
+
+	if (!vdev || !vdev->mlo_dev_ctx) {
+		mlo_err("Invalid input");
+		return;
+	}
+
+	dev_ctx = vdev->mlo_dev_ctx;
+
+	mlo_dev_lock_acquire(dev_ctx);
+	*vdev_count = 0;
+	for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_bridge_vdev_list); i++) {
+		if (dev_ctx->wlan_bridge_vdev_list[i]) {
+			status = wlan_objmgr_vdev_try_get_ref(
+						dev_ctx->wlan_bridge_vdev_list[i],
+						WLAN_MLO_MGR_ID);
+			if (QDF_IS_STATUS_ERROR(status))
+				break;
+			wlan_bridge_vdev_list[*vdev_count] =
+				dev_ctx->wlan_bridge_vdev_list[i];
+			(*vdev_count) += 1;
+		}
+	}
+	mlo_dev_lock_release(dev_ctx);
+}
+
+QDF_STATUS mlo_ap_get_bridge_vdev_count(struct wlan_mlo_dev_context *mld_ctx,
+					uint16_t *vdev_count)
+{
+	int i;
+
+	*vdev_count = 0;
+
+	if (!mld_ctx) {
+		mlo_err("Invalid input");
+		return QDF_STATUS_E_NULL_VALUE;
+	}
+
+	mlo_dev_lock_acquire(mld_ctx);
+	*vdev_count = 0;
+	for (i = 0; i < QDF_ARRAY_SIZE(mld_ctx->wlan_bridge_vdev_list); i++) {
+		if (mld_ctx->wlan_bridge_vdev_list[i])
+			(*vdev_count) += 1;
+	}
+	mlo_dev_lock_release(mld_ctx);
+
+	return QDF_STATUS_SUCCESS;
+}
+
+void mlo_ap_get_vdev_list_no_flag(struct wlan_objmgr_vdev *vdev,
+				  uint16_t *vdev_count,
+				  struct wlan_objmgr_vdev **wlan_vdev_list)
+{
+	struct wlan_mlo_dev_context *dev_ctx;
+	int i;
+	QDF_STATUS status;
+
+	*vdev_count = 0;
+
+	if (!vdev || !vdev->mlo_dev_ctx) {
+		mlo_err("Invalid input");
+		return;
+	}
+
+	dev_ctx = vdev->mlo_dev_ctx;
+
+	mlo_dev_lock_acquire(dev_ctx);
+	*vdev_count = 0;
+	for (i = 0; i < QDF_ARRAY_SIZE(dev_ctx->wlan_vdev_list); i++) {
+		if (dev_ctx->wlan_vdev_list[i]) {
+			status = wlan_objmgr_vdev_try_get_ref(
+					dev_ctx->wlan_vdev_list[i],
+					WLAN_MLO_MGR_ID);
+			if (QDF_IS_STATUS_ERROR(status))
+				break;
+			wlan_vdev_list[*vdev_count] =
+				dev_ctx->wlan_vdev_list[i];
+			(*vdev_count) += 1;
+		}
+	}
+	mlo_dev_lock_release(dev_ctx);
+}
+#endif
+
 void mlo_peer_get_vdev_list(struct wlan_objmgr_peer *peer,
 			    uint16_t *vdev_count,
 			    struct wlan_objmgr_vdev **wlan_vdev_list)

+ 95 - 0
umac/mlo_mgr/src/wlan_mlo_mgr_main.c

@@ -706,6 +706,86 @@ static inline void mlo_ptqm_migration_init(struct wlan_mlo_dev_context *ml_dev)
 { }
 #endif
 
+#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_MLO_MULTI_CHIP)
+static QDF_STATUS
+mlo_add_to_bridge_vdev_list(struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_mlo_dev_context *ml_dev;
+	struct qdf_mac_addr *mld_addr;
+	uint8_t id = 0;
+
+	if (!vdev)
+		return QDF_STATUS_E_FAILURE;
+
+	mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
+	ml_dev = wlan_mlo_get_mld_ctx_by_mldaddr(mld_addr);
+
+	if (ml_dev) {
+		mlo_dev_lock_acquire(ml_dev);
+		while (id < WLAN_UMAC_MLO_MAX_BRIDGE_VDEVS) {
+			if (ml_dev->wlan_bridge_vdev_list[id]) {
+				id++;
+				continue;
+			}
+
+			ml_dev->wlan_bridge_vdev_list[id] = vdev;
+			vdev->mlo_dev_ctx = ml_dev;
+			break;
+		}
+		mlo_dev_lock_release(ml_dev);
+
+		if (id == WLAN_UMAC_MLO_MAX_BRIDGE_VDEVS)
+			return QDF_STATUS_E_FAILURE;
+
+		return QDF_STATUS_SUCCESS;
+	}
+
+	return QDF_STATUS_E_FAILURE;
+}
+
+static QDF_STATUS
+mld_delete_from_bridge_vdev_list(struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_mlo_dev_context *ml_dev;
+	struct qdf_mac_addr *mld_addr;
+	uint8_t id = 0;
+
+	if (!vdev)
+		return QDF_STATUS_E_FAILURE;
+
+	mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
+	ml_dev = wlan_mlo_get_mld_ctx_by_mldaddr(mld_addr);
+
+	if (ml_dev) {
+		mlo_dev_lock_acquire(ml_dev);
+		while (id < WLAN_UMAC_MLO_MAX_BRIDGE_VDEVS) {
+			if (ml_dev->wlan_bridge_vdev_list[id] == vdev) {
+				vdev->mlo_dev_ctx = NULL;
+				ml_dev->wlan_bridge_vdev_list[id] = NULL;
+				break;
+			}
+			id++;
+		}
+		mlo_dev_lock_release(ml_dev);
+		return QDF_STATUS_SUCCESS;
+	}
+
+	return QDF_STATUS_E_FAILURE;
+}
+#else
+static QDF_STATUS
+mlo_add_to_bridge_vdev_list(struct wlan_objmgr_vdev *vdev)
+{
+	return QDF_STATUS_SUCCESS;
+}
+
+static QDF_STATUS
+mld_delete_from_bridge_vdev_list(struct wlan_objmgr_vdev *vdev)
+{
+	return QDF_STATUS_SUCCESS;
+}
+#endif
+
 static QDF_STATUS mlo_dev_ctx_init(struct wlan_objmgr_vdev *vdev)
 {
 	struct wlan_mlo_dev_context *ml_dev;
@@ -714,6 +794,13 @@ static QDF_STATUS mlo_dev_ctx_init(struct wlan_objmgr_vdev *vdev)
 	struct mlo_mgr_context *g_mlo_ctx = wlan_objmgr_get_mlo_ctx();
 	uint8_t id = 0;
 
+	if (wlan_vdev_mlme_is_mlo_bridge_vdev(vdev)) {
+		status = mlo_add_to_bridge_vdev_list(vdev);
+		if (!QDF_IS_STATUS_SUCCESS(status))
+			mlo_err("Failed to init bridge vap ctx");
+		return status;
+	}
+
 	mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev);
 	ml_dev = wlan_mlo_get_mld_ctx_by_mldaddr(mld_addr);
 
@@ -876,6 +963,14 @@ static QDF_STATUS mlo_dev_ctx_deinit(struct wlan_objmgr_vdev *vdev)
 
 	mlo_debug("deleting vdev from MLD device ctx "QDF_MAC_ADDR_FMT,
 		  QDF_MAC_ADDR_REF(mld_addr->bytes));
+
+	if (wlan_vdev_mlme_is_mlo_bridge_vdev(vdev)) {
+		status = mld_delete_from_bridge_vdev_list(vdev);
+		if (!QDF_IS_STATUS_SUCCESS(status))
+			mlo_err("Failed to deinit bridge vap ctx");
+		return status;
+	}
+
 	mlo_dev_lock_acquire(ml_dev);
 	while (id < WLAN_UMAC_MLO_MAX_VDEVS) {
 		if (ml_dev->wlan_vdev_list[id] == vdev) {