[07/13] net/mlx5: add hairpin binding function

Message ID 1569479349-36962-8-git-send-email-orika@mellanox.com (mailing list archive)
State Superseded, archived
Delegated to: Ferruh Yigit
Headers
Series add hairpin feature |

Checks

Context Check Description
ci/Intel-compilation success Compilation OK
ci/checkpatch success coding style OK

Commit Message

Ori Kam Sept. 26, 2019, 6:29 a.m. UTC
  When starting the port, in addition to creating the queues
we need to bind the hairpin queues.

Signed-off-by: Ori Kam <orika@mellanox.com>
---
 drivers/net/mlx5/mlx5.h           |  1 +
 drivers/net/mlx5/mlx5_devx_cmds.c |  1 +
 drivers/net/mlx5/mlx5_prm.h       |  6 +++
 drivers/net/mlx5/mlx5_trigger.c   | 97 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 105 insertions(+)
  

Comments

Slava Ovsiienko Sept. 26, 2019, 9:33 a.m. UTC | #1
> -----Original Message-----
> From: Ori Kam <orika@mellanox.com>
> Sent: Thursday, September 26, 2019 9:29
> To: Matan Azrad <matan@mellanox.com>; Shahaf Shuler
> <shahafs@mellanox.com>; Slava Ovsiienko <viacheslavo@mellanox.com>
> Cc: dev@dpdk.org; Ori Kam <orika@mellanox.com>; jingjing.wu@intel.com;
> stephen@networkplumber.org
> Subject: [PATCH 07/13] net/mlx5: add hairpin binding function
> 
> When starting the port, in addition to creating the queues we need to bind
> the hairpin queues.
> 
> Signed-off-by: Ori Kam <orika@mellanox.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@mellanox.com>

