1b3ad8450SAlexander Lobakin // SPDX-License-Identifier: GPL-2.0-only 2b3ad8450SAlexander Lobakin /* Copyright (C) 2025 Intel Corporation */ 3b3ad8450SAlexander Lobakin 4b3ad8450SAlexander Lobakin #define DEFAULT_SYMBOL_NAMESPACE "LIBETH_XDP" 5b3ad8450SAlexander Lobakin 6b3ad8450SAlexander Lobakin #include <linux/export.h> 7b3ad8450SAlexander Lobakin 8b3ad8450SAlexander Lobakin #include <net/libeth/xsk.h> 9b3ad8450SAlexander Lobakin 10b3ad8450SAlexander Lobakin #include "priv.h" 11b3ad8450SAlexander Lobakin 12b3ad8450SAlexander Lobakin /* ``XDP_TX`` bulking */ 13b3ad8450SAlexander Lobakin 14b3ad8450SAlexander Lobakin void __cold libeth_xsk_tx_return_bulk(const struct libeth_xdp_tx_frame *bq, 15b3ad8450SAlexander Lobakin u32 count) 16b3ad8450SAlexander Lobakin { 17b3ad8450SAlexander Lobakin for (u32 i = 0; i < count; i++) 18b3ad8450SAlexander Lobakin libeth_xsk_buff_free_slow(bq[i].xsk); 19b3ad8450SAlexander Lobakin } 20b3ad8450SAlexander Lobakin 2140e846d1SAlexander Lobakin /* XSk TMO */ 2240e846d1SAlexander Lobakin 2340e846d1SAlexander Lobakin const struct xsk_tx_metadata_ops libeth_xsktmo_slow = { 2440e846d1SAlexander Lobakin .tmo_request_checksum = libeth_xsktmo_req_csum, 2540e846d1SAlexander Lobakin }; 2640e846d1SAlexander Lobakin 27b3ad8450SAlexander Lobakin /* Rx polling path */ 28b3ad8450SAlexander Lobakin 29b3ad8450SAlexander Lobakin /** 30b3ad8450SAlexander Lobakin * libeth_xsk_buff_free_slow - free an XSk Rx buffer 31b3ad8450SAlexander Lobakin * @xdp: buffer to free 32b3ad8450SAlexander Lobakin * 33b3ad8450SAlexander Lobakin * Slowpath version of xsk_buff_free() to be used on exceptions, cleanups etc. 34b3ad8450SAlexander Lobakin * to avoid unwanted inlining. 35b3ad8450SAlexander Lobakin */ 36b3ad8450SAlexander Lobakin void libeth_xsk_buff_free_slow(struct libeth_xdp_buff *xdp) 37b3ad8450SAlexander Lobakin { 38b3ad8450SAlexander Lobakin xsk_buff_free(&xdp->base); 39b3ad8450SAlexander Lobakin } 40b3ad8450SAlexander Lobakin EXPORT_SYMBOL_GPL(libeth_xsk_buff_free_slow); 41*5495c58cSAlexander Lobakin 42*5495c58cSAlexander Lobakin /** 43*5495c58cSAlexander Lobakin * libeth_xsk_buff_add_frag - add frag to XSk Rx buffer 44*5495c58cSAlexander Lobakin * @head: head buffer 45*5495c58cSAlexander Lobakin * @xdp: frag buffer 46*5495c58cSAlexander Lobakin * 47*5495c58cSAlexander Lobakin * External helper used by libeth_xsk_process_buff(), do not call directly. 48*5495c58cSAlexander Lobakin * Frees both main and frag buffers on error. 49*5495c58cSAlexander Lobakin * 50*5495c58cSAlexander Lobakin * Return: main buffer with attached frag on success, %NULL on error (no space 51*5495c58cSAlexander Lobakin * for a new frag). 52*5495c58cSAlexander Lobakin */ 53*5495c58cSAlexander Lobakin struct libeth_xdp_buff *libeth_xsk_buff_add_frag(struct libeth_xdp_buff *head, 54*5495c58cSAlexander Lobakin struct libeth_xdp_buff *xdp) 55*5495c58cSAlexander Lobakin { 56*5495c58cSAlexander Lobakin if (!xsk_buff_add_frag(&head->base, &xdp->base)) 57*5495c58cSAlexander Lobakin goto free; 58*5495c58cSAlexander Lobakin 59*5495c58cSAlexander Lobakin return head; 60*5495c58cSAlexander Lobakin 61*5495c58cSAlexander Lobakin free: 62*5495c58cSAlexander Lobakin libeth_xsk_buff_free_slow(xdp); 63*5495c58cSAlexander Lobakin libeth_xsk_buff_free_slow(head); 64*5495c58cSAlexander Lobakin 65*5495c58cSAlexander Lobakin return NULL; 66*5495c58cSAlexander Lobakin } 67*5495c58cSAlexander Lobakin EXPORT_SYMBOL_GPL(libeth_xsk_buff_add_frag); 68*5495c58cSAlexander Lobakin 69*5495c58cSAlexander Lobakin /** 70*5495c58cSAlexander Lobakin * libeth_xsk_buff_stats_frags - update onstack RQ stats with XSk frags info 71*5495c58cSAlexander Lobakin * @rs: onstack stats to update 72*5495c58cSAlexander Lobakin * @xdp: buffer to account 73*5495c58cSAlexander Lobakin * 74*5495c58cSAlexander Lobakin * External helper used by __libeth_xsk_run_pass(), do not call directly. 75*5495c58cSAlexander Lobakin * Adds buffer's frags count and total len to the onstack stats. 76*5495c58cSAlexander Lobakin */ 77*5495c58cSAlexander Lobakin void libeth_xsk_buff_stats_frags(struct libeth_rq_napi_stats *rs, 78*5495c58cSAlexander Lobakin const struct libeth_xdp_buff *xdp) 79*5495c58cSAlexander Lobakin { 80*5495c58cSAlexander Lobakin libeth_xdp_buff_stats_frags(rs, xdp); 81*5495c58cSAlexander Lobakin } 82*5495c58cSAlexander Lobakin EXPORT_SYMBOL_GPL(libeth_xsk_buff_stats_frags); 83*5495c58cSAlexander Lobakin 84*5495c58cSAlexander Lobakin /** 85*5495c58cSAlexander Lobakin * __libeth_xsk_run_prog_slow - process the non-``XDP_REDIRECT`` verdicts 86*5495c58cSAlexander Lobakin * @xdp: buffer to process 87*5495c58cSAlexander Lobakin * @bq: Tx bulk for queueing on ``XDP_TX`` 88*5495c58cSAlexander Lobakin * @act: verdict to process 89*5495c58cSAlexander Lobakin * @ret: error code if ``XDP_REDIRECT`` failed 90*5495c58cSAlexander Lobakin * 91*5495c58cSAlexander Lobakin * External helper used by __libeth_xsk_run_prog(), do not call directly. 92*5495c58cSAlexander Lobakin * ``XDP_REDIRECT`` is the most common and hottest verdict on XSk, thus 93*5495c58cSAlexander Lobakin * it is processed inline. The rest goes here for out-of-line processing, 94*5495c58cSAlexander Lobakin * together with redirect errors. 95*5495c58cSAlexander Lobakin * 96*5495c58cSAlexander Lobakin * Return: libeth_xdp XDP prog verdict. 97*5495c58cSAlexander Lobakin */ 98*5495c58cSAlexander Lobakin u32 __libeth_xsk_run_prog_slow(struct libeth_xdp_buff *xdp, 99*5495c58cSAlexander Lobakin const struct libeth_xdp_tx_bulk *bq, 100*5495c58cSAlexander Lobakin enum xdp_action act, int ret) 101*5495c58cSAlexander Lobakin { 102*5495c58cSAlexander Lobakin switch (act) { 103*5495c58cSAlexander Lobakin case XDP_DROP: 104*5495c58cSAlexander Lobakin xsk_buff_free(&xdp->base); 105*5495c58cSAlexander Lobakin 106*5495c58cSAlexander Lobakin return LIBETH_XDP_DROP; 107*5495c58cSAlexander Lobakin case XDP_TX: 108*5495c58cSAlexander Lobakin return LIBETH_XDP_TX; 109*5495c58cSAlexander Lobakin case XDP_PASS: 110*5495c58cSAlexander Lobakin return LIBETH_XDP_PASS; 111*5495c58cSAlexander Lobakin default: 112*5495c58cSAlexander Lobakin break; 113*5495c58cSAlexander Lobakin } 114*5495c58cSAlexander Lobakin 115*5495c58cSAlexander Lobakin return libeth_xdp_prog_exception(bq, xdp, act, ret); 116*5495c58cSAlexander Lobakin } 117*5495c58cSAlexander Lobakin EXPORT_SYMBOL_GPL(__libeth_xsk_run_prog_slow); 118*5495c58cSAlexander Lobakin 119*5495c58cSAlexander Lobakin /** 120*5495c58cSAlexander Lobakin * libeth_xsk_prog_exception - handle XDP prog exceptions on XSk 121*5495c58cSAlexander Lobakin * @xdp: buffer to process 122*5495c58cSAlexander Lobakin * @act: verdict returned by the prog 123*5495c58cSAlexander Lobakin * @ret: error code if ``XDP_REDIRECT`` failed 124*5495c58cSAlexander Lobakin * 125*5495c58cSAlexander Lobakin * Internal. Frees the buffer and, if the queue uses XSk wakeups, stop the 126*5495c58cSAlexander Lobakin * current NAPI poll when there are no free buffers left. 127*5495c58cSAlexander Lobakin * 128*5495c58cSAlexander Lobakin * Return: libeth_xdp's XDP prog verdict. 129*5495c58cSAlexander Lobakin */ 130*5495c58cSAlexander Lobakin u32 __cold libeth_xsk_prog_exception(struct libeth_xdp_buff *xdp, 131*5495c58cSAlexander Lobakin enum xdp_action act, int ret) 132*5495c58cSAlexander Lobakin { 133*5495c58cSAlexander Lobakin const struct xdp_buff_xsk *xsk; 134*5495c58cSAlexander Lobakin u32 __ret = LIBETH_XDP_DROP; 135*5495c58cSAlexander Lobakin 136*5495c58cSAlexander Lobakin if (act != XDP_REDIRECT) 137*5495c58cSAlexander Lobakin goto drop; 138*5495c58cSAlexander Lobakin 139*5495c58cSAlexander Lobakin xsk = container_of(&xdp->base, typeof(*xsk), xdp); 140*5495c58cSAlexander Lobakin if (xsk_uses_need_wakeup(xsk->pool) && ret == -ENOBUFS) 141*5495c58cSAlexander Lobakin __ret = LIBETH_XDP_ABORTED; 142*5495c58cSAlexander Lobakin 143*5495c58cSAlexander Lobakin drop: 144*5495c58cSAlexander Lobakin libeth_xsk_buff_free_slow(xdp); 145*5495c58cSAlexander Lobakin 146*5495c58cSAlexander Lobakin return __ret; 147*5495c58cSAlexander Lobakin } 148