[v2,06/19] net/mlx5: provide the available tag registers

Message ID 20221006150325.660-7-valex@nvidia.com (mailing list archive)
State Superseded, archived
Delegated to: Raslan Darawsheh
Headers
Series net/mlx5: Add HW steering low level support |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Alex Vesker Oct. 6, 2022, 3:03 p.m. UTC
  From: Bing Zhao <bingz@nvidia.com>

The available tags that can be used by the application are fixed
after startup.

A global array is used to store the information and transfer the TAG
item directly from the ID to the REG_C_x.

Signed-off-by: Bing Zhao <bingz@nvidia.com>
---
 drivers/net/mlx5/linux/mlx5_os.c |  5 ++-
 drivers/net/mlx5/mlx5.c          |  2 +
 drivers/net/mlx5/mlx5.h          |  1 +
 drivers/net/mlx5/mlx5_defs.h     |  2 +
 drivers/net/mlx5/mlx5_flow.c     | 11 +++++
 drivers/net/mlx5/mlx5_flow.h     | 27 ++++++++++++
 drivers/net/mlx5/mlx5_flow_hw.c  | 76 ++++++++++++++++++++++++++++++++
 7 files changed, 123 insertions(+), 1 deletion(-)
  

Patch

diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c
index 1036b870de..1d77b49aac 100644
--- a/drivers/net/mlx5/linux/mlx5_os.c
+++ b/drivers/net/mlx5/linux/mlx5_os.c
@@ -1543,8 +1543,11 @@  mlx5_dev_spawn(struct rte_device *dpdk_dev,
 	rte_rwlock_init(&priv->ind_tbls_lock);
 	if (priv->vport_meta_mask)
 		flow_hw_set_port_info(eth_dev);
-	if (priv->sh->config.dv_flow_en == 2)
+	if (priv->sh->config.dv_flow_en == 2) {
+		/* Only HWS requires this information. */
+		flow_hw_init_tags_set(eth_dev);
 		return eth_dev;
+	}
 	/* Port representor shares the same max priority with pf port. */
 	if (!priv->sh->flow_priority_check_flag) {
 		/* Supported Verbs flow priority number detection. */
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index ad561bd86d..cb1a670954 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -1946,6 +1946,8 @@  mlx5_dev_close(struct rte_eth_dev *dev)
 	flow_hw_resource_release(dev);
 #endif
 	flow_hw_clear_port_info(dev);
+	if (priv->sh->config.dv_flow_en == 2)
+		flow_hw_clear_tags_set(dev);
 	if (priv->rxq_privs != NULL) {
 		/* XXX race condition if mlx5_rx_burst() is still running. */
 		rte_delay_us_sleep(1000);
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index 95ecbea39e..ea63c29bf9 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -1200,6 +1200,7 @@  struct mlx5_dev_ctx_shared {
 	uint32_t drop_action_check_flag:1; /* Check Flag for drop action. */
 	uint32_t flow_priority_check_flag:1; /* Check Flag for flow priority. */
 	uint32_t metadata_regc_check_flag:1; /* Check Flag for metadata REGC. */
+	uint32_t hws_tags:1; /* Check if tags info for HWS initialized. */
 	uint32_t max_port; /* Maximal IB device port index. */
 	struct mlx5_bond_info bond; /* Bonding information. */
 	struct mlx5_common_device *cdev; /* Backend mlx5 device. */
diff --git a/drivers/net/mlx5/mlx5_defs.h b/drivers/net/mlx5/mlx5_defs.h
index 018d3f0f0c..585afb0a98 100644
--- a/drivers/net/mlx5/mlx5_defs.h
+++ b/drivers/net/mlx5/mlx5_defs.h
@@ -139,6 +139,8 @@ 
 #define MLX5_XMETA_MODE_META32 2
 /* Provide info on patrial hw miss. Implies MLX5_XMETA_MODE_META16 */
 #define MLX5_XMETA_MODE_MISS_INFO 3
+/* Only valid in HWS, 32bits extended META without MARK support in FDB. */
+#define MLX5_XMETA_MODE_META32_HWS 4
 
 /* Tx accurate scheduling on timestamps parameters. */
 #define MLX5_TXPP_WAIT_INIT_TS 1000ul /* How long to wait timestamp. */
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index acf1467bf6..45109001ca 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -39,6 +39,17 @@ 
  */
 struct flow_hw_port_info mlx5_flow_hw_port_infos[RTE_MAX_ETHPORTS];
 
+/*
+ * A global structure to save the available REG_C_x for tags usage.
+ * The Meter color REG (ASO) and the last available one will be reserved
+ * for PMD internal usage.
+ * Since there is no "port" concept in the driver, it is assumed that the
+ * available tags set will be the minimum intersection.
+ * 3 - in FDB mode / 5 - in legacy mode
+ */
+uint32_t mlx5_flow_hw_avl_tags_init_cnt;
+enum modify_reg mlx5_flow_hw_avl_tags[MLX5_FLOW_HW_TAGS_MAX] = {REG_NON};
+
 struct tunnel_default_miss_ctx {
 	uint16_t *queue;
 	__extension__
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 2eb2b46060..cae1a64def 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -1328,6 +1328,10 @@  struct flow_hw_port_info {
 
 extern struct flow_hw_port_info mlx5_flow_hw_port_infos[RTE_MAX_ETHPORTS];
 
+#define MLX5_FLOW_HW_TAGS_MAX 8
+extern uint32_t mlx5_flow_hw_avl_tags_init_cnt;
+extern enum modify_reg mlx5_flow_hw_avl_tags[];
+
 /*
  * Get metadata match tag and mask for given rte_eth_dev port.
  * Used in HWS rule creation.
@@ -1367,9 +1371,32 @@  flow_hw_get_wire_port(struct ibv_context *ibctx)
 	return NULL;
 }
 
+/*
+ * Convert metadata or tag to the actual register.
+ * META: Can only be used to match in the FDB in this stage, fixed C_1.
+ * TAG: C_x expect meter color reg and the reserved ones.
+ * TODO: Per port / device, FDB or NIC for Meta matching.
+ */
+static __rte_always_inline int
+flow_hw_get_reg_id(enum rte_flow_item_type type, uint32_t id)
+{
+	switch (type) {
+	case RTE_FLOW_ITEM_TYPE_META:
+		return REG_C_1;
+	case RTE_FLOW_ITEM_TYPE_TAG:
+		MLX5_ASSERT(id < MLX5_FLOW_HW_TAGS_MAX);
+		return mlx5_flow_hw_avl_tags[id];
+	default:
+		return REG_NON;
+	}
+}
+
 void flow_hw_set_port_info(struct rte_eth_dev *dev);
 void flow_hw_clear_port_info(struct rte_eth_dev *dev);
 
+void flow_hw_init_tags_set(struct rte_eth_dev *dev);
+void flow_hw_clear_tags_set(struct rte_eth_dev *dev);
+
 typedef int (*mlx5_flow_validate_t)(struct rte_eth_dev *dev,
 				    const struct rte_flow_attr *attr,
 				    const struct rte_flow_item items[],
diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c
index fe809a83b9..78c741bb91 100644
--- a/drivers/net/mlx5/mlx5_flow_hw.c
+++ b/drivers/net/mlx5/mlx5_flow_hw.c
@@ -2237,6 +2237,82 @@  flow_hw_clear_port_info(struct rte_eth_dev *dev)
 	info->is_wire = 0;
 }
 
+/*
+ * Initialize the information of available tag registers and an intersection
+ * of all the probed devices' REG_C_Xs.
+ * PS. No port concept in steering part, right now it cannot be per port level.
+ *
+ * @param[in] dev
+ *   Pointer to the rte_eth_dev structure.
+ */
+void flow_hw_init_tags_set(struct rte_eth_dev *dev)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	uint32_t meta_mode = priv->sh->config.dv_xmeta_en;
+	uint8_t masks = (uint8_t)priv->sh->cdev->config.hca_attr.set_reg_c;
+	uint32_t i, j;
+	enum modify_reg copy[MLX5_FLOW_HW_TAGS_MAX] = {REG_NON};
+	uint8_t unset = 0;
+	uint8_t copy_masks = 0;
+
+	/*
+	 * The CAPA is global for common device but only used in net.
+	 * It is shared per eswitch domain.
+	 */
+	if (!!priv->sh->hws_tags)
+		return;
+	unset |= 1 << (priv->mtr_color_reg - REG_C_0);
+	unset |= 1 << (REG_C_6 - REG_C_0);
+	if (meta_mode == MLX5_XMETA_MODE_META32_HWS) {
+		unset |= 1 << (REG_C_1 - REG_C_0);
+		unset |= 1 << (REG_C_0 - REG_C_0);
+	}
+	masks &= ~unset;
+	if (mlx5_flow_hw_avl_tags_init_cnt) {
+		for (i = 0; i < MLX5_FLOW_HW_TAGS_MAX; i++) {
+			if (mlx5_flow_hw_avl_tags[i] != REG_NON && !!((1 << i) & masks)) {
+				copy[mlx5_flow_hw_avl_tags[i] - REG_C_0] =
+						mlx5_flow_hw_avl_tags[i];
+				copy_masks |= (1 << i);
+			}
+		}
+		if (copy_masks != masks) {
+			j = 0;
+			for (i = 0; i < MLX5_FLOW_HW_TAGS_MAX; i++)
+				if (!!((1 << i) & copy_masks))
+					mlx5_flow_hw_avl_tags[j++] = copy[i];
+		}
+	} else {
+		j = 0;
+		for (i = 0; i < MLX5_FLOW_HW_TAGS_MAX; i++) {
+			if (!!((1 << i) & masks))
+				mlx5_flow_hw_avl_tags[j++] =
+					(enum modify_reg)(i + (uint32_t)REG_C_0);
+		}
+	}
+	priv->sh->hws_tags = 1;
+	mlx5_flow_hw_avl_tags_init_cnt++;
+}
+
+/*
+ * Reset the available tag registers information to NONE.
+ *
+ * @param[in] dev
+ *   Pointer to the rte_eth_dev structure.
+ */
+void flow_hw_clear_tags_set(struct rte_eth_dev *dev)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+
+	if (!priv->sh->hws_tags)
+		return;
+	priv->sh->hws_tags = 0;
+	mlx5_flow_hw_avl_tags_init_cnt--;
+	if (!mlx5_flow_hw_avl_tags_init_cnt)
+		memset(mlx5_flow_hw_avl_tags, REG_NON,
+		       sizeof(enum modify_reg) * MLX5_FLOW_HW_TAGS_MAX);
+}
+
 /**
  * Create shared action.
  *