mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00

On 64-bit systems, writing/reading one u64 is faster than two u32s even when they're are adjacent in a struct. The compilers won't guarantee they will combine those; I observed both successful and unsuccessful attempts with both GCC and Clang, and it's not easy to say what it depends on. There's a few places in libeth_xdp winning up to several percent from combined access (both performance and object code size, especially when unrolling). Add __LIBETH_WORD_ACCESS and use it there on LE. Drivers are free to optimize HW-specific callbacks under the same definition. Signed-off-by: Alexander Lobakin <aleksander.lobakin@intel.com> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
685 lines
20 KiB
C
685 lines
20 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/* Copyright (C) 2025 Intel Corporation */
|
|
|
|
#ifndef __LIBETH_XSK_H
|
|
#define __LIBETH_XSK_H
|
|
|
|
#include <net/libeth/xdp.h>
|
|
#include <net/xdp_sock_drv.h>
|
|
|
|
/* ``XDP_TXMD_FLAGS_VALID`` is defined only under ``CONFIG_XDP_SOCKETS`` */
|
|
#ifdef XDP_TXMD_FLAGS_VALID
|
|
static_assert(XDP_TXMD_FLAGS_VALID <= LIBETH_XDP_TX_XSKMD);
|
|
#endif
|
|
|
|
/* ``XDP_TX`` bulking */
|
|
|
|
/**
|
|
* libeth_xsk_tx_queue_head - internal helper for queueing XSk ``XDP_TX`` head
|
|
* @bq: XDP Tx bulk to queue the head frag to
|
|
* @xdp: XSk buffer with the head to queue
|
|
*
|
|
* Return: false if it's the only frag of the frame, true if it's an S/G frame.
|
|
*/
|
|
static inline bool libeth_xsk_tx_queue_head(struct libeth_xdp_tx_bulk *bq,
|
|
struct libeth_xdp_buff *xdp)
|
|
{
|
|
bq->bulk[bq->count++] = (typeof(*bq->bulk)){
|
|
.xsk = xdp,
|
|
__libeth_xdp_tx_len(xdp->base.data_end - xdp->data,
|
|
LIBETH_XDP_TX_FIRST),
|
|
};
|
|
|
|
if (likely(!xdp_buff_has_frags(&xdp->base)))
|
|
return false;
|
|
|
|
bq->bulk[bq->count - 1].flags |= LIBETH_XDP_TX_MULTI;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* libeth_xsk_tx_queue_frag - internal helper for queueing XSk ``XDP_TX`` frag
|
|
* @bq: XDP Tx bulk to queue the frag to
|
|
* @frag: XSk frag to queue
|
|
*/
|
|
static inline void libeth_xsk_tx_queue_frag(struct libeth_xdp_tx_bulk *bq,
|
|
struct libeth_xdp_buff *frag)
|
|
{
|
|
bq->bulk[bq->count++] = (typeof(*bq->bulk)){
|
|
.xsk = frag,
|
|
__libeth_xdp_tx_len(frag->base.data_end - frag->data),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* libeth_xsk_tx_queue_bulk - internal helper for queueing XSk ``XDP_TX`` frame
|
|
* @bq: XDP Tx bulk to queue the frame to
|
|
* @xdp: XSk buffer to queue
|
|
* @flush_bulk: driver callback to flush the bulk to the HW queue
|
|
*
|
|
* Return: true on success, false on flush error.
|
|
*/
|
|
static __always_inline bool
|
|
libeth_xsk_tx_queue_bulk(struct libeth_xdp_tx_bulk *bq,
|
|
struct libeth_xdp_buff *xdp,
|
|
bool (*flush_bulk)(struct libeth_xdp_tx_bulk *bq,
|
|
u32 flags))
|
|
{
|
|
bool ret = true;
|
|
|
|
if (unlikely(bq->count == LIBETH_XDP_TX_BULK) &&
|
|
unlikely(!flush_bulk(bq, LIBETH_XDP_TX_XSK))) {
|
|
libeth_xsk_buff_free_slow(xdp);
|
|
return false;
|
|
}
|
|
|
|
if (!libeth_xsk_tx_queue_head(bq, xdp))
|
|
goto out;
|
|
|
|
for (const struct libeth_xdp_buff *head = xdp; ; ) {
|
|
xdp = container_of(xsk_buff_get_frag(&head->base),
|
|
typeof(*xdp), base);
|
|
if (!xdp)
|
|
break;
|
|
|
|
if (unlikely(bq->count == LIBETH_XDP_TX_BULK) &&
|
|
unlikely(!flush_bulk(bq, LIBETH_XDP_TX_XSK))) {
|
|
ret = false;
|
|
break;
|
|
}
|
|
|
|
libeth_xsk_tx_queue_frag(bq, xdp);
|
|
}
|
|
|
|
out:
|
|
bq->bulk[bq->count - 1].flags |= LIBETH_XDP_TX_LAST;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* libeth_xsk_tx_fill_buf - internal helper to fill XSk ``XDP_TX`` &libeth_sqe
|
|
* @frm: XDP Tx frame from the bulk
|
|
* @i: index on the HW queue
|
|
* @sq: XDPSQ abstraction for the queue
|
|
* @priv: private data
|
|
*
|
|
* Return: XDP Tx descriptor with the synced DMA and other info to pass to
|
|
* the driver callback.
|
|
*/
|
|
static inline struct libeth_xdp_tx_desc
|
|
libeth_xsk_tx_fill_buf(struct libeth_xdp_tx_frame frm, u32 i,
|
|
const struct libeth_xdpsq *sq, u64 priv)
|
|
{
|
|
struct libeth_xdp_buff *xdp = frm.xsk;
|
|
struct libeth_xdp_tx_desc desc = {
|
|
.addr = xsk_buff_xdp_get_dma(&xdp->base),
|
|
.opts = frm.opts,
|
|
};
|
|
struct libeth_sqe *sqe;
|
|
|
|
xsk_buff_raw_dma_sync_for_device(sq->pool, desc.addr, desc.len);
|
|
|
|
sqe = &sq->sqes[i];
|
|
sqe->xsk = xdp;
|
|
|
|
if (!(desc.flags & LIBETH_XDP_TX_FIRST)) {
|
|
sqe->type = LIBETH_SQE_XSK_TX_FRAG;
|
|
return desc;
|
|
}
|
|
|
|
sqe->type = LIBETH_SQE_XSK_TX;
|
|
libeth_xdp_tx_fill_stats(sqe, &desc,
|
|
xdp_get_shared_info_from_buff(&xdp->base));
|
|
|
|
return desc;
|
|
}
|
|
|
|
/**
|
|
* libeth_xsk_tx_flush_bulk - wrapper to define flush of XSk ``XDP_TX`` bulk
|
|
* @bq: bulk to flush
|
|
* @flags: Tx flags, see __libeth_xdp_tx_flush_bulk()
|
|
* @prep: driver callback to prepare the queue
|
|
* @xmit: driver callback to fill a HW descriptor
|
|
*
|
|
* Use via LIBETH_XSK_DEFINE_FLUSH_TX() to define an XSk ``XDP_TX`` driver
|
|
* callback.
|
|
*/
|
|
#define libeth_xsk_tx_flush_bulk(bq, flags, prep, xmit) \
|
|
__libeth_xdp_tx_flush_bulk(bq, (flags) | LIBETH_XDP_TX_XSK, prep, \
|
|
libeth_xsk_tx_fill_buf, xmit)
|
|
|
|
/* XSk TMO */
|
|
|
|
/**
|
|
* libeth_xsktmo_req_csum - XSk Tx metadata op to request checksum offload
|
|
* @csum_start: unused
|
|
* @csum_offset: unused
|
|
* @priv: &libeth_xdp_tx_desc from the filling helper
|
|
*
|
|
* Generic implementation of ::tmo_request_checksum. Works only when HW doesn't
|
|
* require filling checksum offsets and other parameters beside the checksum
|
|
* request bit.
|
|
* Consider using within @libeth_xsktmo unless the driver requires HW-specific
|
|
* callbacks.
|
|
*/
|
|
static inline void libeth_xsktmo_req_csum(u16 csum_start, u16 csum_offset,
|
|
void *priv)
|
|
{
|
|
((struct libeth_xdp_tx_desc *)priv)->flags |= LIBETH_XDP_TX_CSUM;
|
|
}
|
|
|
|
/* Only to inline the callbacks below, use @libeth_xsktmo in drivers instead */
|
|
static const struct xsk_tx_metadata_ops __libeth_xsktmo = {
|
|
.tmo_request_checksum = libeth_xsktmo_req_csum,
|
|
};
|
|
|
|
/**
|
|
* __libeth_xsk_xmit_fill_buf_md - internal helper to prepare XSk xmit w/meta
|
|
* @xdesc: &xdp_desc from the XSk buffer pool
|
|
* @sq: XDPSQ abstraction for the queue
|
|
* @priv: XSk Tx metadata ops
|
|
*
|
|
* Same as __libeth_xsk_xmit_fill_buf(), but requests metadata pointer and
|
|
* fills additional fields in &libeth_xdp_tx_desc to ask for metadata offload.
|
|
*
|
|
* Return: XDP Tx descriptor with the DMA, metadata request bits, and other
|
|
* info to pass to the driver callback.
|
|
*/
|
|
static __always_inline struct libeth_xdp_tx_desc
|
|
__libeth_xsk_xmit_fill_buf_md(const struct xdp_desc *xdesc,
|
|
const struct libeth_xdpsq *sq,
|
|
u64 priv)
|
|
{
|
|
const struct xsk_tx_metadata_ops *tmo = libeth_xdp_priv_to_ptr(priv);
|
|
struct libeth_xdp_tx_desc desc;
|
|
struct xdp_desc_ctx ctx;
|
|
|
|
ctx = xsk_buff_raw_get_ctx(sq->pool, xdesc->addr);
|
|
desc = (typeof(desc)){
|
|
.addr = ctx.dma,
|
|
__libeth_xdp_tx_len(xdesc->len),
|
|
};
|
|
|
|
BUILD_BUG_ON(!__builtin_constant_p(tmo == libeth_xsktmo));
|
|
tmo = tmo == libeth_xsktmo ? &__libeth_xsktmo : tmo;
|
|
|
|
xsk_tx_metadata_request(ctx.meta, tmo, &desc);
|
|
|
|
return desc;
|
|
}
|
|
|
|
/* XSk xmit implementation */
|
|
|
|
/**
|
|
* __libeth_xsk_xmit_fill_buf - internal helper to prepare XSk xmit w/o meta
|
|
* @xdesc: &xdp_desc from the XSk buffer pool
|
|
* @sq: XDPSQ abstraction for the queue
|
|
*
|
|
* Return: XDP Tx descriptor with the DMA and other info to pass to
|
|
* the driver callback.
|
|
*/
|
|
static inline struct libeth_xdp_tx_desc
|
|
__libeth_xsk_xmit_fill_buf(const struct xdp_desc *xdesc,
|
|
const struct libeth_xdpsq *sq)
|
|
{
|
|
return (struct libeth_xdp_tx_desc){
|
|
.addr = xsk_buff_raw_get_dma(sq->pool, xdesc->addr),
|
|
__libeth_xdp_tx_len(xdesc->len),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* libeth_xsk_xmit_fill_buf - internal helper to prepare an XSk xmit
|
|
* @frm: &xdp_desc from the XSk buffer pool
|
|
* @i: index on the HW queue
|
|
* @sq: XDPSQ abstraction for the queue
|
|
* @priv: XSk Tx metadata ops
|
|
*
|
|
* Depending on the metadata ops presence (determined at compile time), calls
|
|
* the quickest helper to build a libeth XDP Tx descriptor.
|
|
*
|
|
* Return: XDP Tx descriptor with the synced DMA, metadata request bits,
|
|
* and other info to pass to the driver callback.
|
|
*/
|
|
static __always_inline struct libeth_xdp_tx_desc
|
|
libeth_xsk_xmit_fill_buf(struct libeth_xdp_tx_frame frm, u32 i,
|
|
const struct libeth_xdpsq *sq, u64 priv)
|
|
{
|
|
struct libeth_xdp_tx_desc desc;
|
|
|
|
if (priv)
|
|
desc = __libeth_xsk_xmit_fill_buf_md(&frm.desc, sq, priv);
|
|
else
|
|
desc = __libeth_xsk_xmit_fill_buf(&frm.desc, sq);
|
|
|
|
desc.flags |= xsk_is_eop_desc(&frm.desc) ? LIBETH_XDP_TX_LAST : 0;
|
|
|
|
xsk_buff_raw_dma_sync_for_device(sq->pool, desc.addr, desc.len);
|
|
|
|
return desc;
|
|
}
|
|
|
|
/**
|
|
* libeth_xsk_xmit_do_bulk - send XSk xmit frames
|
|
* @pool: XSk buffer pool containing the frames to send
|
|
* @xdpsq: opaque pointer to driver's XDPSQ struct
|
|
* @budget: maximum number of frames can be sent
|
|
* @tmo: optional XSk Tx metadata ops
|
|
* @prep: driver callback to build a &libeth_xdpsq
|
|
* @xmit: driver callback to put frames to a HW queue
|
|
* @finalize: driver callback to start a transmission
|
|
*
|
|
* Implements generic XSk xmit. Always turns on XSk Tx wakeup as it's assumed
|
|
* lazy cleaning is used and interrupts are disabled for the queue.
|
|
* HW descriptor filling is unrolled by ``LIBETH_XDP_TX_BATCH`` to optimize
|
|
* writes.
|
|
* Note that unlike other XDP Tx ops, the queue must be locked and cleaned
|
|
* prior to calling this function to already know available @budget.
|
|
* @prepare must only build a &libeth_xdpsq and return ``U32_MAX``.
|
|
*
|
|
* Return: false if @budget was exhausted, true otherwise.
|
|
*/
|
|
static __always_inline bool
|
|
libeth_xsk_xmit_do_bulk(struct xsk_buff_pool *pool, void *xdpsq, u32 budget,
|
|
const struct xsk_tx_metadata_ops *tmo,
|
|
u32 (*prep)(void *xdpsq, struct libeth_xdpsq *sq),
|
|
void (*xmit)(struct libeth_xdp_tx_desc desc, u32 i,
|
|
const struct libeth_xdpsq *sq, u64 priv),
|
|
void (*finalize)(void *xdpsq, bool sent, bool flush))
|
|
{
|
|
const struct libeth_xdp_tx_frame *bulk;
|
|
bool wake;
|
|
u32 n;
|
|
|
|
wake = xsk_uses_need_wakeup(pool);
|
|
if (wake)
|
|
xsk_clear_tx_need_wakeup(pool);
|
|
|
|
n = xsk_tx_peek_release_desc_batch(pool, budget);
|
|
bulk = container_of(&pool->tx_descs[0], typeof(*bulk), desc);
|
|
|
|
libeth_xdp_tx_xmit_bulk(bulk, xdpsq, n, true,
|
|
libeth_xdp_ptr_to_priv(tmo), prep,
|
|
libeth_xsk_xmit_fill_buf, xmit);
|
|
finalize(xdpsq, n, true);
|
|
|
|
if (wake)
|
|
xsk_set_tx_need_wakeup(pool);
|
|
|
|
return n < budget;
|
|
}
|
|
|
|
/* Rx polling path */
|
|
|
|
/**
|
|
* libeth_xsk_tx_init_bulk - initialize XDP Tx bulk for an XSk Rx NAPI poll
|
|
* @bq: bulk to initialize
|
|
* @prog: RCU pointer to the XDP program (never %NULL)
|
|
* @dev: target &net_device
|
|
* @xdpsqs: array of driver XDPSQ structs
|
|
* @num: number of active XDPSQs, the above array length
|
|
*
|
|
* Should be called on an onstack XDP Tx bulk before the XSk NAPI polling loop.
|
|
* Initializes all the needed fields to run libeth_xdp functions.
|
|
* Never checks if @prog is %NULL or @num == 0 as XDP must always be enabled
|
|
* when hitting this path.
|
|
*/
|
|
#define libeth_xsk_tx_init_bulk(bq, prog, dev, xdpsqs, num) \
|
|
__libeth_xdp_tx_init_bulk(bq, prog, dev, xdpsqs, num, true, \
|
|
__UNIQUE_ID(bq_), __UNIQUE_ID(nqs_))
|
|
|
|
struct libeth_xdp_buff *libeth_xsk_buff_add_frag(struct libeth_xdp_buff *head,
|
|
struct libeth_xdp_buff *xdp);
|
|
|
|
/**
|
|
* libeth_xsk_process_buff - attach XSk Rx buffer to &libeth_xdp_buff
|
|
* @head: head XSk buffer to attach the XSk buffer to (or %NULL)
|
|
* @xdp: XSk buffer to process
|
|
* @len: received data length from the descriptor
|
|
*
|
|
* If @head == %NULL, treats the XSk buffer as head and initializes
|
|
* the required fields. Otherwise, attaches the buffer as a frag.
|
|
* Already performs DMA sync-for-CPU and frame start prefetch
|
|
* (for head buffers only).
|
|
*
|
|
* Return: head XSk buffer on success or if the descriptor must be skipped
|
|
* (empty), %NULL if there is no space for a new frag.
|
|
*/
|
|
static inline struct libeth_xdp_buff *
|
|
libeth_xsk_process_buff(struct libeth_xdp_buff *head,
|
|
struct libeth_xdp_buff *xdp, u32 len)
|
|
{
|
|
if (unlikely(!len)) {
|
|
libeth_xsk_buff_free_slow(xdp);
|
|
return head;
|
|
}
|
|
|
|
xsk_buff_set_size(&xdp->base, len);
|
|
xsk_buff_dma_sync_for_cpu(&xdp->base);
|
|
|
|
if (head)
|
|
return libeth_xsk_buff_add_frag(head, xdp);
|
|
|
|
prefetch(xdp->data);
|
|
|
|
return xdp;
|
|
}
|
|
|
|
void libeth_xsk_buff_stats_frags(struct libeth_rq_napi_stats *rs,
|
|
const struct libeth_xdp_buff *xdp);
|
|
|
|
u32 __libeth_xsk_run_prog_slow(struct libeth_xdp_buff *xdp,
|
|
const struct libeth_xdp_tx_bulk *bq,
|
|
enum xdp_action act, int ret);
|
|
|
|
/**
|
|
* __libeth_xsk_run_prog - run XDP program on XSk buffer
|
|
* @xdp: XSk buffer to run the prog on
|
|
* @bq: buffer bulk for ``XDP_TX`` queueing
|
|
*
|
|
* Internal inline abstraction to run XDP program on XSk Rx path. Handles
|
|
* only the most common ``XDP_REDIRECT`` inline, the rest is processed
|
|
* externally.
|
|
* Reports an XDP prog exception on errors.
|
|
*
|
|
* Return: libeth_xdp prog verdict depending on the prog's verdict.
|
|
*/
|
|
static __always_inline u32
|
|
__libeth_xsk_run_prog(struct libeth_xdp_buff *xdp,
|
|
const struct libeth_xdp_tx_bulk *bq)
|
|
{
|
|
enum xdp_action act;
|
|
int ret = 0;
|
|
|
|
act = bpf_prog_run_xdp(bq->prog, &xdp->base);
|
|
if (unlikely(act != XDP_REDIRECT))
|
|
rest:
|
|
return __libeth_xsk_run_prog_slow(xdp, bq, act, ret);
|
|
|
|
ret = xdp_do_redirect(bq->dev, &xdp->base, bq->prog);
|
|
if (unlikely(ret))
|
|
goto rest;
|
|
|
|
return LIBETH_XDP_REDIRECT;
|
|
}
|
|
|
|
/**
|
|
* libeth_xsk_run_prog - run XDP program on XSk path and handle all verdicts
|
|
* @xdp: XSk buffer to process
|
|
* @bq: XDP Tx bulk to queue ``XDP_TX`` buffers
|
|
* @fl: driver ``XDP_TX`` bulk flush callback
|
|
*
|
|
* Run the attached XDP program and handle all possible verdicts.
|
|
* Prefer using it via LIBETH_XSK_DEFINE_RUN{,_PASS,_PROG}().
|
|
*
|
|
* Return: libeth_xdp prog verdict depending on the prog's verdict.
|
|
*/
|
|
#define libeth_xsk_run_prog(xdp, bq, fl) \
|
|
__libeth_xdp_run_flush(xdp, bq, __libeth_xsk_run_prog, \
|
|
libeth_xsk_tx_queue_bulk, fl)
|
|
|
|
/**
|
|
* __libeth_xsk_run_pass - helper to run XDP program and handle the result
|
|
* @xdp: XSk buffer to process
|
|
* @bq: XDP Tx bulk to queue ``XDP_TX`` frames
|
|
* @napi: NAPI to build an skb and pass it up the stack
|
|
* @rs: onstack libeth RQ stats
|
|
* @md: metadata that should be filled to the XSk buffer
|
|
* @prep: callback for filling the metadata
|
|
* @run: driver wrapper to run XDP program
|
|
* @populate: driver callback to populate an skb with the HW descriptor data
|
|
*
|
|
* Inline abstraction, XSk's counterpart of __libeth_xdp_run_pass(), see its
|
|
* doc for details.
|
|
*
|
|
* Return: false if the polling loop must be exited due to lack of free
|
|
* buffers, true otherwise.
|
|
*/
|
|
static __always_inline bool
|
|
__libeth_xsk_run_pass(struct libeth_xdp_buff *xdp,
|
|
struct libeth_xdp_tx_bulk *bq, struct napi_struct *napi,
|
|
struct libeth_rq_napi_stats *rs, const void *md,
|
|
void (*prep)(struct libeth_xdp_buff *xdp,
|
|
const void *md),
|
|
u32 (*run)(struct libeth_xdp_buff *xdp,
|
|
struct libeth_xdp_tx_bulk *bq),
|
|
bool (*populate)(struct sk_buff *skb,
|
|
const struct libeth_xdp_buff *xdp,
|
|
struct libeth_rq_napi_stats *rs))
|
|
{
|
|
struct sk_buff *skb;
|
|
u32 act;
|
|
|
|
rs->bytes += xdp->base.data_end - xdp->data;
|
|
rs->packets++;
|
|
|
|
if (unlikely(xdp_buff_has_frags(&xdp->base)))
|
|
libeth_xsk_buff_stats_frags(rs, xdp);
|
|
|
|
if (prep && (!__builtin_constant_p(!!md) || md))
|
|
prep(xdp, md);
|
|
|
|
act = run(xdp, bq);
|
|
if (likely(act == LIBETH_XDP_REDIRECT))
|
|
return true;
|
|
|
|
if (act != LIBETH_XDP_PASS)
|
|
return act != LIBETH_XDP_ABORTED;
|
|
|
|
skb = xdp_build_skb_from_zc(&xdp->base);
|
|
if (unlikely(!skb)) {
|
|
libeth_xsk_buff_free_slow(xdp);
|
|
return true;
|
|
}
|
|
|
|
if (unlikely(!populate(skb, xdp, rs))) {
|
|
napi_consume_skb(skb, true);
|
|
return true;
|
|
}
|
|
|
|
napi_gro_receive(napi, skb);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* libeth_xsk_run_pass - helper to run XDP program and handle the result
|
|
* @xdp: XSk buffer to process
|
|
* @bq: XDP Tx bulk to queue ``XDP_TX`` frames
|
|
* @napi: NAPI to build an skb and pass it up the stack
|
|
* @rs: onstack libeth RQ stats
|
|
* @desc: pointer to the HW descriptor for that frame
|
|
* @run: driver wrapper to run XDP program
|
|
* @populate: driver callback to populate an skb with the HW descriptor data
|
|
*
|
|
* Wrapper around the underscored version when "fill the descriptor metadata"
|
|
* means just writing the pointer to the HW descriptor as @xdp->desc.
|
|
*/
|
|
#define libeth_xsk_run_pass(xdp, bq, napi, rs, desc, run, populate) \
|
|
__libeth_xsk_run_pass(xdp, bq, napi, rs, desc, libeth_xdp_prep_desc, \
|
|
run, populate)
|
|
|
|
/**
|
|
* libeth_xsk_finalize_rx - finalize XDPSQ after an XSk NAPI polling loop
|
|
* @bq: ``XDP_TX`` frame bulk
|
|
* @flush: driver callback to flush the bulk
|
|
* @finalize: driver callback to start sending the frames and run the timer
|
|
*
|
|
* Flush the bulk if there are frames left to send, kick the queue and flush
|
|
* the XDP maps.
|
|
*/
|
|
#define libeth_xsk_finalize_rx(bq, flush, finalize) \
|
|
__libeth_xdp_finalize_rx(bq, LIBETH_XDP_TX_XSK, flush, finalize)
|
|
|
|
/*
|
|
* Helpers to reduce boilerplate code in drivers.
|
|
*
|
|
* Typical driver XSk Rx flow would be (excl. bulk and buff init, frag attach):
|
|
*
|
|
* LIBETH_XDP_DEFINE_START();
|
|
* LIBETH_XSK_DEFINE_FLUSH_TX(static driver_xsk_flush_tx, driver_xsk_tx_prep,
|
|
* driver_xdp_xmit);
|
|
* LIBETH_XSK_DEFINE_RUN(static driver_xsk_run, driver_xsk_run_prog,
|
|
* driver_xsk_flush_tx, driver_populate_skb);
|
|
* LIBETH_XSK_DEFINE_FINALIZE(static driver_xsk_finalize_rx,
|
|
* driver_xsk_flush_tx, driver_xdp_finalize_sq);
|
|
* LIBETH_XDP_DEFINE_END();
|
|
*
|
|
* This will build a set of 4 static functions. The compiler is free to decide
|
|
* whether to inline them.
|
|
* Then, in the NAPI polling function:
|
|
*
|
|
* while (packets < budget) {
|
|
* // ...
|
|
* if (!driver_xsk_run(xdp, &bq, napi, &rs, desc))
|
|
* break;
|
|
* }
|
|
* driver_xsk_finalize_rx(&bq);
|
|
*/
|
|
|
|
/**
|
|
* LIBETH_XSK_DEFINE_FLUSH_TX - define a driver XSk ``XDP_TX`` flush function
|
|
* @name: name of the function to define
|
|
* @prep: driver callback to clean an XDPSQ
|
|
* @xmit: driver callback to write a HW Tx descriptor
|
|
*/
|
|
#define LIBETH_XSK_DEFINE_FLUSH_TX(name, prep, xmit) \
|
|
__LIBETH_XDP_DEFINE_FLUSH_TX(name, prep, xmit, xsk)
|
|
|
|
/**
|
|
* LIBETH_XSK_DEFINE_RUN_PROG - define a driver XDP program run function
|
|
* @name: name of the function to define
|
|
* @flush: driver callback to flush an XSk ``XDP_TX`` bulk
|
|
*/
|
|
#define LIBETH_XSK_DEFINE_RUN_PROG(name, flush) \
|
|
u32 __LIBETH_XDP_DEFINE_RUN_PROG(name, flush, xsk)
|
|
|
|
/**
|
|
* LIBETH_XSK_DEFINE_RUN_PASS - define a driver buffer process + pass function
|
|
* @name: name of the function to define
|
|
* @run: driver callback to run XDP program (above)
|
|
* @populate: driver callback to fill an skb with HW descriptor info
|
|
*/
|
|
#define LIBETH_XSK_DEFINE_RUN_PASS(name, run, populate) \
|
|
bool __LIBETH_XDP_DEFINE_RUN_PASS(name, run, populate, xsk)
|
|
|
|
/**
|
|
* LIBETH_XSK_DEFINE_RUN - define a driver buffer process, run + pass function
|
|
* @name: name of the function to define
|
|
* @run: name of the XDP prog run function to define
|
|
* @flush: driver callback to flush an XSk ``XDP_TX`` bulk
|
|
* @populate: driver callback to fill an skb with HW descriptor info
|
|
*/
|
|
#define LIBETH_XSK_DEFINE_RUN(name, run, flush, populate) \
|
|
__LIBETH_XDP_DEFINE_RUN(name, run, flush, populate, XSK)
|
|
|
|
/**
|
|
* LIBETH_XSK_DEFINE_FINALIZE - define a driver XSk NAPI poll finalize function
|
|
* @name: name of the function to define
|
|
* @flush: driver callback to flush an XSk ``XDP_TX`` bulk
|
|
* @finalize: driver callback to finalize an XDPSQ and run the timer
|
|
*/
|
|
#define LIBETH_XSK_DEFINE_FINALIZE(name, flush, finalize) \
|
|
__LIBETH_XDP_DEFINE_FINALIZE(name, flush, finalize, xsk)
|
|
|
|
/* Refilling */
|
|
|
|
/**
|
|
* struct libeth_xskfq - structure representing an XSk buffer (fill) queue
|
|
* @fp: hotpath part of the structure
|
|
* @pool: &xsk_buff_pool for buffer management
|
|
* @fqes: array of XSk buffer pointers
|
|
* @descs: opaque pointer to the HW descriptor array
|
|
* @ntu: index of the next buffer to poll
|
|
* @count: number of descriptors/buffers the queue has
|
|
* @pending: current number of XSkFQEs to refill
|
|
* @thresh: threshold below which the queue is refilled
|
|
* @buf_len: HW-writeable length per each buffer
|
|
* @nid: ID of the closest NUMA node with memory
|
|
*/
|
|
struct libeth_xskfq {
|
|
struct_group_tagged(libeth_xskfq_fp, fp,
|
|
struct xsk_buff_pool *pool;
|
|
struct libeth_xdp_buff **fqes;
|
|
void *descs;
|
|
|
|
u32 ntu;
|
|
u32 count;
|
|
);
|
|
|
|
/* Cold fields */
|
|
u32 pending;
|
|
u32 thresh;
|
|
|
|
u32 buf_len;
|
|
int nid;
|
|
};
|
|
|
|
int libeth_xskfq_create(struct libeth_xskfq *fq);
|
|
void libeth_xskfq_destroy(struct libeth_xskfq *fq);
|
|
|
|
/**
|
|
* libeth_xsk_buff_xdp_get_dma - get DMA address of XSk &libeth_xdp_buff
|
|
* @xdp: buffer to get the DMA addr for
|
|
*/
|
|
#define libeth_xsk_buff_xdp_get_dma(xdp) \
|
|
xsk_buff_xdp_get_dma(&(xdp)->base)
|
|
|
|
/**
|
|
* libeth_xskfqe_alloc - allocate @n XSk Rx buffers
|
|
* @fq: hotpath part of the XSkFQ, usually onstack
|
|
* @n: number of buffers to allocate
|
|
* @fill: driver callback to write DMA addresses to HW descriptors
|
|
*
|
|
* Note that @fq->ntu gets updated, but ::pending must be recalculated
|
|
* by the caller.
|
|
*
|
|
* Return: number of buffers refilled.
|
|
*/
|
|
static __always_inline u32
|
|
libeth_xskfqe_alloc(struct libeth_xskfq_fp *fq, u32 n,
|
|
void (*fill)(const struct libeth_xskfq_fp *fq, u32 i))
|
|
{
|
|
u32 this, ret, done = 0;
|
|
struct xdp_buff **xskb;
|
|
|
|
this = fq->count - fq->ntu;
|
|
if (likely(this > n))
|
|
this = n;
|
|
|
|
again:
|
|
xskb = (typeof(xskb))&fq->fqes[fq->ntu];
|
|
ret = xsk_buff_alloc_batch(fq->pool, xskb, this);
|
|
|
|
for (u32 i = 0, ntu = fq->ntu; likely(i < ret); i++)
|
|
fill(fq, ntu + i);
|
|
|
|
done += ret;
|
|
fq->ntu += ret;
|
|
|
|
if (likely(fq->ntu < fq->count) || unlikely(ret < this))
|
|
goto out;
|
|
|
|
fq->ntu = 0;
|
|
|
|
if (this < n) {
|
|
this = n - this;
|
|
goto again;
|
|
}
|
|
|
|
out:
|
|
return done;
|
|
}
|
|
|
|
/* .ndo_xsk_wakeup */
|
|
|
|
void libeth_xsk_init_wakeup(call_single_data_t *csd, struct napi_struct *napi);
|
|
void libeth_xsk_wakeup(call_single_data_t *csd, u32 qid);
|
|
|
|
/* Pool setup */
|
|
|
|
int libeth_xsk_setup_pool(struct net_device *dev, u32 qid, bool enable);
|
|
|
|
#endif /* __LIBETH_XSK_H */
|