> ---
>  drivers/net/mlx5/mlx5.h           |  1 +
>  drivers/net/mlx5/mlx5_devx_cmds.c |  1 +
>  drivers/net/mlx5/mlx5_prm.h       |  6 +++
>  drivers/net/mlx5/mlx5_trigger.c   | 97
> +++++++++++++++++++++++++++++++++++++++
>  4 files changed, 105 insertions(+)
> 
> diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index
> 506920e..41eb35a 100644
> --- a/drivers/net/mlx5/mlx5.h
> +++ b/drivers/net/mlx5/mlx5.h
> @@ -188,6 +188,7 @@ struct mlx5_hca_attr {
>  	uint32_t log_max_hairpin_queues:5;
>  	uint32_t log_max_hairpin_wq_data_sz:5;
>  	uint32_t log_max_hairpin_num_packets:5;
> +	uint32_t vhca_id:16;
>  };
> 
>  /* Flow list . */
> diff --git a/drivers/net/mlx5/mlx5_devx_cmds.c
> b/drivers/net/mlx5/mlx5_devx_cmds.c
> index 917bbf9..0243733 100644
> --- a/drivers/net/mlx5/mlx5_devx_cmds.c
> +++ b/drivers/net/mlx5/mlx5_devx_cmds.c
> @@ -334,6 +334,7 @@ struct mlx5_devx_obj *
> 
> log_max_hairpin_wq_data_sz);
>  	attr->log_max_hairpin_num_packets = MLX5_GET
>  		(cmd_hca_cap, hcattr, log_min_hairpin_wq_data_sz);
> +	attr->vhca_id = MLX5_GET(cmd_hca_cap, hcattr, vhca_id);
>  	attr->eth_net_offloads = MLX5_GET(cmd_hca_cap, hcattr,
>  					  eth_net_offloads);
>  	attr->eth_virt = MLX5_GET(cmd_hca_cap, hcattr, eth_virt); diff --git
> a/drivers/net/mlx5/mlx5_prm.h b/drivers/net/mlx5/mlx5_prm.h index
> faa7996..d4084db 100644
> --- a/drivers/net/mlx5/mlx5_prm.h
> +++ b/drivers/net/mlx5/mlx5_prm.h
> @@ -1611,6 +1611,12 @@ struct mlx5_ifc_create_rqt_in_bits {  #pragma
> GCC diagnostic error "-Wpedantic"
>  #endif
> 
> +enum {
> +	MLX5_SQC_STATE_RST  = 0x0,
> +	MLX5_SQC_STATE_RDY  = 0x1,
> +	MLX5_SQC_STATE_ERR  = 0x3,
> +};
> +
>  struct mlx5_ifc_sqc_bits {
>  	u8 rlky[0x1];
>  	u8 cd_master[0x1];
> diff --git a/drivers/net/mlx5/mlx5_trigger.c
> b/drivers/net/mlx5/mlx5_trigger.c index 3ec86c4..a4fcdb3 100644
> --- a/drivers/net/mlx5/mlx5_trigger.c
> +++ b/drivers/net/mlx5/mlx5_trigger.c
> @@ -162,6 +162,96 @@
>  }
> 
>  /**
> + * Binds Tx queues to Rx queues for hairpin.
> + *
> + * Binds Tx queues to the target Rx queues.
> + *
> + * @param dev
> + *   Pointer to Ethernet device structure.
> + *
> + * @return
> + *   0 on success, a negative errno value otherwise and rte_errno is set.
> + */
> +static int
> +mlx5_hairpin_bind(struct rte_eth_dev *dev) {
> +	struct mlx5_priv *priv = dev->data->dev_private;
> +	struct mlx5_devx_modify_sq_attr sq_attr = { 0 };
> +	struct mlx5_devx_modify_rq_attr rq_attr = { 0 };
> +	struct mlx5_txq_ctrl *txq_ctrl;
> +	struct mlx5_rxq_ctrl *rxq_ctrl;
> +	struct mlx5_devx_obj *sq;
> +	struct mlx5_devx_obj *rq;
> +	unsigned int i;
> +	int ret = 0;
> +
> +	for (i = 0; i != priv->txqs_n; ++i) {
> +		txq_ctrl = mlx5_txq_get(dev, i);
> +		if (!txq_ctrl)
> +			continue;
> +		if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) {
> +			mlx5_txq_release(dev, i);
> +			continue;
> +		}
> +		if (!txq_ctrl->obj) {
> +			rte_errno = ENOMEM;
> +			DRV_LOG(ERR, "port %u no txq object found: %d",
> +				dev->data->port_id, i);
> +			mlx5_txq_release(dev, i);
> +			return -rte_errno;
> +		}
> +		sq = txq_ctrl->obj->sq;
> +		rxq_ctrl = mlx5_rxq_get(dev,
> +					txq_ctrl-
> >hairpin_conf.peers[0].queue);
> +		if (!rxq_ctrl) {
> +			mlx5_txq_release(dev, i);
> +			rte_errno = EINVAL;
> +			DRV_LOG(ERR, "port %u no rxq object found: %d",
> +				dev->data->port_id,
> +				txq_ctrl->hairpin_conf.peers[0].queue);
> +			return -rte_errno;
> +		}
> +		if (rxq_ctrl->type != MLX5_RXQ_TYPE_HAIRPIN ||
> +		    rxq_ctrl->hairpin_conf.peers[0].queue != i) {
> +			rte_errno = ENOMEM;
> +			DRV_LOG(ERR, "port %u Tx queue %d can't be binded
> to "
> +				"Rx queue %d", dev->data->port_id,
> +				i, txq_ctrl->hairpin_conf.peers[0].queue);
> +			goto error;
> +		}
> +		rq = rxq_ctrl->obj->rq;
> +		if (!rq) {
> +			rte_errno = ENOMEM;
> +			DRV_LOG(ERR, "port %u hairpin no matching rxq:
> %d",
> +				dev->data->port_id,
> +				txq_ctrl->hairpin_conf.peers[0].queue);
> +			goto error;
> +		}
> +		sq_attr.state = MLX5_SQC_STATE_RDY;
> +		sq_attr.sq_state = MLX5_SQC_STATE_RST;
> +		sq_attr.hairpin_peer_rq = rq->id;
> +		sq_attr.hairpin_peer_vhca = priv->config.hca_attr.vhca_id;
> +		ret = mlx5_devx_cmd_modify_sq(sq, &sq_attr);
> +		if (ret)
> +			goto error;
> +		rq_attr.state = MLX5_SQC_STATE_RDY;
> +		rq_attr.rq_state = MLX5_SQC_STATE_RST;
> +		rq_attr.hairpin_peer_sq = sq->id;
> +		rq_attr.hairpin_peer_vhca = priv->config.hca_attr.vhca_id;
> +		ret = mlx5_devx_cmd_modify_rq(rq, &rq_attr);
> +		if (ret)
> +			goto error;
> +		mlx5_txq_release(dev, i);
> +		mlx5_rxq_release(dev, txq_ctrl-
> >hairpin_conf.peers[0].queue);
> +	}
> +	return 0;
> +error:
> +	mlx5_txq_release(dev, i);
> +	mlx5_rxq_release(dev, txq_ctrl->hairpin_conf.peers[0].queue);
> +	return -rte_errno;
> +}
> +
> +/**
>   * DPDK callback to start the device.
>   *
>   * Simulate device start by attaching all configured flows.
> @@ -192,6 +282,13 @@
>  		mlx5_txq_stop(dev);
>  		return -rte_errno;
>  	}
> +	ret = mlx5_hairpin_bind(dev);
> +	if (ret) {
> +		DRV_LOG(ERR, "port %u hairpin binding failed: %s",
> +			dev->data->port_id, strerror(rte_errno));
> +		mlx5_txq_stop(dev);
> +		return -rte_errno;
> +	}
>  	dev->data->dev_started = 1;
>  	ret = mlx5_rx_intr_vec_enable(dev);
>  	if (ret) {
> --
> 1.8.3.1
  

Patch

diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index 506920e..41eb35a 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -188,6 +188,7 @@  struct mlx5_hca_attr {
 	uint32_t log_max_hairpin_queues:5;
 	uint32_t log_max_hairpin_wq_data_sz:5;
 	uint32_t log_max_hairpin_num_packets:5;
+	uint32_t vhca_id:16;
 };
 
 /* Flow list . */
