[03/13] net/mlx5: add port flow configuration

Message ID 20220210162926.20436-4-suanmingm@nvidia.com (mailing list archive)
State Superseded, archived
Delegated to: Raslan Darawsheh
Headers
Series net/mlx5: add hardware steering |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Suanming Mou Feb. 10, 2022, 4:29 p.m. UTC
  The hardware steering is backend to support rte_flow_q API in mlx5
PMD. The port configuration function creates the queues and needed
flow management resources.

The PMD layer configuration function allocates the queues' context
and per-queue job descriptor. The job descriptor size is equal to
the queue size, and the job descriptors will be popped from LIFO
to convey the flow information during flow insertion/destruction.
So when polling the result, the flow information will be extracted
from the descriptor and then the job descriptor will be push back
to the LIFO.

The commit creates the flow port queue and the job descriptors.

Signed-off-by: Suanming Mou <suanmingm@nvidia.com>
---
 drivers/net/mlx5/mlx5.c         |   3 +
 drivers/net/mlx5/mlx5.h         |  26 ++++++-
 drivers/net/mlx5/mlx5_flow.c    |  37 +++++++++
 drivers/net/mlx5/mlx5_flow.h    |   9 +++
 drivers/net/mlx5/mlx5_flow_hw.c | 132 ++++++++++++++++++++++++++++++++
 5 files changed, 206 insertions(+), 1 deletion(-)
  

Patch

diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index a4826a583b..f1933fd253 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -1567,6 +1567,9 @@  mlx5_dev_close(struct rte_eth_dev *dev)
 	/* Free the eCPRI flex parser resource. */
 	mlx5_flex_parser_ecpri_release(dev);
 	mlx5_flex_item_port_cleanup(dev);
+#ifdef HAVE_IBV_FLOW_DV_SUPPORT
+	flow_hw_resource_release(dev);
+#endif
 	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 f3b991e549..31a13ca69a 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -33,7 +33,7 @@ 
 #include "mlx5_utils.h"
 #include "mlx5_os.h"
 #include "mlx5_autoconf.h"
-
+#include "mlx5dr.h"
 
 #define MLX5_SH(dev) (((struct mlx5_priv *)(dev)->data->dev_private)->sh)
 
@@ -324,6 +324,26 @@  struct mlx5_lb_ctx {
 	uint16_t refcnt; /* Reference count for representors. */
 };
 
+/* HW steering queue job descriptor type. */
+enum {
+	MLX5_HW_Q_JOB_TYPE_CREATE, /* Flow create job type. */
+	MLX5_HW_Q_JOB_TYPE_DESTROY, /* Flow destroy job type. */
+};
+
+/* HW steering flow management job descriptor. */
+struct mlx5_hw_q_job {
+	uint32_t type; /* Job type. */
+	struct rte_flow *flow; /* Flow attached to the job. */
+	void *user_data; /* Job user data. */
+};
+
+/* HW steering job descriptor LIFO header . */
+struct mlx5_hw_q {
+	uint32_t job_idx; /* Free job index. */
+	uint32_t size; /* LIFO size. */
+	struct mlx5_hw_q_job **job; /* LIFO pointer. */
+} __rte_cache_aligned;
+
 #define MLX5_COUNTERS_PER_POOL 512
 #define MLX5_MAX_PENDING_QUERIES 4
 #define MLX5_CNT_CONTAINER_RESIZE 64
@@ -1480,6 +1500,10 @@  struct mlx5_priv {
 	struct mlx5_flex_item flex_item[MLX5_PORT_FLEX_ITEM_NUM];
 	/* Flex items have been created on the port. */
 	uint32_t flex_item_map; /* Map of allocated flex item elements. */
+	struct mlx5dr_context *dr_ctx; /**< HW steering DR context. */
+	uint32_t nb_queue; /* HW steering queue number. */
+	/* HW steering queue polling mechanism job descriptor LIFO. */
+	struct mlx5_hw_q *hw_q;
 };
 
 #define PORT_ID(priv) ((priv)->dev_data->port_id)
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 21d17aca44..5ff96642b4 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -805,6 +805,12 @@  static int
 mlx5_flow_flex_item_release(struct rte_eth_dev *dev,
 			    const struct rte_flow_item_flex_handle *handle,
 			    struct rte_flow_error *error);
