net/mvpp2: check meter packet mode
[dpdk.git] / drivers / net / mlx5 / mlx5_trigger.c
index 28ce8dd..94dd567 100644 (file)
@@ -6,9 +6,10 @@
 #include <unistd.h>
 
 #include <rte_ether.h>
-#include <rte_ethdev_driver.h>
+#include <ethdev_driver.h>
 #include <rte_interrupts.h>
 #include <rte_alarm.h>
+#include <rte_cycles.h>
 
 #include <mlx5_malloc.h>
 
@@ -77,6 +78,7 @@ mlx5_txq_start(struct rte_eth_dev *dev)
                }
                if (txq_ctrl->type == MLX5_TXQ_TYPE_STANDARD) {
                        size_t size = txq_data->cqe_s * sizeof(*txq_data->fcqs);
+
                        txq_data->fcqs = mlx5_malloc(flags, size,
                                                     RTE_CACHE_LINE_SIZE,
                                                     txq_ctrl->socket);
@@ -218,6 +220,8 @@ mlx5_hairpin_auto_bind(struct rte_eth_dev *dev)
        struct mlx5_devx_obj *rq;
        unsigned int i;
        int ret = 0;
+       bool need_auto = false;
+       uint16_t self_port = dev->data->port_id;
 
        for (i = 0; i != priv->txqs_n; ++i) {
                txq_ctrl = mlx5_txq_get(dev, i);
@@ -227,6 +231,28 @@ mlx5_hairpin_auto_bind(struct rte_eth_dev *dev)
                        mlx5_txq_release(dev, i);
                        continue;
                }
+               if (txq_ctrl->hairpin_conf.peers[0].port != self_port)
+                       continue;
+               if (txq_ctrl->hairpin_conf.manual_bind) {
+                       mlx5_txq_release(dev, i);
+                       return 0;
+               }
+               need_auto = true;
+               mlx5_txq_release(dev, i);
+       }
+       if (!need_auto)
+               return 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;
+               }
+               /* Skip hairpin queues with other peer ports. */
+               if (txq_ctrl->hairpin_conf.peers[0].port != self_port)
+                       continue;
                if (!txq_ctrl->obj) {
                        rte_errno = ENOMEM;
                        DRV_LOG(ERR, "port %u no txq object found: %d",
@@ -275,6 +301,9 @@ mlx5_hairpin_auto_bind(struct rte_eth_dev *dev)
                ret = mlx5_devx_cmd_modify_rq(rq, &rq_attr);
                if (ret)
                        goto error;
+               /* Qs with auto-bind will be destroyed directly. */
+               rxq_ctrl->hairpin_status = 1;
+               txq_ctrl->hairpin_status = 1;
                mlx5_txq_release(dev, i);
                mlx5_rxq_release(dev, txq_ctrl->hairpin_conf.peers[0].queue);
        }
@@ -906,7 +935,96 @@ mlx5_hairpin_unbind(struct rte_eth_dev *dev, uint16_t rx_port)
                                return ret;
                }
        else
