src/dpdk/drivers/net/mlx5/mlx5_trigger.c
static int
mlx5_hairpin_bind_single_port(struct rte_eth_dev *dev, uint16_t rx_port)
{
	struct mlx5_priv *priv = dev->data->dev_private;
	int ret = 0;
	struct mlx5_txq_ctrl *txq_ctrl;
	uint32_t i;
	struct rte_hairpin_peer_info peer = {0xffffff};
	struct rte_hairpin_peer_info cur;
	const struct rte_eth_hairpin_conf *conf;
	uint16_t num_q = 0;
	uint16_t local_port = priv->dev_data->port_id;
	uint32_t manual;
	uint32_t explicit;
	uint16_t rx_queue;

	if (mlx5_eth_find_next(rx_port, priv->pci_dev) != rx_port) {
		rte_errno = ENODEV;
		DRV_LOG(ERR, "Rx port %u does not belong to mlx5", rx_port);
		return -rte_errno;
	}
	/*
	 * Before binding TxQ to peer RxQ, first round loop will be used for
	 * checking the queues' configuration consistency. This would be a
	 * little time consuming but better than doing the rollback.
	 */
	for (i = 0; i != priv->txqs_n; i++) {
		txq_ctrl = mlx5_txq_get(dev, i);
		if (txq_ctrl == NULL)
			continue;
		if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) {
			mlx5_txq_release(dev, i);
			continue;
		}
		/*
		 * All hairpin Tx queues of a single port that connected to the
		 * same peer Rx port should have the same "auto binding" and
		 * "implicit Tx flow" modes.
		 * Peer consistency checking will be done in per queue binding.
		 */
		conf = &txq_ctrl->hairpin_conf;
		if (conf->peers[0].port == rx_port) {
			if (num_q == 0) {
				manual = conf->manual_bind;
				explicit = conf->tx_explicit;
			} else {
				if (manual != conf->manual_bind ||
				    explicit != conf->tx_explicit) {
					rte_errno = EINVAL;
					DRV_LOG(ERR, "port %u queue %d mode"
						" mismatch: %u %u, %u %u",
						local_port, i, manual,
						conf->manual_bind, explicit,
						conf->tx_explicit);
					mlx5_txq_release(dev, i);
					return -rte_errno;
				}
			}
			num_q++;
		}
		mlx5_txq_release(dev, i);
	}
	/* Once no queue is configured, success is returned directly. */
	if (num_q == 0)
		return ret;
	/* All the hairpin TX queues need to be traversed again. */
	for (i = 0; i != priv->txqs_n; i++) {
		txq_ctrl = mlx5_txq_get(dev, i);
		if (txq_ctrl == NULL)
			continue;
		if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) {
			mlx5_txq_release(dev, i);
			continue;
		}
		if (txq_ctrl->hairpin_conf.peers[0].port != rx_port) {
			mlx5_txq_release(dev, i);
			continue;
		}
		rx_queue = txq_ctrl->hairpin_conf.peers[0].queue;
		/*
		 * Fetch peer RxQ's information.
		 * No need to pass the information of the current queue.
		 */
		ret = rte_eth_hairpin_queue_peer_update(rx_port, rx_queue,
							NULL, &peer, 1);
		if (ret != 0) {
			mlx5_txq_release(dev, i);
			goto error;
		}
		/* Accessing its own device, inside mlx5 PMD. */
		ret = mlx5_hairpin_queue_peer_bind(dev, i, &peer, 1);
		if (ret != 0) {
			mlx5_txq_release(dev, i);
			goto error;
		}
		/* Pass TxQ's information to peer RxQ and try binding. */
		cur.peer_q = rx_queue;
		cur.qp_id = txq_ctrl->obj->sq->id;
		cur.vhca_id = priv->config.hca_attr.vhca_id;
		cur.tx_explicit = txq_ctrl->hairpin_conf.tx_explicit;
		cur.manual_bind = txq_ctrl->hairpin_conf.manual_bind;
		/*
		 * In order to access another device in a proper way, RTE level
		 * private function is needed.
		 */
		ret = rte_eth_hairpin_queue_peer_bind(rx_port, rx_queue,
						      &cur, 0);
		if (ret != 0) {
			mlx5_txq_release(dev, i);
			goto error;
		}
		mlx5_txq_release(dev, i);
	}
	return 0;
error:
	/*
	 * Do roll-back process for the queues already bound.
	 * No need to check the return value of the queue unbind function.
	 */
	do {
		/* No validation is needed here. */
		txq_ctrl = mlx5_txq_get(dev, i);
		if (txq_ctrl == NULL)
			continue;
		rx_queue = txq_ctrl->hairpin_conf.peers[0].queue;
		rte_eth_hairpin_queue_peer_unbind(rx_port, rx_queue, 0);
		mlx5_hairpin_queue_peer_unbind(dev, i, 1);
		mlx5_txq_release(dev, i);
	} while (i--);
	return ret;
}
/*
 * Bind the hairpin port pairs, from the Tx to the peer Rx.
 * This function only supports to bind the Tx to one Rx.
 *
 * @param dev
 *   Pointer to Ethernet device structure.
 * @param rx_port
 *   Port identifier of the Rx port.
 *
 * @return
 *   0 on success, a negative errno value otherwise and rte_errno is set.
 */
