numam-dpdk/drivers/net/mlx5/mlx5_tx.c
Michael Baum 79a876e3c4 net/mlx5: separate Tx function implementations to new file
This patch separates Tx function implementations to different source
file as an optional preparation step for Tx cleanup.

Signed-off-by: Michael Baum <michaelba@nvidia.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@nvidia.com>
2021-04-15 08:24:58 +02:00

781 lines
22 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright 2021 6WIND S.A.
* Copyright 2021 Mellanox Technologies, Ltd
*/
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <rte_mbuf.h>
#include <rte_mempool.h>
#include <rte_prefetch.h>
#include <rte_common.h>
#include <rte_branch_prediction.h>
#include <rte_ether.h>
#include <rte_cycles.h>
#include <rte_flow.h>
#include <mlx5_prm.h>
#include <mlx5_common.h>
#include "mlx5_autoconf.h"
#include "mlx5_defs.h"
#include "mlx5.h"
#include "mlx5_mr.h"
#include "mlx5_utils.h"
#include "mlx5_rxtx.h"
#include "mlx5_tx.h"
#define MLX5_TXOFF_INFO(func, olx) {mlx5_tx_burst_##func, olx},
/**
* Move QP from error state to running state and initialize indexes.
*
* @param txq_ctrl
* Pointer to TX queue control structure.
*
* @return
* 0 on success, else -1.
*/
static int
tx_recover_qp(struct mlx5_txq_ctrl *txq_ctrl)
{
struct mlx5_mp_arg_queue_state_modify sm = {
.is_wq = 0,
.queue_id = txq_ctrl->txq.idx,
};
if (mlx5_queue_state_modify(ETH_DEV(txq_ctrl->priv), &sm))
return -1;
txq_ctrl->txq.wqe_ci = 0;
txq_ctrl->txq.wqe_pi = 0;
txq_ctrl->txq.elts_comp = 0;
return 0;
}
/* Return 1 if the error CQE is signed otherwise, sign it and return 0. */
static int
check_err_cqe_seen(volatile struct mlx5_err_cqe *err_cqe)
{
static const uint8_t magic[] = "seen";
int ret = 1;
unsigned int i;
for (i = 0; i < sizeof(magic); ++i)
if (!ret || err_cqe->rsvd1[i] != magic[i]) {
ret = 0;
err_cqe->rsvd1[i] = magic[i];
}
return ret;
}
/**
* Handle error CQE.
*
* @param txq
* Pointer to TX queue structure.
* @param error_cqe
* Pointer to the error CQE.
*
* @return
* Negative value if queue recovery failed, otherwise
* the error completion entry is handled successfully.
*/
static int
mlx5_tx_error_cqe_handle(struct mlx5_txq_data *__rte_restrict txq,
volatile struct mlx5_err_cqe *err_cqe)
{
if (err_cqe->syndrome != MLX5_CQE_SYNDROME_WR_FLUSH_ERR) {
const uint16_t wqe_m = ((1 << txq->wqe_n) - 1);
struct mlx5_txq_ctrl *txq_ctrl =
container_of(txq, struct mlx5_txq_ctrl, txq);
uint16_t new_wqe_pi = rte_be_to_cpu_16(err_cqe->wqe_counter);
int seen = check_err_cqe_seen(err_cqe);
if (!seen && txq_ctrl->dump_file_n <
txq_ctrl->priv->config.max_dump_files_num) {
MKSTR(err_str, "Unexpected CQE error syndrome "
"0x%02x CQN = %u SQN = %u wqe_counter = %u "
"wq_ci = %u cq_ci = %u", err_cqe->syndrome,
txq->cqe_s, txq->qp_num_8s >> 8,
rte_be_to_cpu_16(err_cqe->wqe_counter),
txq->wqe_ci, txq->cq_ci);
MKSTR(name, "dpdk_mlx5_port_%u_txq_%u_index_%u_%u",
PORT_ID(txq_ctrl->priv), txq->idx,
txq_ctrl->dump_file_n, (uint32_t)rte_rdtsc());
mlx5_dump_debug_information(name, NULL, err_str, 0);
mlx5_dump_debug_information(name, "MLX5 Error CQ:",
(const void *)((uintptr_t)
txq->cqes),
sizeof(*err_cqe) *
(1 << txq->cqe_n));
mlx5_dump_debug_information(name, "MLX5 Error SQ:",
(const void *)((uintptr_t)
txq->wqes),
MLX5_WQE_SIZE *
(1 << txq->wqe_n));
txq_ctrl->dump_file_n++;
}
if (!seen)
/*
* Count errors in WQEs units.
* Later it can be improved to count error packets,
* for example, by SQ parsing to find how much packets
* should be counted for each WQE.
*/
txq->stats.oerrors += ((txq->wqe_ci & wqe_m) -
new_wqe_pi) & wqe_m;
if (tx_recover_qp(txq_ctrl)) {
/* Recovering failed - retry later on the same WQE. */
return -1;
}
/* Release all the remaining buffers. */
txq_free_elts(txq_ctrl);
}
return 0;
}
/**
* Dummy DPDK callback for TX.
*
* This function is used to temporarily replace the real callback during
* unsafe control operations on the queue, or in case of error.
*
* @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
removed_tx_burst(void *dpdk_txq __rte_unused,
struct rte_mbuf **pkts __rte_unused,
uint16_t pkts_n __rte_unused)
{
rte_mb();
return 0;
}
/**
* Update completion queue consuming index via doorbell
* and flush the completed data buffers.
*
* @param txq
* Pointer to TX queue structure.
* @param last_cqe
* valid CQE pointer, if not NULL update txq->wqe_pi and flush the buffers.
* @param olx
* Configured Tx offloads mask. It is fully defined at
* compile time and may be used for optimization.
*/
static __rte_always_inline void
mlx5_tx_comp_flush(struct mlx5_txq_data *__rte_restrict txq,
volatile struct mlx5_cqe *last_cqe,
unsigned int olx __rte_unused)
{
if (likely(last_cqe != NULL)) {
uint16_t tail;
txq->wqe_pi = rte_be_to_cpu_16(last_cqe->wqe_counter);
tail = txq->fcqs[(txq->cq_ci - 1) & txq->cqe_m];
if (likely(tail != txq->elts_tail)) {
mlx5_tx_free_elts(txq, tail, olx);
MLX5_ASSERT(tail == txq->elts_tail);
}
}
}
/**
* Manage TX completions. This routine checks the CQ for
* arrived CQEs, deduces the last accomplished WQE in SQ,
* updates SQ producing index and frees all completed mbufs.
*
* @param txq
* Pointer to TX queue structure.
* @param olx
* Configured Tx offloads mask. It is fully defined at
* compile time and may be used for optimization.
*
* NOTE: not inlined intentionally, it makes tx_burst
* routine smaller, simple and faster - from experiments.
*/
void
mlx5_tx_handle_completion(struct mlx5_txq_data *__rte_restrict txq,
unsigned int olx __rte_unused)
{
unsigned int count = MLX5_TX_COMP_MAX_CQE;
volatile struct mlx5_cqe *last_cqe = NULL;
bool ring_doorbell = false;
int ret;
do {
volatile struct mlx5_cqe *cqe;
cqe = &txq->cqes[txq->cq_ci & txq->cqe_m];
ret = check_cqe(cqe, txq->cqe_s, txq->cq_ci);
if (unlikely(ret != MLX5_CQE_STATUS_SW_OWN)) {
if (likely(ret != MLX5_CQE_STATUS_ERR)) {
/* No new CQEs in completion queue. */
MLX5_ASSERT(ret == MLX5_CQE_STATUS_HW_OWN);
break;
}
/*
* Some error occurred, try to restart.
* We have no barrier after WQE related Doorbell
* written, make sure all writes are completed
* here, before we might perform SQ reset.
*/
rte_wmb();
ret = mlx5_tx_error_cqe_handle
(txq, (volatile struct mlx5_err_cqe *)cqe);
if (unlikely(ret < 0)) {
/*
* Some error occurred on queue error
* handling, we do not advance the index
* here, allowing to retry on next call.
*/
return;
}
/*
* We are going to fetch all entries with
* MLX5_CQE_SYNDROME_WR_FLUSH_ERR status.
* The send queue is supposed to be empty.
*/
ring_doorbell = true;
++txq->cq_ci;
txq->cq_pi = txq->cq_ci;
last_cqe = NULL;
continue;
}
/* Normal transmit completion. */
MLX5_ASSERT(txq->cq_ci != txq->cq_pi);
#ifdef RTE_LIBRTE_MLX5_DEBUG
MLX5_ASSERT((txq->fcqs[txq->cq_ci & txq->cqe_m] >> 16) ==
cqe->wqe_counter);
#endif
ring_doorbell = true;
++txq->cq_ci;
last_cqe = cqe;
/*
* We have to restrict the amount of processed CQEs
* in one tx_burst routine call. The CQ may be large
* and many CQEs may be updated by the NIC in one
* transaction. Buffers freeing is time consuming,
* multiple iterations may introduce significant latency.
*/
if (likely(--count == 0))
break;
} while (true);
if (likely(ring_doorbell)) {
/* Ring doorbell to notify hardware. */
rte_compiler_barrier();
*txq->cq_db = rte_cpu_to_be_32(txq->cq_ci);
mlx5_tx_comp_flush(txq, last_cqe, olx);
}
}
/**
* DPDK callback to check the status of a Tx descriptor.
*
* @param tx_queue
* The Tx queue.
* @param[in] offset
* The index of the descriptor in the ring.
*
* @return
* The status of the Tx descriptor.
*/
int
mlx5_tx_descriptor_status(void *tx_queue, uint16_t offset)
{
struct mlx5_txq_data *__rte_restrict txq = tx_queue;
uint16_t used;
mlx5_tx_handle_completion(txq, 0);
used = txq->elts_head - txq->elts_tail;
if (offset < used)
return RTE_ETH_TX_DESC_FULL;
return RTE_ETH_TX_DESC_DONE;
}
/*
* Array of declared and compiled Tx burst function and corresponding
* supported offloads set. The array is used to select the Tx burst
* function for specified offloads set at Tx queue configuration time.
*/
const struct {
eth_tx_burst_t func;
unsigned int olx;
} txoff_func[] = {
MLX5_TXOFF_INFO(full_empw,
MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
MLX5_TXOFF_INFO(none_empw,
MLX5_TXOFF_CONFIG_NONE | MLX5_TXOFF_CONFIG_EMPW)
MLX5_TXOFF_INFO(md_empw,
MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
MLX5_TXOFF_INFO(mt_empw,
MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
MLX5_TXOFF_INFO(mtsc_empw,
MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
MLX5_TXOFF_INFO(mti_empw,
MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
MLX5_TXOFF_CONFIG_INLINE |
MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
MLX5_TXOFF_INFO(mtv_empw,
MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
MLX5_TXOFF_CONFIG_VLAN |
MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
MLX5_TXOFF_INFO(mtiv_empw,
MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
MLX5_TXOFF_INFO(sc_empw,
MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
MLX5_TXOFF_INFO(sci_empw,
MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
MLX5_TXOFF_CONFIG_INLINE |
MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
MLX5_TXOFF_INFO(scv_empw,
MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
MLX5_TXOFF_CONFIG_VLAN |
MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
MLX5_TXOFF_INFO(sciv_empw,
MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
MLX5_TXOFF_INFO(i_empw,
MLX5_TXOFF_CONFIG_INLINE |
MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
MLX5_TXOFF_INFO(v_empw,
MLX5_TXOFF_CONFIG_VLAN |
MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
MLX5_TXOFF_INFO(iv_empw,
MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_EMPW)
MLX5_TXOFF_INFO(full_ts_nompw,
MLX5_TXOFF_CONFIG_FULL | MLX5_TXOFF_CONFIG_TXPP)
MLX5_TXOFF_INFO(full_ts_nompwi,
MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
MLX5_TXOFF_CONFIG_VLAN | MLX5_TXOFF_CONFIG_METADATA |
MLX5_TXOFF_CONFIG_TXPP)
MLX5_TXOFF_INFO(full_ts,
MLX5_TXOFF_CONFIG_FULL | MLX5_TXOFF_CONFIG_TXPP |
MLX5_TXOFF_CONFIG_EMPW)
MLX5_TXOFF_INFO(full_ts_noi,
MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
MLX5_TXOFF_CONFIG_VLAN | MLX5_TXOFF_CONFIG_METADATA |
MLX5_TXOFF_CONFIG_TXPP | MLX5_TXOFF_CONFIG_EMPW)
MLX5_TXOFF_INFO(none_ts,
MLX5_TXOFF_CONFIG_NONE | MLX5_TXOFF_CONFIG_TXPP |
MLX5_TXOFF_CONFIG_EMPW)
MLX5_TXOFF_INFO(mdi_ts,
MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_METADATA |
MLX5_TXOFF_CONFIG_TXPP | MLX5_TXOFF_CONFIG_EMPW)
MLX5_TXOFF_INFO(mti_ts,
MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_METADATA |
MLX5_TXOFF_CONFIG_TXPP | MLX5_TXOFF_CONFIG_EMPW)
MLX5_TXOFF_INFO(mtiv_ts,
MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
MLX5_TXOFF_CONFIG_METADATA | MLX5_TXOFF_CONFIG_TXPP |
MLX5_TXOFF_CONFIG_EMPW)
MLX5_TXOFF_INFO(full,
MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
MLX5_TXOFF_CONFIG_METADATA)
MLX5_TXOFF_INFO(none,
MLX5_TXOFF_CONFIG_NONE)
MLX5_TXOFF_INFO(md,
MLX5_TXOFF_CONFIG_METADATA)
MLX5_TXOFF_INFO(mt,
MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
MLX5_TXOFF_CONFIG_METADATA)
MLX5_TXOFF_INFO(mtsc,
MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
MLX5_TXOFF_CONFIG_METADATA)
MLX5_TXOFF_INFO(mti,
MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
MLX5_TXOFF_CONFIG_INLINE |
MLX5_TXOFF_CONFIG_METADATA)
MLX5_TXOFF_INFO(mtv,
MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
MLX5_TXOFF_CONFIG_VLAN |
MLX5_TXOFF_CONFIG_METADATA)
MLX5_TXOFF_INFO(mtiv,
MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_TSO |
MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
MLX5_TXOFF_CONFIG_METADATA)
MLX5_TXOFF_INFO(sc,
MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
MLX5_TXOFF_CONFIG_METADATA)
MLX5_TXOFF_INFO(sci,
MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
MLX5_TXOFF_CONFIG_INLINE |
MLX5_TXOFF_CONFIG_METADATA)
MLX5_TXOFF_INFO(scv,
MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
MLX5_TXOFF_CONFIG_VLAN |
MLX5_TXOFF_CONFIG_METADATA)
MLX5_TXOFF_INFO(sciv,
MLX5_TXOFF_CONFIG_SWP | MLX5_TXOFF_CONFIG_CSUM |
MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
MLX5_TXOFF_CONFIG_METADATA)
MLX5_TXOFF_INFO(i,
MLX5_TXOFF_CONFIG_INLINE |
MLX5_TXOFF_CONFIG_METADATA)
MLX5_TXOFF_INFO(v,
MLX5_TXOFF_CONFIG_VLAN |
MLX5_TXOFF_CONFIG_METADATA)
MLX5_TXOFF_INFO(iv,
MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_VLAN |
MLX5_TXOFF_CONFIG_METADATA)
MLX5_TXOFF_INFO(none_mpw,
MLX5_TXOFF_CONFIG_NONE | MLX5_TXOFF_CONFIG_EMPW |
MLX5_TXOFF_CONFIG_MPW)
MLX5_TXOFF_INFO(mci_mpw,
MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_CSUM |
MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_EMPW |
MLX5_TXOFF_CONFIG_MPW)
MLX5_TXOFF_INFO(mc_mpw,
MLX5_TXOFF_CONFIG_MULTI | MLX5_TXOFF_CONFIG_CSUM |
MLX5_TXOFF_CONFIG_EMPW | MLX5_TXOFF_CONFIG_MPW)
MLX5_TXOFF_INFO(i_mpw,
MLX5_TXOFF_CONFIG_INLINE | MLX5_TXOFF_CONFIG_EMPW |
MLX5_TXOFF_CONFIG_MPW)
};
/**
* Configure the Tx function to use. The routine checks configured
* Tx offloads for the device and selects appropriate Tx burst routine.
* There are multiple Tx burst routines compiled from the same template
* in the most optimal way for the dedicated Tx offloads set.
*
* @param dev
* Pointer to private data structure.
*
* @return
* Pointer to selected Tx burst function.
*/
eth_tx_burst_t
mlx5_select_tx_function(struct rte_eth_dev *dev)
{
struct mlx5_priv *priv = dev->data->dev_private;
struct mlx5_dev_config *config = &priv->config;
uint64_t tx_offloads = dev->data->dev_conf.txmode.offloads;
unsigned int diff = 0, olx = 0, i, m;
MLX5_ASSERT(priv);
if (tx_offloads & DEV_TX_OFFLOAD_MULTI_SEGS) {
/* We should support Multi-Segment Packets. */
olx |= MLX5_TXOFF_CONFIG_MULTI;
}
if (tx_offloads & (DEV_TX_OFFLOAD_TCP_TSO |
DEV_TX_OFFLOAD_VXLAN_TNL_TSO |
DEV_TX_OFFLOAD_GRE_TNL_TSO |
DEV_TX_OFFLOAD_IP_TNL_TSO |
DEV_TX_OFFLOAD_UDP_TNL_TSO)) {
/* We should support TCP Send Offload. */
olx |= MLX5_TXOFF_CONFIG_TSO;
}
if (tx_offloads & (DEV_TX_OFFLOAD_IP_TNL_TSO |
DEV_TX_OFFLOAD_UDP_TNL_TSO |
DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM)) {
/* We should support Software Parser for Tunnels. */
olx |= MLX5_TXOFF_CONFIG_SWP;
}
if (tx_offloads & (DEV_TX_OFFLOAD_IPV4_CKSUM |
DEV_TX_OFFLOAD_UDP_CKSUM |
DEV_TX_OFFLOAD_TCP_CKSUM |
DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM)) {
/* We should support IP/TCP/UDP Checksums. */
olx |= MLX5_TXOFF_CONFIG_CSUM;
}
if (tx_offloads & DEV_TX_OFFLOAD_VLAN_INSERT) {
/* We should support VLAN insertion. */
olx |= MLX5_TXOFF_CONFIG_VLAN;
}
if (tx_offloads & DEV_TX_OFFLOAD_SEND_ON_TIMESTAMP &&
rte_mbuf_dynflag_lookup
(RTE_MBUF_DYNFLAG_TX_TIMESTAMP_NAME, NULL) >= 0 &&
rte_mbuf_dynfield_lookup
(RTE_MBUF_DYNFIELD_TIMESTAMP_NAME, NULL) >= 0) {
/* Offload configured, dynamic entities registered. */
olx |= MLX5_TXOFF_CONFIG_TXPP;
}
if (priv->txqs_n && (*priv->txqs)[0]) {
struct mlx5_txq_data *txd = (*priv->txqs)[0];
if (txd->inlen_send) {
/*
* Check the data inline requirements. Data inline
* is enabled on per device basis, we can check
* the first Tx queue only.
*
* If device does not support VLAN insertion in WQE
* and some queues are requested to perform VLAN
* insertion offload than inline must be enabled.
*/
olx |= MLX5_TXOFF_CONFIG_INLINE;
}
}
if (config->mps == MLX5_MPW_ENHANCED &&
config->txq_inline_min <= 0) {
/*
* The NIC supports Enhanced Multi-Packet Write
* and does not require minimal inline data.
*/
olx |= MLX5_TXOFF_CONFIG_EMPW;
}
if (rte_flow_dynf_metadata_avail()) {
/* We should support Flow metadata. */
olx |= MLX5_TXOFF_CONFIG_METADATA;
}
if (config->mps == MLX5_MPW) {
/*
* The NIC supports Legacy Multi-Packet Write.
* The MLX5_TXOFF_CONFIG_MPW controls the descriptor building
* method in combination with MLX5_TXOFF_CONFIG_EMPW.
*/
if (!(olx & (MLX5_TXOFF_CONFIG_TSO |
MLX5_TXOFF_CONFIG_SWP |
MLX5_TXOFF_CONFIG_VLAN |
MLX5_TXOFF_CONFIG_METADATA)))
olx |= MLX5_TXOFF_CONFIG_EMPW |
MLX5_TXOFF_CONFIG_MPW;
}
/*
* Scan the routines table to find the minimal
* satisfying routine with requested offloads.
*/
m = RTE_DIM(txoff_func);
for (i = 0; i < RTE_DIM(txoff_func); i++) {
unsigned int tmp;
tmp = txoff_func[i].olx;
if (tmp == olx) {
/* Meets requested offloads exactly.*/
m = i;
break;
}
if ((tmp & olx) != olx) {
/* Does not meet requested offloads at all. */
continue;
}
if ((olx ^ tmp) & MLX5_TXOFF_CONFIG_MPW)
/* Do not enable legacy MPW if not configured. */
continue;
if ((olx ^ tmp) & MLX5_TXOFF_CONFIG_EMPW)
/* Do not enable eMPW if not configured. */
continue;
if ((olx ^ tmp) & MLX5_TXOFF_CONFIG_INLINE)
/* Do not enable inlining if not configured. */
continue;
if ((olx ^ tmp) & MLX5_TXOFF_CONFIG_TXPP)
/* Do not enable scheduling if not configured. */
continue;
/*
* Some routine meets the requirements.
* Check whether it has minimal amount
* of not requested offloads.
*/
tmp = __builtin_popcountl(tmp & ~olx);
if (m >= RTE_DIM(txoff_func) || tmp < diff) {
/* First or better match, save and continue. */
m = i;
diff = tmp;
continue;
}
if (tmp == diff) {
tmp = txoff_func[i].olx ^ txoff_func[m].olx;
if (__builtin_ffsl(txoff_func[i].olx & ~tmp) <
__builtin_ffsl(txoff_func[m].olx & ~tmp)) {
/* Lighter not requested offload. */
m = i;
}
}
}
if (m >= RTE_DIM(txoff_func)) {
DRV_LOG(DEBUG, "port %u has no selected Tx function"
" for requested offloads %04X",
dev->data->port_id, olx);
return NULL;
}
DRV_LOG(DEBUG, "port %u has selected Tx function"
" supporting offloads %04X/%04X",
dev->data->port_id, olx, txoff_func[m].olx);
if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_MULTI)
DRV_LOG(DEBUG, "\tMULTI (multi segment)");
if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_TSO)
DRV_LOG(DEBUG, "\tTSO (TCP send offload)");
if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_SWP)
DRV_LOG(DEBUG, "\tSWP (software parser)");
if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_CSUM)
DRV_LOG(DEBUG, "\tCSUM (checksum offload)");
if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_INLINE)
DRV_LOG(DEBUG, "\tINLIN (inline data)");
if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_VLAN)
DRV_LOG(DEBUG, "\tVLANI (VLAN insertion)");
if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_METADATA)
DRV_LOG(DEBUG, "\tMETAD (tx Flow metadata)");
if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_TXPP)
DRV_LOG(DEBUG, "\tMETAD (tx Scheduling)");
if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_EMPW) {
if (txoff_func[m].olx & MLX5_TXOFF_CONFIG_MPW)
DRV_LOG(DEBUG, "\tMPW (Legacy MPW)");
else
DRV_LOG(DEBUG, "\tEMPW (Enhanced MPW)");
}
return txoff_func[m].func;
}
/**
* DPDK callback to get the TX queue information.
*
* @param dev
* Pointer to the device structure.
*
* @param tx_queue_id
* Tx queue identificator.
*
* @param qinfo
* Pointer to the TX queue information structure.
*
* @return
* None.
*/
void
mlx5_txq_info_get(struct rte_eth_dev *dev, uint16_t tx_queue_id,
struct rte_eth_txq_info *qinfo)
{
struct mlx5_priv *priv = dev->data->dev_private;
struct mlx5_txq_data *txq = (*priv->txqs)[tx_queue_id];
struct mlx5_txq_ctrl *txq_ctrl =
container_of(txq, struct mlx5_txq_ctrl, txq);
if (!txq)
return;
qinfo->nb_desc = txq->elts_s;
qinfo->conf.tx_thresh.pthresh = 0;
qinfo->conf.tx_thresh.hthresh = 0;
qinfo->conf.tx_thresh.wthresh = 0;
qinfo->conf.tx_rs_thresh = 0;
qinfo->conf.tx_free_thresh = 0;
qinfo->conf.tx_deferred_start = txq_ctrl ? 0 : 1;
qinfo->conf.offloads = dev->data->dev_conf.txmode.offloads;
}
/**
* DPDK callback to get the TX packet burst mode information.
*
* @param dev
* Pointer to the device structure.
*
* @param tx_queue_id
* Tx queue identificatior.
*
* @param mode
* Pointer to the burts mode information.
*
* @return
* 0 as success, -EINVAL as failure.
*/
int
mlx5_tx_burst_mode_get(struct rte_eth_dev *dev,
uint16_t tx_queue_id,
struct rte_eth_burst_mode *mode)
{
eth_tx_burst_t pkt_burst = dev->tx_pkt_burst;
struct mlx5_priv *priv = dev->data->dev_private;
struct mlx5_txq_data *txq = (*priv->txqs)[tx_queue_id];
unsigned int i, olx;
for (i = 0; i < RTE_DIM(txoff_func); i++) {
if (pkt_burst == txoff_func[i].func) {
olx = txoff_func[i].olx;
snprintf(mode->info, sizeof(mode->info),
"%s%s%s%s%s%s%s%s%s%s",
(olx & MLX5_TXOFF_CONFIG_EMPW) ?
((olx & MLX5_TXOFF_CONFIG_MPW) ?
"Legacy MPW" : "Enhanced MPW") : "No MPW",
(olx & MLX5_TXOFF_CONFIG_MULTI) ?
" + MULTI" : "",
(olx & MLX5_TXOFF_CONFIG_TSO) ?
" + TSO" : "",
(olx & MLX5_TXOFF_CONFIG_SWP) ?
" + SWP" : "",
(olx & MLX5_TXOFF_CONFIG_CSUM) ?
" + CSUM" : "",
(olx & MLX5_TXOFF_CONFIG_INLINE) ?
" + INLINE" : "",
(olx & MLX5_TXOFF_CONFIG_VLAN) ?
" + VLAN" : "",
(olx & MLX5_TXOFF_CONFIG_METADATA) ?
" + METADATA" : "",
(olx & MLX5_TXOFF_CONFIG_TXPP) ?
" + TXPP" : "",
(txq && txq->fast_free) ?
" + Fast Free" : "");
return 0;
}
}
return -EINVAL;
}