+static int
+mlx5_flow_port_configure(struct rte_eth_dev *dev,
+			 const struct rte_flow_port_attr *port_attr,
+			 uint16_t nb_queue,
+			 const struct rte_flow_queue_attr *queue_attr[],
+			 struct rte_flow_error *err);
 
 static const struct rte_flow_ops mlx5_flow_ops = {
 	.validate = mlx5_flow_validate,
@@ -826,6 +832,7 @@  static const struct rte_flow_ops mlx5_flow_ops = {
 	.get_restore_info = mlx5_flow_tunnel_get_restore_info,
 	.flex_item_create = mlx5_flow_flex_item_create,
 	.flex_item_release = mlx5_flow_flex_item_release,
+	.configure = mlx5_flow_port_configure,
 };
 
 /* Tunnel information. */
@@ -7814,6 +7821,36 @@  mlx5_counter_query(struct rte_eth_dev *dev, uint32_t cnt,
 	return -ENOTSUP;
 }
 
+/**
+ * Configure port HWS resources.
+ *
+ * @param[in] dev
+ *   Pointer to the rte_eth_dev structure.
+ * @param[in] port_attr
+ *   Port configuration attributes.
+ * @param[in] nb_queue
+ *   Number of queue.
+ * @param[in] queue_attr
+ *   Array that holds attributes for each flow queue.
+ * @param[out] error
+ *   Pointer to error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mlx5_flow_port_configure(struct rte_eth_dev *dev,
+			 const struct rte_flow_port_attr *port_attr,
+			 uint16_t nb_queue,
+			 const struct rte_flow_queue_attr *queue_attr[],
+			 struct rte_flow_error *err)
+{
+	const struct mlx5_flow_driver_ops *fops =
+			flow_get_drv_ops(MLX5_FLOW_TYPE_HW);
+
+	return fops->configure(dev, port_attr, nb_queue, queue_attr, err);
+}
+
 /**
  * Allocate a new memory for the counter values wrapped by all the needed
  * management.
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 26f5d97a7d..731478ff05 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -1257,6 +1257,12 @@  typedef int (*mlx5_flow_item_update_t)
 			 const struct rte_flow_item_flex_handle *handle,
 			 const struct rte_flow_item_flex_conf *conf,
 			 struct rte_flow_error *error);
+typedef int (*mlx5_flow_port_configure_t)
+			(struct rte_eth_dev *dev,
+			 const struct rte_flow_port_attr *port_attr,
+			 uint16_t nb_queue,
+			 const struct rte_flow_queue_attr *queue_attr[],
+			 struct rte_flow_error *err);
 
 struct mlx5_flow_driver_ops {
 	mlx5_flow_validate_t validate;
@@ -1295,6 +1301,7 @@  struct mlx5_flow_driver_ops {
 	mlx5_flow_item_create_t item_create;
 	mlx5_flow_item_release_t item_release;
 	mlx5_flow_item_update_t item_update;
+	mlx5_flow_port_configure_t configure;
 };
 
 /* mlx5_flow.c */
@@ -1767,4 +1774,6 @@  const struct mlx5_flow_tunnel *
 mlx5_get_tof(const struct rte_flow_item *items,
 	     const struct rte_flow_action *actions,
 	     enum mlx5_tof_rule_type *rule_type);
+void
+flow_hw_resource_release(struct rte_eth_dev *dev);
 #endif /* RTE_PMD_MLX5_FLOW_H_ */
diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c
index 33875c7d08..4194f81ee9 100644
--- a/drivers/net/mlx5/mlx5_flow_hw.c
+++ b/drivers/net/mlx5/mlx5_flow_hw.c
@@ -4,10 +4,142 @@ 
 
 #include <rte_flow.h>
 
+#include <mlx5_malloc.h>
+#include "mlx5_defs.h"
 #include "mlx5_flow.h"
 
 #ifdef HAVE_IBV_FLOW_DV_SUPPORT
 
 const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops;
 
+/**
+ * Configure port HWS resources.
+ *
+ * @param[in] dev
+ *   Pointer to the rte_eth_dev structure.
+ * @param[in] port_attr
+ *   Port configuration attributes.
+ * @param[in] nb_queue
+ *   Number of queue.
+ * @param[in] queue_attr
+ *   Array that holds attributes for each flow queue.
+ * @param[out] error
+ *   Pointer to error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+flow_hw_configure(struct rte_eth_dev *dev,
+		  const struct rte_flow_port_attr *port_attr,
+		  uint16_t nb_queue,
+		  const struct rte_flow_queue_attr *queue_attr[],
+		  struct rte_flow_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5dr_context *dr_ctx = NULL;
+	struct mlx5dr_context_attr dr_ctx_attr = {0};
+	struct mlx5_hw_q *hw_q;
+	struct mlx5_hw_q_job *job = NULL;
+	uint32_t mem_size, i, j;
+
+	if (!port_attr || !nb_queue || !queue_attr) {
+		rte_errno = EINVAL;
+		goto err;
+	}
+	/* In case re-configuring, release existing context at first. */
+	if (priv->dr_ctx) {
+		/* */
+		for (i = 0; i < nb_queue; i++) {
+			hw_q = &priv->hw_q[i];
+			/* Make sure all queues are empty. */
+			if (hw_q->size != hw_q->job_idx) {
+				rte_errno = EBUSY;
+				goto err;
+			}
+		}
+		flow_hw_resource_release(dev);
+	}
+	/* Allocate the queue job descriptor LIFO. */
+	mem_size = sizeof(priv->hw_q[0]) * nb_queue;
+	for (i = 0; i < nb_queue; i++) {
+		/*
+		 * Check if the queues' size are all the same as the
+		 * limitation from HWS layer.
+		 */
+		if (queue_attr[i]->size != queue_attr[0]->size) {
+			rte_errno = EINVAL;
+			goto err;
+		}
+		mem_size += (sizeof(struct mlx5_hw_q_job *) +
+			    sizeof(struct mlx5_hw_q_job)) *
+			    queue_attr[0]->size;
+	}
+	priv->hw_q = mlx5_malloc(MLX5_MEM_ZERO, mem_size,
+				 64, SOCKET_ID_ANY);
+	if (!priv->hw_q) {
+		rte_errno = ENOMEM;
+		goto err;
+	}
+	for (i = 0; i < nb_queue; i++) {
+		priv->hw_q[i].job_idx = queue_attr[i]->size;
+		priv->hw_q[i].size = queue_attr[i]->size;
+		if (i == 0)
+			priv->hw_q[i].job = (struct mlx5_hw_q_job **)
+					    &priv->hw_q[nb_queue];
+		else
+			priv->hw_q[i].job = (struct mlx5_hw_q_job **)
+					    &job[queue_attr[i - 1]->size];
+		job = (struct mlx5_hw_q_job *)
+		      &priv->hw_q[i].job[queue_attr[i]->size];
+		for (j = 0; j < queue_attr[i]->size; j++)
+			priv->hw_q[i].job[j] = &job[j];
+	}
+	dr_ctx_attr.pd = priv->sh->cdev->pd;
+	dr_ctx_attr.queues = nb_queue;
+	/* Queue size should all be the same. Take the first one. */
+	dr_ctx_attr.queue_size = queue_attr[0]->size;
+	dr_ctx = mlx5dr_context_open(priv->sh->cdev->ctx, &dr_ctx_attr);
+	/* rte_errno has been updated by HWS layer. */
+	if (!dr_ctx)
+		goto err;
+	priv->dr_ctx = dr_ctx;
+	priv->nb_queue = nb_queue;
+	return 0;
+err:
+	if (dr_ctx)
+		claim_zero(mlx5dr_context_close(dr_ctx));
+	if (priv->hw_q) {
+		mlx5_free(priv->hw_q);
+		priv->hw_q = NULL;
+	}
+	return rte_flow_error_set(error, rte_errno,
+				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				  "fail to configure port");
+}
+
+/**
+ * Release HWS resources.
+ *
+ * @param[in] dev
+ *   Pointer to the rte_eth_dev structure.
+ */
+void
+flow_hw_resource_release(struct rte_eth_dev *dev)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+
+	if (!priv->dr_ctx)
+		return;
+	mlx5_free(priv->hw_q);
+	priv->hw_q = NULL;
+	claim_zero(mlx5dr_context_close(priv->dr_ctx));
+	priv->dr_ctx = NULL;
+	priv->nb_queue = 0;
+}
+
+const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops = {
+	.configure = flow_hw_configure,
+};
+
 #endif