diff --git a/drivers/net/mlx5/mlx5_devx_cmds.c b/drivers/net/mlx5/mlx5_devx_cmds.c
index 917bbf9..0243733 100644
--- a/drivers/net/mlx5/mlx5_devx_cmds.c
+++ b/drivers/net/mlx5/mlx5_devx_cmds.c
@@ -334,6 +334,7 @@  struct mlx5_devx_obj *
 						    log_max_hairpin_wq_data_sz);
 	attr->log_max_hairpin_num_packets = MLX5_GET
 		(cmd_hca_cap, hcattr, log_min_hairpin_wq_data_sz);
+	attr->vhca_id = MLX5_GET(cmd_hca_cap, hcattr, vhca_id);
 	attr->eth_net_offloads = MLX5_GET(cmd_hca_cap, hcattr,
 					  eth_net_offloads);
 	attr->eth_virt = MLX5_GET(cmd_hca_cap, hcattr, eth_virt);
diff --git a/drivers/net/mlx5/mlx5_prm.h b/drivers/net/mlx5/mlx5_prm.h
index faa7996..d4084db 100644
--- a/drivers/net/mlx5/mlx5_prm.h
+++ b/drivers/net/mlx5/mlx5_prm.h
@@ -1611,6 +1611,12 @@  struct mlx5_ifc_create_rqt_in_bits {
 #pragma GCC diagnostic error "-Wpedantic"
 #endif
 
+enum {
+	MLX5_SQC_STATE_RST  = 0x0,
+	MLX5_SQC_STATE_RDY  = 0x1,
+	MLX5_SQC_STATE_ERR  = 0x3,
+};
+
 struct mlx5_ifc_sqc_bits {
 	u8 rlky[0x1];
 	u8 cd_master[0x1];
diff --git a/drivers/net/mlx5/mlx5_trigger.c b/drivers/net/mlx5/mlx5_trigger.c
index 3ec86c4..a4fcdb3 100644
--- a/drivers/net/mlx5/mlx5_trigger.c
+++ b/drivers/net/mlx5/mlx5_trigger.c
@@ -162,6 +162,96 @@ 
 }
 
 /**
+ * Binds Tx queues to Rx queues for hairpin.
+ *
+ * Binds Tx queues to the target Rx queues.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mlx5_hairpin_bind(struct rte_eth_dev *dev)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_devx_modify_sq_attr sq_attr = { 0 };
+	struct mlx5_devx_modify_rq_attr rq_attr = { 0 };
+	struct mlx5_txq_ctrl *txq_ctrl;
+	struct mlx5_rxq_ctrl *rxq_ctrl;
+	struct mlx5_devx_obj *sq;
+	struct mlx5_devx_obj *rq;
+	unsigned int i;
+	int ret = 0;
+
+	for (i = 0; i != priv->txqs_n; ++i) {
+		txq_ctrl = mlx5_txq_get(dev, i);
+		if (!txq_ctrl)
+			continue;
+		if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) {
+			mlx5_txq_release(dev, i);
+			continue;
+		}
+		if (!txq_ctrl->obj) {
+			rte_errno = ENOMEM;
+			DRV_LOG(ERR, "port %u no txq object found: %d",
+				dev->data->port_id, i);
+			mlx5_txq_release(dev, i);
+			return -rte_errno;
+		}
+		sq = txq_ctrl->obj->sq;
+		rxq_ctrl = mlx5_rxq_get(dev,
+					txq_ctrl->hairpin_conf.peers[0].queue);
+		if (!rxq_ctrl) {
+			mlx5_txq_release(dev, i);
+			rte_errno = EINVAL;
+			DRV_LOG(ERR, "port %u no rxq object found: %d",
+				dev->data->port_id,
+				txq_ctrl->hairpin_conf.peers[0].queue);
+			return -rte_errno;
+		}
+		if (rxq_ctrl->type != MLX5_RXQ_TYPE_HAIRPIN ||
+		    rxq_ctrl->hairpin_conf.peers[0].queue != i) {
+			rte_errno = ENOMEM;
+			DRV_LOG(ERR, "port %u Tx queue %d can't be binded to "
+				"Rx queue %d", dev->data->port_id,
+				i, txq_ctrl->hairpin_conf.peers[0].queue);
+			goto error;
+		}
+		rq = rxq_ctrl->obj->rq;
+		if (!rq) {
+			rte_errno = ENOMEM;
+			DRV_LOG(ERR, "port %u hairpin no matching rxq: %d",
+				dev->data->port_id,
+				txq_ctrl->hairpin_conf.peers[0].queue);
+			goto error;
+		}
+		sq_attr.state = MLX5_SQC_STATE_RDY;
+		sq_attr.sq_state = MLX5_SQC_STATE_RST;
+		sq_attr.hairpin_peer_rq = rq->id;
+		sq_attr.hairpin_peer_vhca = priv->config.hca_attr.vhca_id;
+		ret = mlx5_devx_cmd_modify_sq(sq, &sq_attr);
+		if (ret)
+			goto error;
+		rq_attr.state = MLX5_SQC_STATE_RDY;
+		rq_attr.rq_state = MLX5_SQC_STATE_RST;
+		rq_attr.hairpin_peer_sq = sq->id;
+		rq_attr.hairpin_peer_vhca = priv->config.hca_attr.vhca_id;
+		ret = mlx5_devx_cmd_modify_rq(rq, &rq_attr);
+		if (ret)
+			goto error;
+		mlx5_txq_release(dev, i);
+		mlx5_rxq_release(dev, txq_ctrl->hairpin_conf.peers[0].queue);
+	}
+	return 0;
+error:
+	mlx5_txq_release(dev, i);
+	mlx5_rxq_release(dev, txq_ctrl->hairpin_conf.peers[0].queue);
+	return -rte_errno;
+}
+
+/**
  * DPDK callback to start the device.
  *
  * Simulate device start by attaching all configured flows.
@@ -192,6 +282,13 @@ 
 		mlx5_txq_stop(dev);
 		return -rte_errno;
 	}
+	ret = mlx5_hairpin_bind(dev);
+	if (ret) {
+		DRV_LOG(ERR, "port %u hairpin binding failed: %s",
+			dev->data->port_id, strerror(rte_errno));
+		mlx5_txq_stop(dev);
+		return -rte_errno;
+	}
 	dev->data->dev_started = 1;
 	ret = mlx5_rx_intr_vec_enable(dev);
 	if (ret) {