[07/13] net/mlx5: add hairpin binding function
Checks
Commit Message
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
> -----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
@@ -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 . */
@@ -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);
@@ -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];
@@ -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) {