Bind the hairpin port pairs, from the Tx to the peer Rx.
This function only supports to bind the Tx to one Rx.

@param dev
Pointer to Ethernet device structure.
@param rx_port
Port identifier of the Rx port.

@return
0 on success, a negative errno value otherwise and rte_errno is set.
Bind the hairpin port pairs from the Tx to the peer Rx . This function only supports to bind the Tx to one Rx . @param dev Pointer to Ethernet device structure . @param rx_port Port identifier of the Rx port . @return 0 on success a negative errno value otherwise and rte_errno is set .
static int
mlx5_hairpin_bind_single_port(struct rte_eth_dev *dev, uint16_t rx_port)
{
	struct mlx5_priv *priv = dev->data->dev_private;
	int ret = 0;
	struct mlx5_txq_ctrl *txq_ctrl;
	uint32_t i;
	struct rte_hairpin_peer_info peer = {0xffffff};
	struct rte_hairpin_peer_info cur;
	const struct rte_eth_hairpin_conf *conf;
	uint16_t num_q = 0;
	uint16_t local_port = priv->dev_data->port_id;
	uint32_t manual;
	uint32_t explicit;
	uint16_t rx_queue;
	if (mlx5_eth_find_next(rx_port, priv->pci_dev) != rx_port) {
		rte_errno = ENODEV;
		DRV_LOG(ERR, "Rx port %u does not belong to mlx5", rx_port);
		return -rte_errno;
	}
	for (i = 0; i != priv->txqs_n; i++) {
		txq_ctrl = mlx5_txq_get(dev, i);
		if (txq_ctrl == NULL)
			continue;
		if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) {
			mlx5_txq_release(dev, i);
			continue;
		}
		conf = &txq_ctrl->hairpin_conf;
		if (conf->peers[0].port == rx_port) {
			if (num_q == 0) {
				manual = conf->manual_bind;
				explicit = conf->tx_explicit;
			} else {
				if (manual != conf->manual_bind ||
				    explicit != conf->tx_explicit) {
					rte_errno = EINVAL;
					DRV_LOG(ERR, "port %u queue %d mode"
						" mismatch: %u %u, %u %u",
						local_port, i, manual,
						conf->manual_bind, explicit,
						conf->tx_explicit);
					mlx5_txq_release(dev, i);
					return -rte_errno;
				}
			}
			num_q++;
		}
		mlx5_txq_release(dev, i);
	}
	if (num_q == 0)
		return ret;
	for (i = 0; i != priv->txqs_n; i++) {
		txq_ctrl = mlx5_txq_get(dev, i);
		if (txq_ctrl == NULL)
			continue;
		if (txq_ctrl->type != MLX5_TXQ_TYPE_HAIRPIN) {
			mlx5_txq_release(dev, i);
			continue;
		}
		if (txq_ctrl->hairpin_conf.peers[0].port != rx_port) {
			mlx5_txq_release(dev, i);
			continue;
		}
		rx_queue = txq_ctrl->hairpin_conf.peers[0].queue;
		ret = rte_eth_hairpin_queue_peer_update(rx_port, rx_queue,
							NULL, &peer, 1);
		if (ret != 0) {
			mlx5_txq_release(dev, i);
			goto error;
		}
		ret = mlx5_hairpin_queue_peer_bind(dev, i, &peer, 1);
		if (ret != 0) {
			mlx5_txq_release(dev, i);
			goto error;
		}
		cur.peer_q = rx_queue;
		cur.qp_id = txq_ctrl->obj->sq->id;
		cur.vhca_id = priv->config.hca_attr.vhca_id;
		cur.tx_explicit = txq_ctrl->hairpin_conf.tx_explicit;
		cur.manual_bind = txq_ctrl->hairpin_conf.manual_bind;
		ret = rte_eth_hairpin_queue_peer_bind(rx_port, rx_queue,
						      &cur, 0);
		if (ret != 0) {
			mlx5_txq_release(dev, i);
			goto error;
		}
		mlx5_txq_release(dev, i);
	}
	return 0;