-               ret = mlx5_hairpin_bind_single_port(dev, rx_port);
+               ret = mlx5_hairpin_unbind_single_port(dev, rx_port);
+       return ret;
+}
+
+/*
+ * DPDK callback to get the hairpin peer ports list.
+ * This will return the actual number of peer ports and save the identifiers
+ * into the array (sorted, may be different from that when setting up the
+ * hairpin peer queues).
+ * The peer port ID could be the same as the port ID of the current device.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param peer_ports
+ *   Pointer to array to save the port identifiers.
+ * @param len
+ *   The length of the array.
+ * @param direction
+ *   Current port to peer port direction.
+ *   positive - current used as Tx to get all peer Rx ports.
+ *   zero - current used as Rx to get all peer Tx ports.
+ *
+ * @return
+ *   0 or positive value on success, actual number of peer ports.
+ *   a negative errno value otherwise and rte_errno is set.
+ */
+int
+mlx5_hairpin_get_peer_ports(struct rte_eth_dev *dev, uint16_t *peer_ports,
+                           size_t len, uint32_t direction)
+{
+       struct mlx5_priv *priv = dev->data->dev_private;
+       struct mlx5_txq_ctrl *txq_ctrl;
+       struct mlx5_rxq_ctrl *rxq_ctrl;
+       uint32_t i;
+       uint16_t pp;
+       uint32_t bits[(RTE_MAX_ETHPORTS + 31) / 32] = {0};
+       int ret = 0;
+
+       if (direction) {
+               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;
+                       }
+                       pp = txq_ctrl->hairpin_conf.peers[0].port;
+                       if (pp >= RTE_MAX_ETHPORTS) {
+                               rte_errno = ERANGE;
+                               mlx5_txq_release(dev, i);
+                               DRV_LOG(ERR, "port %hu queue %u peer port "
+                                       "out of range %hu",
+                                       priv->dev_data->port_id, i, pp);
+                               return -rte_errno;
+                       }
+                       bits[pp / 32] |= 1 << (pp % 32);
+                       mlx5_txq_release(dev, i);
+               }
+       } else {
+               for (i = 0; i < priv->rxqs_n; i++) {
+                       rxq_ctrl = mlx5_rxq_get(dev, i);
+                       if (!rxq_ctrl)
+                               continue;
+                       if (rxq_ctrl->type != MLX5_RXQ_TYPE_HAIRPIN) {
+                               mlx5_rxq_release(dev, i);
+                               continue;
+                       }
+                       pp = rxq_ctrl->hairpin_conf.peers[0].port;
+                       if (pp >= RTE_MAX_ETHPORTS) {
+                               rte_errno = ERANGE;
+                               mlx5_rxq_release(dev, i);
+                               DRV_LOG(ERR, "port %hu queue %u peer port "
+                                       "out of range %hu",
+                                       priv->dev_data->port_id, i, pp);
+                               return -rte_errno;
+                       }
+                       bits[pp / 32] |= 1 << (pp % 32);
+                       mlx5_rxq_release(dev, i);
+               }
+       }
+       for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
+               if (bits[i / 32] & (1 << (i % 32))) {
+                       if ((size_t)ret >= len) {
+                               rte_errno = E2BIG;
+                               return -rte_errno;
+                       }
+                       peer_ports[ret++] = i;
+               }
+       }
        return ret;
 }
 
@@ -961,9 +1079,13 @@ mlx5_dev_start(struct rte_eth_dev *dev)
                        dev->data->port_id, strerror(rte_errno));
                goto error;
        }
+       /*
+        * Such step will be skipped if there is no hairpin TX queue configured
+        * with RX peer queue from the same device.
+        */
        ret = mlx5_hairpin_auto_bind(dev);
        if (ret) {
-               DRV_LOG(ERR, "port %u hairpin binding failed: %s",
+               DRV_LOG(ERR, "port %u hairpin auto binding failed: %s",
                        dev->data->port_id, strerror(rte_errno));
                goto error;
        }
@@ -1050,7 +1172,7 @@ mlx5_dev_stop(struct rte_eth_dev *dev)
        rte_wmb();
        /* Disable datapath on secondary process. */
        mlx5_mp_os_req_stop_rxtx(dev);
-       usleep(1000 * priv->rxqs_n);
+       rte_delay_us_sleep(1000 * priv->rxqs_n);
        DRV_LOG(DEBUG, "port %u stopping device", dev->data->port_id);
        mlx5_flow_stop_default(dev);
        /* Control flows for default traffic can be removed firstly. */
@@ -1114,7 +1236,11 @@ mlx5_traffic_enable(struct rte_eth_dev *dev)
                struct mlx5_txq_ctrl *txq_ctrl = mlx5_txq_get(dev, i);
                if (!txq_ctrl)
                        continue;
-               if (txq_ctrl->type == MLX5_TXQ_TYPE_HAIRPIN) {
+               /* Only Tx implicit mode requires the default Tx flow. */
+               if (txq_ctrl->type == MLX5_TXQ_TYPE_HAIRPIN &&
+                   txq_ctrl->hairpin_conf.tx_explicit == 0 &&
+                   txq_ctrl->hairpin_conf.peers[0].port ==
+                   priv->dev_data->port_id) {
                        ret = mlx5_ctrl_flow_source_queue(dev, i);
                        if (ret) {
                                mlx5_txq_release(dev, i);
@@ -1190,8 +1316,12 @@ mlx5_traffic_enable(struct rte_eth_dev *dev)
                                goto error;
                        ret = mlx5_ctrl_flow(dev, &ipv6_multi_spec,
                                             &ipv6_multi_mask);
-                       if (ret)
-                               goto error;
+                       if (ret) {
+                               /* Do not fail on IPv6 broadcast creation failure. */
+                               DRV_LOG(WARNING,
+                                       "IPv6 broadcast is not supported");
+                               ret = 0;
+                       }
                }
        }
        /* Add MAC address flows. */