From: Or Ami Date: Thu, 17 Mar 2016 15:38:55 +0000 (+0100) Subject: mlx5: allow operation in secondary processes X-Git-Tag: spdx-start~7204 X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=a48deada651b;p=dpdk.git mlx5: allow operation in secondary processes Secondary processes are expected to use queues and other resources allocated by the primary, however Verbs resources can only be shared between processes when inherited through fork(). This limitation can be worked around for TX by configuring separate queues from secondary processes. Signed-off-by: Or Ami --- diff --git a/doc/guides/nics/mlx5.rst b/doc/guides/nics/mlx5.rst index 24606284d5..5cd09b296d 100644 --- a/doc/guides/nics/mlx5.rst +++ b/doc/guides/nics/mlx5.rst @@ -83,6 +83,7 @@ Features - Multicast promiscuous mode. - Hardware checksum offloads. - Flow director (RTE_FDIR_MODE_PERFECT and RTE_FDIR_MODE_PERFECT_MAC_VLAN). +- Secondary process TX is supported. Limitations ----------- @@ -91,7 +92,7 @@ Limitations - Inner RSS for VXLAN frames is not supported yet. - Port statistics through software counters only. - Hardware checksum offloads for VXLAN inner header are not supported yet. -- Secondary processes are not supported yet. +- Secondary process RX is not supported. Configuration ------------- diff --git a/doc/guides/rel_notes/release_16_04.rst b/doc/guides/rel_notes/release_16_04.rst index 6d671f5edb..b58befaf91 100644 --- a/doc/guides/rel_notes/release_16_04.rst +++ b/doc/guides/rel_notes/release_16_04.rst @@ -213,6 +213,10 @@ This section should contain new features added in this release. Sample format: Implemented callbacks to bring link up and down. +* **Added mlx5 support for operation in secondary processes.** + + Implemented TX support in secondary processes (like mlx4). + * **Changed szedata2 type of driver from vdev to pdev.** Previously szedata2 device had to be added by ``--vdev`` option. diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c index 039cb4339e..b25eaab799 100644 --- a/drivers/net/mlx5/mlx5.c +++ b/drivers/net/mlx5/mlx5.c @@ -78,7 +78,7 @@ static void mlx5_dev_close(struct rte_eth_dev *dev) { - struct priv *priv = dev->data->dev_private; + struct priv *priv = mlx5_get_priv(dev); void *tmp; unsigned int i; @@ -484,18 +484,44 @@ mlx5_pci_devinit(struct rte_pci_driver *pci_drv, struct rte_pci_device *pci_dev) goto port_error; } - eth_dev->data->dev_private = priv; - eth_dev->pci_dev = pci_dev; + /* Secondary processes have to use local storage for their + * private data as well as a copy of eth_dev->data, but this + * pointer must not be modified before burst functions are + * actually called. */ + if (mlx5_is_secondary()) { + struct mlx5_secondary_data *sd = + &mlx5_secondary_data[eth_dev->data->port_id]; + sd->primary_priv = eth_dev->data->dev_private; + if (sd->primary_priv == NULL) { + ERROR("no private data for port %u", + eth_dev->data->port_id); + err = EINVAL; + goto port_error; + } + sd->shared_dev_data = eth_dev->data; + rte_spinlock_init(&sd->lock); + memcpy(sd->data.name, sd->shared_dev_data->name, + sizeof(sd->data.name)); + sd->data.dev_private = priv; + sd->data.rx_mbuf_alloc_failed = 0; + sd->data.mtu = ETHER_MTU; + sd->data.port_id = sd->shared_dev_data->port_id; + sd->data.mac_addrs = priv->mac; + eth_dev->tx_pkt_burst = mlx5_tx_burst_secondary_setup; + eth_dev->rx_pkt_burst = mlx5_rx_burst_secondary_setup; + } else { + eth_dev->data->dev_private = priv; + eth_dev->data->rx_mbuf_alloc_failed = 0; + eth_dev->data->mtu = ETHER_MTU; + eth_dev->data->mac_addrs = priv->mac; + } + eth_dev->pci_dev = pci_dev; rte_eth_copy_pci_info(eth_dev, pci_dev); - eth_dev->driver = &mlx5_driver; - eth_dev->data->rx_mbuf_alloc_failed = 0; - eth_dev->data->mtu = ETHER_MTU; - priv->dev = eth_dev; eth_dev->dev_ops = &mlx5_dev_ops; - eth_dev->data->mac_addrs = priv->mac; + TAILQ_INIT(ð_dev->link_intr_cbs); /* Bring Ethernet device up. */ diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h index 1bd3b403df..99d1443863 100644 --- a/drivers/net/mlx5/mlx5.h +++ b/drivers/net/mlx5/mlx5.h @@ -59,6 +59,7 @@ #include #include #include +#include #ifdef PEDANTIC #pragma GCC diagnostic error "-pedantic" #endif @@ -125,6 +126,14 @@ struct priv { rte_spinlock_t lock; /* Lock for control functions. */ }; +/* Local storage for secondary process data. */ +struct mlx5_secondary_data { + struct rte_eth_dev_data data; /* Local device data. */ + struct priv *primary_priv; /* Private structure from primary. */ + struct rte_eth_dev_data *shared_dev_data; /* Shared device data. */ + rte_spinlock_t lock; /* Port configuration lock. */ +} mlx5_secondary_data[RTE_MAX_ETHPORTS]; + /** * Lock private structure to protect it from concurrent access in the * control path. @@ -152,6 +161,8 @@ priv_unlock(struct priv *priv) /* mlx5_ethdev.c */ +struct priv *mlx5_get_priv(struct rte_eth_dev *dev); +int mlx5_is_secondary(void); int priv_get_ifname(const struct priv *, char (*)[IF_NAMESIZE]); int priv_ifreq(const struct priv *, int req, struct ifreq *); int priv_get_mtu(struct priv *, uint16_t *); @@ -171,6 +182,7 @@ void priv_dev_interrupt_handler_uninstall(struct priv *, struct rte_eth_dev *); void priv_dev_interrupt_handler_install(struct priv *, struct rte_eth_dev *); int mlx5_set_link_down(struct rte_eth_dev *dev); int mlx5_set_link_up(struct rte_eth_dev *dev); +struct priv *mlx5_secondary_data_setup(struct priv *priv); /* mlx5_mac.c */ diff --git a/drivers/net/mlx5/mlx5_ethdev.c b/drivers/net/mlx5/mlx5_ethdev.c index 463b326728..7b959c8e06 100644 --- a/drivers/net/mlx5/mlx5_ethdev.c +++ b/drivers/net/mlx5/mlx5_ethdev.c @@ -59,6 +59,7 @@ #include #include #include +#include #ifdef PEDANTIC #pragma GCC diagnostic error "-pedantic" #endif @@ -67,6 +68,38 @@ #include "mlx5_rxtx.h" #include "mlx5_utils.h" +/** + * Return private structure associated with an Ethernet device. + * + * @param dev + * Pointer to Ethernet device structure. + * + * @return + * Pointer to private structure. + */ +struct priv * +mlx5_get_priv(struct rte_eth_dev *dev) +{ + struct mlx5_secondary_data *sd; + + if (!mlx5_is_secondary()) + return dev->data->dev_private; + sd = &mlx5_secondary_data[dev->data->port_id]; + return sd->data.dev_private; +} + +/** + * Check if running as a secondary process. + * + * @return + * Nonzero if running as a secondary process. + */ +inline int +mlx5_is_secondary(void) +{ + return rte_eal_process_type() != RTE_PROC_PRIMARY; +} + /** * Get interface name from private structure. * @@ -464,6 +497,9 @@ mlx5_dev_configure(struct rte_eth_dev *dev) struct priv *priv = dev->data->dev_private; int ret; + if (mlx5_is_secondary()) + return -E_RTE_SECONDARY; + priv_lock(priv); ret = dev_configure(dev); assert(ret >= 0); @@ -482,7 +518,7 @@ mlx5_dev_configure(struct rte_eth_dev *dev) void mlx5_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info) { - struct priv *priv = dev->data->dev_private; + struct priv *priv = mlx5_get_priv(dev); unsigned int max; char ifname[IF_NAMESIZE]; @@ -555,7 +591,7 @@ mlx5_dev_supported_ptypes_get(struct rte_eth_dev *dev) static int mlx5_link_update_unlocked(struct rte_eth_dev *dev, int wait_to_complete) { - struct priv *priv = dev->data->dev_private; + struct priv *priv = mlx5_get_priv(dev); struct ethtool_cmd edata = { .cmd = ETHTOOL_GSET }; @@ -604,7 +640,7 @@ mlx5_link_update_unlocked(struct rte_eth_dev *dev, int wait_to_complete) int mlx5_link_update(struct rte_eth_dev *dev, int wait_to_complete) { - struct priv *priv = dev->data->dev_private; + struct priv *priv = mlx5_get_priv(dev); int ret; priv_lock(priv); @@ -639,6 +675,9 @@ mlx5_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu) uint16_t (*rx_func)(void *, struct rte_mbuf **, uint16_t) = mlx5_rx_burst; + if (mlx5_is_secondary()) + return -E_RTE_SECONDARY; + priv_lock(priv); /* Set kernel interface MTU first. */ if (priv_set_mtu(priv, mtu)) { @@ -713,6 +752,9 @@ mlx5_dev_get_flow_ctrl(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) }; int ret; + if (mlx5_is_secondary()) + return -E_RTE_SECONDARY; + ifr.ifr_data = ðpause; priv_lock(priv); if (priv_ifreq(priv, SIOCETHTOOL, &ifr)) { @@ -761,6 +803,9 @@ mlx5_dev_set_flow_ctrl(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) }; int ret; + if (mlx5_is_secondary()) + return -E_RTE_SECONDARY; + ifr.ifr_data = ðpause; ethpause.autoneg = fc_conf->autoneg; if (((fc_conf->mode & RTE_FC_FULL) == RTE_FC_FULL) || @@ -1072,3 +1117,154 @@ mlx5_set_link_up(struct rte_eth_dev *dev) priv_unlock(priv); return err; } + +/** + * Configure secondary process queues from a private data pointer (primary + * or secondary) and update burst callbacks. Can take place only once. + * + * All queues must have been previously created by the primary process to + * avoid undefined behavior. + * + * @param priv + * Private data pointer from either primary or secondary process. + * + * @return + * Private data pointer from secondary process, NULL in case of error. + */ +struct priv * +mlx5_secondary_data_setup(struct priv *priv) +{ + unsigned int port_id = 0; + struct mlx5_secondary_data *sd; + void **tx_queues; + void **rx_queues; + unsigned int nb_tx_queues; + unsigned int nb_rx_queues; + unsigned int i; + + /* priv must be valid at this point. */ + assert(priv != NULL); + /* priv->dev must also be valid but may point to local memory from + * another process, possibly with the same address and must not + * be dereferenced yet. */ + assert(priv->dev != NULL); + /* Determine port ID by finding out where priv comes from. */ + while (1) { + sd = &mlx5_secondary_data[port_id]; + rte_spinlock_lock(&sd->lock); + /* Primary process? */ + if (sd->primary_priv == priv) + break; + /* Secondary process? */ + if (sd->data.dev_private == priv) + break; + rte_spinlock_unlock(&sd->lock); + if (++port_id == RTE_DIM(mlx5_secondary_data)) + port_id = 0; + } + /* Switch to secondary private structure. If private data has already + * been updated by another thread, there is nothing else to do. */ + priv = sd->data.dev_private; + if (priv->dev->data == &sd->data) + goto end; + /* Sanity checks. Secondary private structure is supposed to point + * to local eth_dev, itself still pointing to the shared device data + * structure allocated by the primary process. */ + assert(sd->shared_dev_data != &sd->data); + assert(sd->data.nb_tx_queues == 0); + assert(sd->data.tx_queues == NULL); + assert(sd->data.nb_rx_queues == 0); + assert(sd->data.rx_queues == NULL); + assert(priv != sd->primary_priv); + assert(priv->dev->data == sd->shared_dev_data); + assert(priv->txqs_n == 0); + assert(priv->txqs == NULL); + assert(priv->rxqs_n == 0); + assert(priv->rxqs == NULL); + nb_tx_queues = sd->shared_dev_data->nb_tx_queues; + nb_rx_queues = sd->shared_dev_data->nb_rx_queues; + /* Allocate local storage for queues. */ + tx_queues = rte_zmalloc("secondary ethdev->tx_queues", + sizeof(sd->data.tx_queues[0]) * nb_tx_queues, + RTE_CACHE_LINE_SIZE); + rx_queues = rte_zmalloc("secondary ethdev->rx_queues", + sizeof(sd->data.rx_queues[0]) * nb_rx_queues, + RTE_CACHE_LINE_SIZE); + if (tx_queues == NULL || rx_queues == NULL) + goto error; + /* Lock to prevent control operations during setup. */ + priv_lock(priv); + /* TX queues. */ + for (i = 0; i != nb_tx_queues; ++i) { + struct txq *primary_txq = (*sd->primary_priv->txqs)[i]; + struct txq *txq; + + if (primary_txq == NULL) + continue; + txq = rte_calloc_socket("TXQ", 1, sizeof(*txq), 0, + primary_txq->socket); + if (txq != NULL) { + if (txq_setup(priv->dev, + txq, + primary_txq->elts_n * MLX5_PMD_SGE_WR_N, + primary_txq->socket, + NULL) == 0) { + txq->stats.idx = primary_txq->stats.idx; + tx_queues[i] = txq; + continue; + } + rte_free(txq); + } + while (i) { + txq = tx_queues[--i]; + txq_cleanup(txq); + rte_free(txq); + } + goto error; + } + /* RX queues. */ + for (i = 0; i != nb_rx_queues; ++i) { + struct rxq *primary_rxq = (*sd->primary_priv->rxqs)[i]; + + if (primary_rxq == NULL) + continue; + /* Not supported yet. */ + rx_queues[i] = NULL; + } + /* Update everything. */ + priv->txqs = (void *)tx_queues; + priv->txqs_n = nb_tx_queues; + priv->rxqs = (void *)rx_queues; + priv->rxqs_n = nb_rx_queues; + sd->data.rx_queues = rx_queues; + sd->data.tx_queues = tx_queues; + sd->data.nb_rx_queues = nb_rx_queues; + sd->data.nb_tx_queues = nb_tx_queues; + sd->data.dev_link = sd->shared_dev_data->dev_link; + sd->data.mtu = sd->shared_dev_data->mtu; + memcpy(sd->data.rx_queue_state, sd->shared_dev_data->rx_queue_state, + sizeof(sd->data.rx_queue_state)); + memcpy(sd->data.tx_queue_state, sd->shared_dev_data->tx_queue_state, + sizeof(sd->data.tx_queue_state)); + sd->data.dev_flags = sd->shared_dev_data->dev_flags; + /* Use local data from now on. */ + rte_mb(); + priv->dev->data = &sd->data; + rte_mb(); + priv->dev->tx_pkt_burst = mlx5_tx_burst; + priv->dev->rx_pkt_burst = removed_rx_burst; + priv_unlock(priv); +end: + /* More sanity checks. */ + assert(priv->dev->tx_pkt_burst == mlx5_tx_burst); + assert(priv->dev->rx_pkt_burst == removed_rx_burst); + assert(priv->dev->data == &sd->data); + rte_spinlock_unlock(&sd->lock); + return priv; +error: + priv_unlock(priv); + rte_free(tx_queues); + rte_free(rx_queues); + rte_spinlock_unlock(&sd->lock); + return NULL; +} diff --git a/drivers/net/mlx5/mlx5_mac.c b/drivers/net/mlx5/mlx5_mac.c index edb05ad6ed..c9cea48518 100644 --- a/drivers/net/mlx5/mlx5_mac.c +++ b/drivers/net/mlx5/mlx5_mac.c @@ -209,6 +209,9 @@ mlx5_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index) { struct priv *priv = dev->data->dev_private; + if (mlx5_is_secondary()) + return; + priv_lock(priv); DEBUG("%p: removing MAC address from index %" PRIu32, (void *)dev, index); @@ -474,6 +477,9 @@ mlx5_mac_addr_add(struct rte_eth_dev *dev, struct ether_addr *mac_addr, { struct priv *priv = dev->data->dev_private; + if (mlx5_is_secondary()) + return; + (void)vmdq; priv_lock(priv); DEBUG("%p: adding MAC address at index %" PRIu32, diff --git a/drivers/net/mlx5/mlx5_rxmode.c b/drivers/net/mlx5/mlx5_rxmode.c index 2bc005e1df..3a55f633fb 100644 --- a/drivers/net/mlx5/mlx5_rxmode.c +++ b/drivers/net/mlx5/mlx5_rxmode.c @@ -396,6 +396,9 @@ mlx5_promiscuous_enable(struct rte_eth_dev *dev) struct priv *priv = dev->data->dev_private; int ret; + if (mlx5_is_secondary()) + return; + priv_lock(priv); priv->promisc_req = 1; ret = priv_rehash_flows(priv); @@ -417,6 +420,9 @@ mlx5_promiscuous_disable(struct rte_eth_dev *dev) struct priv *priv = dev->data->dev_private; int ret; + if (mlx5_is_secondary()) + return; + priv_lock(priv); priv->promisc_req = 0; ret = priv_rehash_flows(priv); @@ -438,6 +444,9 @@ mlx5_allmulticast_enable(struct rte_eth_dev *dev) struct priv *priv = dev->data->dev_private; int ret; + if (mlx5_is_secondary()) + return; + priv_lock(priv); priv->allmulti_req = 1; ret = priv_rehash_flows(priv); @@ -459,6 +468,9 @@ mlx5_allmulticast_disable(struct rte_eth_dev *dev) struct priv *priv = dev->data->dev_private; int ret; + if (mlx5_is_secondary()) + return; + priv_lock(priv); priv->allmulti_req = 0; ret = priv_rehash_flows(priv); diff --git a/drivers/net/mlx5/mlx5_rxq.c b/drivers/net/mlx5/mlx5_rxq.c index df6fd92c2c..3d84f41588 100644 --- a/drivers/net/mlx5/mlx5_rxq.c +++ b/drivers/net/mlx5/mlx5_rxq.c @@ -1395,6 +1395,9 @@ mlx5_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc, struct rxq *rxq = (*priv->rxqs)[idx]; int ret; + if (mlx5_is_secondary()) + return -E_RTE_SECONDARY; + priv_lock(priv); DEBUG("%p: configuring queue %u for %u descriptors", (void *)dev, idx, desc); @@ -1453,6 +1456,9 @@ mlx5_rx_queue_release(void *dpdk_rxq) struct priv *priv; unsigned int i; + if (mlx5_is_secondary()) + return; + if (rxq == NULL) return; priv = rxq->priv; @@ -1468,3 +1474,43 @@ mlx5_rx_queue_release(void *dpdk_rxq) rte_free(rxq); priv_unlock(priv); } + +/** + * DPDK callback for RX in secondary processes. + * + * This function configures all queues from primary process information + * if necessary before reverting to the normal RX burst callback. + * + * @param dpdk_rxq + * Generic pointer to RX queue structure. + * @param[out] pkts + * Array to store received packets. + * @param pkts_n + * Maximum number of packets in array. + * + * @return + * Number of packets successfully received (<= pkts_n). + */ +uint16_t +mlx5_rx_burst_secondary_setup(void *dpdk_rxq, struct rte_mbuf **pkts, + uint16_t pkts_n) +{ + struct rxq *rxq = dpdk_rxq; + struct priv *priv = mlx5_secondary_data_setup(rxq->priv); + struct priv *primary_priv; + unsigned int index; + + if (priv == NULL) + return 0; + primary_priv = + mlx5_secondary_data[priv->dev->data->port_id].primary_priv; + /* Look for queue index in both private structures. */ + for (index = 0; index != priv->rxqs_n; ++index) + if (((*primary_priv->rxqs)[index] == rxq) || + ((*priv->rxqs)[index] == rxq)) + break; + if (index == priv->rxqs_n) + return 0; + rxq = (*priv->rxqs)[index]; + return priv->dev->rx_pkt_burst(rxq, pkts, pkts_n); +} diff --git a/drivers/net/mlx5/mlx5_rxtx.h b/drivers/net/mlx5/mlx5_rxtx.h index 6ac1a5a48e..6a0087e225 100644 --- a/drivers/net/mlx5/mlx5_rxtx.h +++ b/drivers/net/mlx5/mlx5_rxtx.h @@ -309,13 +309,21 @@ int rxq_setup(struct rte_eth_dev *, struct rxq *, uint16_t, unsigned int, int mlx5_rx_queue_setup(struct rte_eth_dev *, uint16_t, uint16_t, unsigned int, const struct rte_eth_rxconf *, struct rte_mempool *); void mlx5_rx_queue_release(void *); +uint16_t mlx5_rx_burst_secondary_setup(void *dpdk_rxq, struct rte_mbuf **pkts, + uint16_t pkts_n); + /* mlx5_txq.c */ void txq_cleanup(struct txq *); +int txq_setup(struct rte_eth_dev *dev, struct txq *txq, uint16_t desc, + unsigned int socket, const struct rte_eth_txconf *conf); + int mlx5_tx_queue_setup(struct rte_eth_dev *, uint16_t, uint16_t, unsigned int, const struct rte_eth_txconf *); void mlx5_tx_queue_release(void *); +uint16_t mlx5_tx_burst_secondary_setup(void *dpdk_txq, struct rte_mbuf **pkts, + uint16_t pkts_n); /* mlx5_rxtx.c */ diff --git a/drivers/net/mlx5/mlx5_stats.c b/drivers/net/mlx5/mlx5_stats.c index 6d1a600e32..2d3cb51906 100644 --- a/drivers/net/mlx5/mlx5_stats.c +++ b/drivers/net/mlx5/mlx5_stats.c @@ -55,7 +55,7 @@ void mlx5_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats) { - struct priv *priv = dev->data->dev_private; + struct priv *priv = mlx5_get_priv(dev); struct rte_eth_stats tmp = {0}; unsigned int i; unsigned int idx; diff --git a/drivers/net/mlx5/mlx5_trigger.c b/drivers/net/mlx5/mlx5_trigger.c index b5ca7d4668..e9b9a293f5 100644 --- a/drivers/net/mlx5/mlx5_trigger.c +++ b/drivers/net/mlx5/mlx5_trigger.c @@ -64,6 +64,9 @@ mlx5_dev_start(struct rte_eth_dev *dev) struct priv *priv = dev->data->dev_private; int err; + if (mlx5_is_secondary()) + return -E_RTE_SECONDARY; + priv_lock(priv); if (priv->started) { priv_unlock(priv); @@ -104,6 +107,9 @@ mlx5_dev_stop(struct rte_eth_dev *dev) { struct priv *priv = dev->data->dev_private; + if (mlx5_is_secondary()) + return; + priv_lock(priv); if (!priv->started) { priv_unlock(priv); diff --git a/drivers/net/mlx5/mlx5_txq.c b/drivers/net/mlx5/mlx5_txq.c index 3364fcab08..6700af41a5 100644 --- a/drivers/net/mlx5/mlx5_txq.c +++ b/drivers/net/mlx5/mlx5_txq.c @@ -255,11 +255,11 @@ txq_cleanup(struct txq *txq) * @return * 0 on success, errno value on failure. */ -static int +int txq_setup(struct rte_eth_dev *dev, struct txq *txq, uint16_t desc, unsigned int socket, const struct rte_eth_txconf *conf) { - struct priv *priv = dev->data->dev_private; + struct priv *priv = mlx5_get_priv(dev); struct txq tmpl = { .priv = priv, .socket = socket @@ -464,6 +464,9 @@ mlx5_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc, struct txq *txq = (*priv->txqs)[idx]; int ret; + if (mlx5_is_secondary()) + return -E_RTE_SECONDARY; + priv_lock(priv); DEBUG("%p: configuring queue %u for %u descriptors", (void *)dev, idx, desc); @@ -519,6 +522,9 @@ mlx5_tx_queue_release(void *dpdk_txq) struct priv *priv; unsigned int i; + if (mlx5_is_secondary()) + return; + if (txq == NULL) return; priv = txq->priv; @@ -534,3 +540,43 @@ mlx5_tx_queue_release(void *dpdk_txq) rte_free(txq); priv_unlock(priv); } + +/** + * DPDK callback for TX in secondary processes. + * + * This function configures all queues from primary process information + * if necessary before reverting to the normal TX burst callback. + * + * @param dpdk_txq + * Generic pointer to TX queue structure. + * @param[in] pkts + * Packets to transmit. + * @param pkts_n + * Number of packets in array. + * + * @return + * Number of packets successfully transmitted (<= pkts_n). + */ +uint16_t +mlx5_tx_burst_secondary_setup(void *dpdk_txq, struct rte_mbuf **pkts, + uint16_t pkts_n) +{ + struct txq *txq = dpdk_txq; + struct priv *priv = mlx5_secondary_data_setup(txq->priv); + struct priv *primary_priv; + unsigned int index; + + if (priv == NULL) + return 0; + primary_priv = + mlx5_secondary_data[priv->dev->data->port_id].primary_priv; + /* Look for queue index in both private structures. */ + for (index = 0; index != priv->txqs_n; ++index) + if (((*primary_priv->txqs)[index] == txq) || + ((*priv->txqs)[index] == txq)) + break; + if (index == priv->txqs_n) + return 0; + txq = (*priv->txqs)[index]; + return priv->dev->tx_pkt_burst(txq, pkts, pkts_n); +}