#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>
}
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);
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);
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",
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);
}
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;
}
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;
}
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. */
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);
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. */