error:
	do {
		txq_ctrl = mlx5_txq_get(dev, i);
		if (txq_ctrl == NULL)
			continue;
		rx_queue = txq_ctrl->hairpin_conf.peers[0].queue;
		rte_eth_hairpin_queue_peer_unbind(rx_port, rx_queue, 0);
		mlx5_hairpin_queue_peer_unbind(dev, i, 1);
		mlx5_txq_release(dev, i);
	} while (i--);
	return ret;
}
static int mlx5_hairpin_bind_single_port ( struct rte_eth_dev * dev , uint16_t rx_port ) { struct mlx5_priv * priv = dev -> data -> dev_private ; int ret = 0 ; struct mlx5_txq_ctrl * txq_ctrl ; uint32_t i ; struct rte_hairpin_peer_info peer = { 0xffffff } ; struct rte_hairpin_peer_info cur ; const struct rte_eth_hairpin_conf * conf ; uint16_t num_q = 0 ; uint16_t local_port = priv -> dev_data -> port_id ; uint32_t manual ; uint32_t explicit ; uint16_t rx_queue ; if ( mlx5_eth_find_next ( rx_port , priv -> pci_dev ) != rx_port ) { rte_errno = ENODEV ; DRV_LOG ( ERR , " " , rx_port ) ; return - rte_errno ; } for ( i = 0 ; i != priv -> txqs_n ; i ++ ) { txq_ctrl = mlx5_txq_get ( dev , i ) ; if ( txq_ctrl == NULL ) continue ; if ( txq_ctrl -> type != MLX5_TXQ_TYPE_HAIRPIN ) { mlx5_txq_release ( dev , i ) ; continue ; } conf = & txq_ctrl -> hairpin_conf ; if ( conf -> peers [ 0 ] . port == rx_port ) { if ( num_q == 0 ) { manual = conf -> manual_bind ; explicit = conf -> tx_explicit ; } else { if ( manual != conf -> manual_bind || explicit != conf -> tx_explicit ) { rte_errno = EINVAL ; DRV_LOG ( ERR , " " " " , local_port , i , manual , conf -> manual_bind , explicit , conf -> tx_explicit ) ; mlx5_txq_release ( dev , i ) ; return - rte_errno ; } } num_q ++ ; } mlx5_txq_release ( dev , i ) ; } if ( num_q == 0 ) return ret ; for ( i = 0 ; i != priv -> txqs_n ; i ++ ) { txq_ctrl = mlx5_txq_get ( dev , i ) ; if ( txq_ctrl == NULL ) continue ; if ( txq_ctrl -> type != MLX5_TXQ_TYPE_HAIRPIN ) { mlx5_txq_release ( dev , i ) ; continue ; } if ( txq_ctrl -> hairpin_conf . peers [ 0 ] . port != rx_port ) { mlx5_txq_release ( dev , i ) ; continue ; } rx_queue = txq_ctrl -> hairpin_conf . peers [ 0 ] . queue ; ret = rte_eth_hairpin_queue_peer_update ( rx_port , rx_queue , NULL , & peer , 1 ) ; if ( ret != 0 ) { mlx5_txq_release ( dev , i ) ; goto error ; } ret = mlx5_hairpin_queue_peer_bind ( dev , i , & peer , 1 ) ; if ( ret != 0 ) { mlx5_txq_release ( dev , i ) ; goto error ; } cur . peer_q = rx_queue ; cur . qp_id = txq_ctrl -> obj -> sq -> id ; cur . vhca_id = priv -> config . hca_attr . vhca_id ; cur . tx_explicit = txq_ctrl -> hairpin_conf . tx_explicit ; cur . manual_bind = txq_ctrl -> hairpin_conf . manual_bind ; ret = rte_eth_hairpin_queue_peer_bind ( rx_port , rx_queue , & cur , 0 ) ; if ( ret != 0 ) { mlx5_txq_release ( dev , i ) ; goto error ; } mlx5_txq_release ( dev , i ) ; } return 0 ; error : do { txq_ctrl = mlx5_txq_get ( dev , i ) ; if ( txq_ctrl == NULL ) continue ; rx_queue = txq_ctrl -> hairpin_conf . peers [ 0 ] . queue ; rte_eth_hairpin_queue_peer_unbind ( rx_port , rx_queue , 0 ) ; mlx5_hairpin_queue_peer_unbind ( dev , i , 1 ) ; mlx5_txq_release ( dev , i ) ; } while ( i -- ) ; return ret ; }
Bind the hairpin port pairs, from the Tx to the peer Rx.
Bind the hairpin port pairs from the Tx to the peer Rx .
/*
	 * Before binding TxQ to peer RxQ, first round loop will be used for
	 * checking the queues' configuration consistency. This would be a
	 * little time consuming but better than doing the rollback.
	 */ /*
		 * All hairpin Tx queues of a single port that connected to the
		 * same peer Rx port should have the same "auto binding" and
		 * "implicit Tx flow" modes.
		 * Peer consistency checking will be done in per queue binding.
		 */ /* Once no queue is configured, success is returned directly. */ /* All the hairpin TX queues need to be traversed again. */ /*
		 * Fetch peer RxQ's information.
		 * No need to pass the information of the current queue.
		 */ /* Accessing its own device, inside mlx5 PMD. */ /* Pass TxQ's information to peer RxQ and try binding. */ /*
		 * In order to access another device in a proper way, RTE level
		 * private function is needed.
		 */ /*
	 * Do roll-back process for the queues already bound.
	 * No need to check the return value of the queue unbind function.
	 */ /* No validation is needed here. */