| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688 |
- /* 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
- * @truesize: step between consecutive buffers, 0 if none exists
- * @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;
- u32 truesize;
- 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 */
|