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(+)
@@ -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) {