net/mlx5: add hairpin binding function
authorOri Kam <orika@mellanox.com>
Wed, 30 Oct 2019 23:53:18 +0000 (23:53 +0000)
committerFerruh Yigit <ferruh.yigit@intel.com>
Fri, 8 Nov 2019 22:15:04 +0000 (23:15 +0100)
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
drivers/net/mlx5/mlx5_devx_cmds.c
drivers/net/mlx5/mlx5_prm.h
drivers/net/mlx5/mlx5_trigger.c

index 742bedd..33cfc5b 100644 (file)
@@ -191,6 +191,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 . */
index a501f1f..3471a9b 100644 (file)
@@ -334,6 +334,7 @@ mlx5_devx_cmd_query_hca_attr(struct ibv_context *ctx,
                                                    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);
index c687cfb..e4b19f8 100644 (file)
@@ -1628,6 +1628,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];
index 3ec86c4..a4fcdb3 100644 (file)
@@ -161,6 +161,96 @@ error:
        return -rte_errno;
 }
 
+/**
+ * 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.
  *
@@ -192,6 +282,13 @@ mlx5_dev_start(struct rte_eth_dev *dev)
                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) {