/**
* Free the mbufs from the linear array of pointers.
*
+ * @param txq
+ * Pointer to Tx queue structure.
* @param pkts
* Pointer to array of packets to be free.
* @param pkts_n
* compile time and may be used for optimization.
*/
static __rte_always_inline void
-mlx5_tx_free_mbuf(struct rte_mbuf **__rte_restrict pkts,
+mlx5_tx_free_mbuf(struct mlx5_txq_data *__rte_restrict txq,
+ struct rte_mbuf **__rte_restrict pkts,
unsigned int pkts_n,
unsigned int olx __rte_unused)
{
*/
MLX5_ASSERT(pkts);
MLX5_ASSERT(pkts_n);
+ /*
+ * Free mbufs directly to the pool in bulk
+ * if fast free offload is engaged
+ */
+ if (!MLX5_TXOFF_CONFIG(MULTI) && txq->fast_free) {
+ mbuf = *pkts;
+ pool = mbuf->pool;
+ rte_mempool_put_bulk(pool, (void *)pkts, pkts_n);
+ return;
+ }
for (;;) {
for (;;) {
/*
}
}
}
+/*
+ * No inline version to free buffers for optimal call
+ * on the tx_burst completion.
+ */
+static __rte_noinline void
+__mlx5_tx_free_mbuf(struct mlx5_txq_data *__rte_restrict txq,
+ struct rte_mbuf **__rte_restrict pkts,
+ unsigned int pkts_n,
+ unsigned int olx __rte_unused)
+{
+ mlx5_tx_free_mbuf(txq, pkts, pkts_n, olx);
+}
/**
* Free the mbuf from the elts ring buffer till new tail.
part = RTE_MIN(part, n_elts);
MLX5_ASSERT(part);
MLX5_ASSERT(part <= txq->elts_s);
- mlx5_tx_free_mbuf(&txq->elts[txq->elts_tail & txq->elts_m],
+ mlx5_tx_free_mbuf(txq,
+ &txq->elts[txq->elts_tail & txq->elts_m],
part, olx);
txq->elts_tail += part;
n_elts -= part;
MLX5_ASSERT(room >= tlen);
room -= tlen;
/*
- * Packet data are completely inlined,
- * free the packet immediately.
+ * Packet data are completely inline,
+ * we can try to free the packet.
*/
- rte_pktmbuf_free_seg(loc->mbuf);
+ if (likely(loc->pkts_sent == loc->mbuf_free)) {
+ /*
+ * All the packets from the burst beginning
+ * are inline, we can free mbufs directly
+ * from the origin array on tx_burst exit().
+ */
+ loc->mbuf_free++;
+ goto next_mbuf;
+ }
+ /*
+ * In order no to call rte_pktmbuf_free_seg() here,
+ * in the most inner loop (that might be very
+ * expensive) we just save the mbuf in elts.
+ */
+ txq->elts[txq->elts_head++ & txq->elts_m] = loc->mbuf;
+ loc->elts_free--;
goto next_mbuf;
pointer_empw:
/*
mlx5_tx_dseg_ptr(txq, loc, dseg, dptr, dlen, olx);
/* We have to store mbuf in elts.*/
txq->elts[txq->elts_head++ & txq->elts_m] = loc->mbuf;
+ loc->elts_free--;
room -= MLX5_WQE_DSEG_SIZE;
/* Ring buffer wraparound is checked at the loop end.*/
++dseg;
slen += dlen;
#endif
loc->pkts_sent++;
- loc->elts_free--;
pkts_n--;
if (unlikely(!pkts_n || !loc->elts_free)) {
/*
MLX5_ASSERT(txq->wqe_s >= (uint16_t)(txq->wqe_ci - txq->wqe_pi));
if (unlikely(!pkts_n))
return 0;
+ if (MLX5_TXOFF_CONFIG(INLINE))
+ loc.mbuf_free = 0;
loc.pkts_sent = 0;
loc.pkts_copy = 0;
loc.wqe_last = NULL;
/* Increment sent packets counter. */
txq->stats.opackets += loc.pkts_sent;
#endif
+ if (MLX5_TXOFF_CONFIG(INLINE) && loc.mbuf_free)
+ __mlx5_tx_free_mbuf(txq, pkts, loc.mbuf_free, olx);
return loc.pkts_sent;
}
int
mlx5_tx_burst_mode_get(struct rte_eth_dev *dev,
- uint16_t tx_queue_id __rte_unused,
+ 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%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_METADATA) ?
" + METADATA" : "",
(olx & MLX5_TXOFF_CONFIG_TXPP) ?
- " + TXPP" : "");
+ " + TXPP" : "",
+ (txq && txq->fast_free) ?
+ " + Fast Free" : "");
return 0;
}
}