From: "Björn Töpel" <bjorn@kernel.org>
To: Magnus Karlsson <magnus.karlsson@intel.com>,
Maciej Fijalkowski <maciej.fijalkowski@intel.com>,
Stanislav Fomichev <sdf@fomichev.me>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@kernel.org>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Simon Horman <horms@kernel.org>, Jonathan Corbet <corbet@lwn.net>,
Shuah Khan <skhan@linuxfoundation.org>,
Randy Dunlap <rdunlap@infradead.org>,
Alexander Duyck <alexanderduyck@fb.com>,
kernel-team@meta.com, Andrew Lunn <andrew+netdev@lunn.ch>,
Jesper Dangaard Brouer <hawk@kernel.org>,
Ilias Apalodimas <ilias.apalodimas@linaro.org>,
Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
John Fastabend <john.fastabend@gmail.com>,
Pavel Begunkov <asml.silence@gmail.com>,
Jens Axboe <axboe@kernel.dk>, Andrii Nakryiko <andrii@kernel.org>,
Eduard Zingerman <eddyz87@gmail.com>,
Kumar Kartikeya Dwivedi <memxor@gmail.com>,
Martin KaFai Lau <martin.lau@linux.dev>,
Song Liu <song@kernel.org>,
Yonghong Song <yonghong.song@linux.dev>,
Jiri Olsa <jolsa@kernel.org>,
Emil Tsalapatis <emil@etsalapatis.com>,
Ihor Solodrai <ihor.solodrai@linux.dev>,
netdev@vger.kernel.org, bpf@vger.kernel.org,
io-uring@vger.kernel.org
Cc: "Björn Töpel" <bjorn@kernel.org>,
"Mike Marciniszyn (Meta)" <mike.marciniszyn@gmail.com>,
"Weiming Shi" <bestswngs@gmail.com>,
"Nikolay Aleksandrov" <razor@blackwall.org>,
"David Wei" <dw@davidwei.uk>,
"Alexander Lobakin" <aleksander.lobakin@intel.com>,
linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
"Mina Almasry" <almasrymina@google.com>
Subject: [RFC net-next 14/15] eth: fbnic: Support AF_XDP zero-copy transmit
Date: Fri, 2 Oct 2026 21:00:15 +0200 [thread overview]
Message-ID: <20261002190018.696925-15-bjorn@kernel.org> (raw)
In-Reply-To: <20261002190018.696925-1-bjorn@kernel.org>
AF_XDP zero copy cannot be advertised until fbnic can send socket TX
descriptors and report their completion.
Send socket descriptors from the RX NAPI poll, and add
ndo_xsk_wakeup to schedule that poll. Record the type of each XDP TX
ring entry. On completion, page-pool buffers go back to page_pool
and UMEM frames go to the AF_XDP completion ring. XDP_TX of provider
RX buffers uses the same records.
Each poll sends at most 64 descriptors per socket, so the
application and NAPI can run at the same time. When a vector has
several sockets, the first one served changes on each poll. The
batch helper does not take a multi-buffer packet that does not fit
the budget left. If a batch was sent and the budget left is smaller
than a maximum-size packet, keep NAPI scheduled.
Socket TX shares the XDP TX ring with XDP_TX. Do socket TX after RX:
XDP_TX drops a frame that does not fit, but a socket descriptor
waits in the socket TX ring.
Advertise AF_XDP zero copy on systems with 4 KiB pages, now that RX
and TX both work.
Signed-off-by: Björn Töpel <bjorn@kernel.org>
---
.../net/ethernet/meta/fbnic/fbnic_netdev.c | 30 +++
drivers/net/ethernet/meta/fbnic/fbnic_txrx.c | 209 ++++++++++++++++--
drivers/net/ethernet/meta/fbnic/fbnic_txrx.h | 18 ++
3 files changed, 238 insertions(+), 19 deletions(-)
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
index 038e91ef14e4..f8495b665d97 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_netdev.c
@@ -666,6 +666,31 @@ static int fbnic_bpf(struct net_device *netdev, struct netdev_bpf *bpf)
}
}
+static int fbnic_xsk_wakeup(struct net_device *netdev, u32 queue_id,
+ u32 __always_unused flags)
+{
+ struct fbnic_net *fbn = netdev_priv(netdev);
+ struct xsk_buff_pool *pool;
+ struct napi_struct *napi;
+
+ if (queue_id >= fbn->num_rx_queues)
+ return -EINVAL;
+ if (!netif_running(netdev))
+ return -ENETDOWN;
+ pool = xsk_get_pool_from_rxq(netdev, queue_id);
+ if (!pool)
+ return -EINVAL;
+
+ napi = __netif_get_rx_queue(netdev, queue_id)->napi;
+ if (WARN_ON_ONCE(!napi))
+ return -EINVAL;
+
+ if (!napi_if_scheduled_mark_missed(napi))
+ napi_schedule(napi);
+
+ return 0;
+}
+
static const struct net_device_ops fbnic_netdev_ops = {
.ndo_open = fbnic_open,
.ndo_stop = fbnic_stop,
@@ -677,6 +702,7 @@ static const struct net_device_ops fbnic_netdev_ops = {
.ndo_set_rx_mode_async = fbnic_set_rx_mode,
.ndo_get_stats64 = fbnic_get_stats64,
.ndo_bpf = fbnic_bpf,
+ .ndo_xsk_wakeup = fbnic_xsk_wakeup,
.ndo_hwtstamp_get = fbnic_hwtstamp_get,
.ndo_hwtstamp_set = fbnic_hwtstamp_set,
};
@@ -935,6 +961,10 @@ struct net_device *fbnic_netdev_alloc(struct fbnic_dev *fbd)
netdev->xdp_features = NETDEV_XDP_ACT_BASIC |
NETDEV_XDP_ACT_REDIRECT |
NETDEV_XDP_ACT_RX_SG;
+ if (PAGE_SIZE == FBNIC_BD_PAGE_SIZE) {
+ netdev->xdp_features |= NETDEV_XDP_ACT_XSK_ZEROCOPY;
+ netdev->xdp_zc_max_segs = FBNIC_MAX_RX_DATA_DESC;
+ }
netdev->min_mtu = IPV6_MIN_MTU;
netdev->max_mtu = FBNIC_MAX_JUMBO_FRAME_SIZE - ETH_HLEN;
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
index e6043607d4e2..6990a7e0fe2f 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
@@ -42,6 +42,7 @@ struct fbnic_xmit_cb {
#define FBNIC_XMIT_CB(__skb) ((struct fbnic_xmit_cb *)((__skb)->cb))
#define FBNIC_XMIT_NOUNMAP ((void *)1)
+#define FBNIC_XSK_TX_BUDGET 64
u32 __iomem *fbnic_ring_csr_base(const struct fbnic_ring *ring)
{
@@ -657,22 +658,79 @@ static void fbnic_clean_twq0(struct fbnic_napi_vector *nv, int napi_budget,
}
}
-static void fbnic_clean_twq1(struct fbnic_napi_vector *nv, bool pp_allow_direct,
+struct fbnic_xsk_tx_complete {
+ struct xsk_buff_pool *pool;
+ u32 descs;
+};
+
+enum fbnic_pp_recycle_mode {
+ FBNIC_PP_RECYCLE_DEFERRED,
+ FBNIC_PP_RECYCLE_DIRECT,
+};
+
+static void
+fbnic_xsk_tx_complete_flush(struct fbnic_xsk_tx_complete *complete)
+{
+ if (!complete->descs)
+ return;
+
+ xsk_tx_completed(complete->pool, complete->descs);
+ complete->descs = 0;
+}
+
+static void
+fbnic_xsk_tx_complete_count(struct fbnic_xsk_tx_complete *complete,
+ struct xsk_buff_pool *pool)
+{
+ if (complete->pool != pool) {
+ fbnic_xsk_tx_complete_flush(complete);
+ complete->pool = pool;
+ }
+
+ complete->descs++;
+}
+
+static void
+fbnic_clean_twq1_buf(struct fbnic_xdp_tx_buf *buf,
+ struct fbnic_xsk_tx_complete *complete,
+ enum fbnic_pp_recycle_mode mode)
+{
+ switch (buf->type) {
+ case FBNIC_XDP_TX_BUF_NETMEM:
+ page_pool_put_full_netmem(netmem_get_pp(buf->netmem),
+ buf->netmem,
+ mode == FBNIC_PP_RECYCLE_DIRECT);
+ break;
+ case FBNIC_XDP_TX_BUF_XSK:
+ fbnic_xsk_tx_complete_count(complete, buf->xsk_pool);
+ break;
+ default:
+ WARN_ON_ONCE(buf->type != FBNIC_XDP_TX_BUF_NONE);
+ break;
+ }
+
+ buf->netmem = 0;
+ buf->type = FBNIC_XDP_TX_BUF_NONE;
+}
+
+static void fbnic_clean_twq1(struct fbnic_napi_vector *nv,
+ enum fbnic_pp_recycle_mode mode,
struct fbnic_ring *ring, bool discard,
unsigned int hw_head)
{
+ struct fbnic_xsk_tx_complete complete = { };
u64 total_bytes = 0, total_packets = 0;
unsigned int head = ring->head;
while (hw_head != head) {
- struct page *page;
+ struct fbnic_xdp_tx_buf *buf;
u64 twd;
if (unlikely(!(ring->desc[head] & FBNIC_TWD_TYPE(AL))))
goto next_desc;
twd = le64_to_cpu(ring->desc[head]);
- page = ring->tx_buf[head];
+ buf = &ring->xdp_buf[head];
/* TYPE_AL is 2, TYPE_LAST_AL is 3. So this trick gives
* us one increment per packet, with no branches.
@@ -681,13 +739,14 @@ static void fbnic_clean_twq1(struct fbnic_napi_vector *nv, bool pp_allow_direct,
FBNIC_TWD_TYPE_AL;
total_bytes += FIELD_GET(FBNIC_TWD_LEN_MASK, twd);
- page_pool_put_page(pp_page_to_nmdesc(page)->pp, page, -1,
- pp_allow_direct);
+ fbnic_clean_twq1_buf(buf, &complete, mode);
next_desc:
head++;
head &= ring->size_mask;
}
+ fbnic_xsk_tx_complete_flush(&complete);
+
if (!total_bytes)
return;
@@ -821,7 +880,8 @@ static void fbnic_clean_twq(struct fbnic_napi_vector *nv, int napi_budget,
if (head1 >= 0) {
qt->cmpl.deferred_head = -1;
if (napi_budget)
- fbnic_clean_twq1(nv, true, &qt->sub1, false, head1);
+ fbnic_clean_twq1(nv, FBNIC_PP_RECYCLE_DIRECT, &qt->sub1,
+ false, head1);
else
qt->cmpl.deferred_head = head1;
}
@@ -1203,7 +1263,7 @@ static long fbnic_pkt_tx(struct fbnic_napi_vector *nv,
unsigned int tail = ring->tail;
struct skb_shared_info *shinfo;
skb_frag_t *frag = NULL;
- struct page *page;
+ netmem_ref netmem;
dma_addr_t dma;
__le64 *twd;
@@ -1221,18 +1281,21 @@ static long fbnic_pkt_tx(struct fbnic_napi_vector *nv,
return -FBNIC_XDP_CONSUME;
}
- page = virt_to_page(pkt->buff.data_hard_start);
- offset = offset_in_page(pkt->buff.data);
- dma = page_pool_get_dma_addr(page);
-
+ netmem = xdp_buff_get_netmem(&pkt->buff);
+ offset = (u8 *)pkt->buff.data -
+ (u8 *)netmem_address(netmem);
+ dma = page_pool_get_dma_addr_netmem(netmem);
size = pkt->buff.data_end - pkt->buff.data;
while (nsegs--) {
+ struct fbnic_xdp_tx_buf *buf = &ring->xdp_buf[tail];
+
dma_sync_single_range_for_device(nv->dev, dma, offset, size,
DMA_BIDIRECTIONAL);
dma += offset;
- ring->tx_buf[tail] = page;
+ buf->netmem = netmem;
+ buf->type = FBNIC_XDP_TX_BUF_NETMEM;
twd = &ring->desc[tail];
*twd = cpu_to_le64(FIELD_PREP(FBNIC_TWD_ADDR_MASK, dma) |
@@ -1247,8 +1310,8 @@ static long fbnic_pkt_tx(struct fbnic_napi_vector *nv,
break;
offset = skb_frag_off(frag);
- page = skb_frag_page(frag);
- dma = page_pool_get_dma_addr(page);
+ netmem = skb_frag_netmem(frag);
+ dma = page_pool_get_dma_addr_netmem(netmem);
size = skb_frag_size(frag);
data_len -= size;
@@ -1490,6 +1553,102 @@ static int fbnic_clean_rcq(struct fbnic_napi_vector *nv,
return complete ? packets : budget;
}
+static bool fbnic_xsk_tx_pool(struct fbnic_ring *ring,
+ struct xsk_buff_pool *pool)
+{
+ unsigned int budget, tail = ring->tail;
+ struct xdp_desc *descs;
+ bool complete = true;
+ bool need_wakeup;
+ u32 i, count;
+
+ need_wakeup = xsk_uses_need_wakeup(pool);
+ if (need_wakeup && ring->head == ring->tail)
+ xsk_set_tx_need_wakeup(pool);
+
+ budget = min_t(unsigned int, fbnic_desc_unused(ring),
+ FBNIC_XSK_TX_BUDGET);
+ if (!budget)
+ goto wake;
+
+ count = xsk_tx_peek_release_desc_batch(pool, budget);
+ /* A shared UMEM bind can allocate the array after pool creation. */
+ descs = pool->tx_descs;
+ for (i = 0; i < count; i++) {
+ struct fbnic_xdp_tx_buf *buf = &ring->xdp_buf[tail];
+ struct xdp_desc_ctx ctx;
+ struct xdp_desc *desc;
+ unsigned int type;
+
+ desc = &descs[i];
+ ctx = xsk_buff_raw_get_ctx(pool, desc->addr, desc->options);
+ xsk_buff_raw_dma_sync_for_device(pool, ctx.dma, desc->len);
+
+ buf->xsk_pool = pool;
+ buf->type = FBNIC_XDP_TX_BUF_XSK;
+ type = xsk_is_eop_desc(desc) ? FBNIC_TWD_TYPE_LAST_AL :
+ FBNIC_TWD_TYPE_AL;
+ ring->desc[tail] =
+ cpu_to_le64(FIELD_PREP(FBNIC_TWD_ADDR_MASK, ctx.dma) |
+ FIELD_PREP(FBNIC_TWD_LEN_MASK, desc->len) |
+ FIELD_PREP(FBNIC_TWD_TYPE_MASK, type));
+
+ tail++;
+ tail &= ring->size_mask;
+ }
+
+ if (count)
+ ring->tail = tail;
+ /* The batch helper stops before a partial multi-buffer packet. Keep
+ * polling if the unused budget was too small for one maximum packet.
+ */
+ complete = !count || budget - count >= pool->xdp_zc_max_segs;
+
+wake:
+ if (need_wakeup && ring->head != ring->tail)
+ xsk_clear_tx_need_wakeup(pool);
+
+ return complete;
+}
+
+static bool fbnic_xsk_tx(struct fbnic_napi_vector *nv)
+{
+ struct fbnic_ring *ring = &nv->qt[0].sub1;
+ unsigned int tail = ring->tail;
+ unsigned int i, queue;
+ bool complete = true;
+
+ if (!nv->rxt_count)
+ return true;
+
+ queue = nv->xsk_tx_start;
+ do {
+ struct xsk_buff_pool *pool;
+
+ i = nv->txt_count + queue;
+ pool = nv->qt[i].xsk_pool;
+ if (pool)
+ complete &= fbnic_xsk_tx_pool(ring, pool);
+
+ queue++;
+ if (queue == nv->rxt_count)
+ queue = 0;
+ } while (queue != nv->xsk_tx_start);
+
+ nv->xsk_tx_start++;
+ if (nv->xsk_tx_start == nv->rxt_count)
+ nv->xsk_tx_start = 0;
+
+ if (tail != ring->tail) {
+ /* Force DMA writes to flush before writing to tail */
+ dma_wmb();
+
+ writel(ring->tail, ring->doorbell);
+ }
+
+ return complete;
+}
+
static void fbnic_nv_irq_disable(struct fbnic_napi_vector *nv)
{
struct fbnic_dev *fbd = nv->fbd;
@@ -1512,6 +1671,7 @@ static int fbnic_poll(struct napi_struct *napi, int budget)
struct fbnic_napi_vector *nv = container_of(napi,
struct fbnic_napi_vector,
napi);
+ bool xsk_complete = true;
int i, j, work_done = 0;
for (i = 0; i < nv->txt_count; i++)
@@ -1520,7 +1680,14 @@ static int fbnic_poll(struct napi_struct *napi, int budget)
for (j = 0; j < nv->rxt_count; j++, i++)
work_done += fbnic_clean_rcq(nv, &nv->qt[i], budget);
- if (work_done >= budget)
+ /* XDP_TX shares this ring and drops frames that do not fit, while
+ * socket TX descriptors wait in the socket's TX ring. Serve XDP_TX
+ * first.
+ */
+ if (budget && nv->rxt_count)
+ xsk_complete = fbnic_xsk_tx(nv);
+
+ if (work_done >= budget || !xsk_complete)
return budget;
if (likely(napi_complete_done(napi, work_done)))
@@ -1884,7 +2051,8 @@ static int fbnic_alloc_napi_vector(struct fbnic_dev *fbd, struct fbnic_net *fbn,
if (xdp_count > 0) {
unsigned int xdp_idx = FBNIC_MAX_TXQS + rxq_idx;
- fbnic_ring_init(&qt->sub1, db, xdp_idx, flags);
+ fbnic_ring_init(&qt->sub1, db, xdp_idx,
+ flags | FBNIC_RING_F_XDP);
fbn->tx[xdp_idx] = &qt->sub1;
xdp_count--;
} else {
@@ -2031,9 +2199,12 @@ static int fbnic_alloc_tx_ring_buffer(struct fbnic_ring *txr)
{
size_t size = array_size(sizeof(*txr->tx_buf), txr->size_mask + 1);
- txr->tx_buf = kvzalloc(size, GFP_KERNEL | __GFP_NOWARN);
+ if (txr->flags & FBNIC_RING_F_XDP)
+ size = array_size(sizeof(*txr->xdp_buf), txr->size_mask + 1);
- return txr->tx_buf ? 0 : -ENOMEM;
+ txr->buffer = kvzalloc(size, GFP_KERNEL | __GFP_NOWARN);
+
+ return txr->buffer ? 0 : -ENOMEM;
}
static int fbnic_alloc_tx_ring_resources(struct fbnic_net *fbn,
@@ -2602,7 +2773,7 @@ static void fbnic_nv_flush(struct fbnic_napi_vector *nv)
/* Clean the work queues of unprocessed work */
fbnic_clean_twq0(nv, 0, &qt->sub0, true, qt->sub0.tail);
- fbnic_clean_twq1(nv, false, &qt->sub1, true,
+ fbnic_clean_twq1(nv, FBNIC_PP_RECYCLE_DEFERRED, &qt->sub1, true,
qt->sub1.tail);
/* Reset completion queue descriptor ring */
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h
index abc96a12ea5c..2fcfe6ac0232 100644
--- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h
+++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h
@@ -36,6 +36,7 @@ struct xsk_buff_pool;
* + 4 descriptors for payload
*/
#define FBNIC_MAX_RX_PKT_DESC 7
+#define FBNIC_MAX_RX_DATA_DESC (FBNIC_MAX_RX_PKT_DESC - 2)
#define FBNIC_RX_DESC_MIN roundup_pow_of_two(FBNIC_MAX_RX_PKT_DESC * 2)
#define FBNIC_MAX_TXQS 128u
@@ -73,6 +74,7 @@ struct xsk_buff_pool;
#define FBNIC_RING_F_DISABLED BIT(0)
#define FBNIC_RING_F_CTX BIT(1)
#define FBNIC_RING_F_STATS BIT(2) /* Ring's stats may be used */
+#define FBNIC_RING_F_XDP BIT(3)
#define FBNIC_HDS_THRESH_MAX \
(4096 - FBNIC_RX_HROOM - FBNIC_RX_TROOM - FBNIC_RX_PAD)
@@ -121,11 +123,26 @@ struct fbnic_rx_buf {
long pagecnt_bias;
};
+enum fbnic_xdp_tx_buf_type {
+ FBNIC_XDP_TX_BUF_NONE = 0,
+ FBNIC_XDP_TX_BUF_NETMEM,
+ FBNIC_XDP_TX_BUF_XSK,
+};
+
+struct fbnic_xdp_tx_buf {
+ union {
+ struct xsk_buff_pool *xsk_pool;
+ netmem_ref netmem;
+ };
+ u8 type;
+};
+
struct fbnic_ring {
/* Pointer to buffer specific info */
union {
struct fbnic_pkt_buff *pkt; /* RCQ */
struct fbnic_rx_buf *rx_buf; /* BDQ */
+ struct fbnic_xdp_tx_buf *xdp_buf; /* TWQ1 */
void **tx_buf; /* TWQ */
void *buffer; /* Generic pointer */
};
@@ -179,6 +196,7 @@ struct fbnic_napi_vector {
u16 v_idx;
u8 txt_count;
u8 rxt_count;
+ u8 xsk_tx_start;
struct fbnic_q_triad qt[];
};
--
2.55.0
next prev parent reply other threads:[~2026-10-02 19:02 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-02 19:00 [RFC net-next 00/15] xsk: Zero copy through page-pool memory providers Björn Töpel
2026-10-02 19:00 ` [RFC net-next 01/15] xdp: Size zero-copy skb heads by their contents Björn Töpel
2026-10-02 19:00 ` [RFC net-next 02/15] eth: fbnic: Report the logical XDP RX queue Björn Töpel
2026-10-02 19:00 ` [RFC net-next 03/15] net: Add memory provider capabilities Björn Töpel
2026-10-03 4:13 ` Mina Almasry
2026-10-09 14:54 ` Björn Töpel
2026-10-03 19:02 ` sashiko-bot
2026-10-12 18:54 ` Björn Töpel
2026-10-05 16:26 ` Stanislav Fomichev
2026-10-12 13:34 ` Björn Töpel
2026-10-02 19:00 ` [RFC net-next 04/15] net: Let memory providers set RX buffer headroom Björn Töpel
2026-10-05 16:52 ` Stanislav Fomichev
2026-10-12 13:35 ` Björn Töpel
2026-10-02 19:00 ` [RFC net-next 05/15] page_pool: Extend memory provider operations Björn Töpel
2026-10-05 16:51 ` Stanislav Fomichev
2026-10-12 13:53 ` Björn Töpel
2026-10-02 19:00 ` [RFC net-next 06/15] xdp: Track non-page netmem in receive buffers Björn Töpel
2026-10-05 17:01 ` Stanislav Fomichev
2026-10-12 14:12 ` Björn Töpel
2026-10-02 19:00 ` [RFC net-next 07/15] xsk: Keep the DMA mapping in the buffer pool Björn Töpel
2026-10-02 19:00 ` [RFC net-next 08/15] xsk: Handle a detached FILL ring in RX wakeup Björn Töpel
2026-10-02 19:00 ` [RFC net-next 09/15] xsk: Add a page-pool memory provider for UMEM Björn Töpel
2026-10-05 17:38 ` Stanislav Fomichev
2026-10-12 14:14 ` Björn Töpel
2026-10-02 19:00 ` [RFC net-next 10/15] xsk: Add RX helpers for page-pool drivers Björn Töpel
2026-10-02 19:00 ` [RFC net-next 11/15] xdp: Copy provider buffers on pass and redirect Björn Töpel
2026-10-03 19:02 ` sashiko-bot
2026-10-12 18:55 ` Björn Töpel
2026-10-02 19:00 ` [RFC net-next 12/15] xsk: Receive provider UMEM without copying Björn Töpel
2026-10-02 19:00 ` [RFC net-next 13/15] eth: fbnic: Support AF_XDP zero-copy receive Björn Töpel
2026-10-03 19:02 ` sashiko-bot
2026-10-12 18:56 ` Björn Töpel
2026-10-05 17:51 ` Stanislav Fomichev
2026-10-12 14:16 ` Björn Töpel
2026-10-02 19:00 ` Björn Töpel [this message]
2026-10-02 19:00 ` [RFC net-next 15/15] Documentation: xsk: Document page-pool zero copy Björn Töpel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261002190018.696925-15-bjorn@kernel.org \
--to=bjorn@kernel.org \
--cc=aleksander.lobakin@intel.com \
--cc=alexanderduyck@fb.com \
--cc=almasrymina@google.com \
--cc=andrew+netdev@lunn.ch \
--cc=andrii@kernel.org \
--cc=asml.silence@gmail.com \
--cc=ast@kernel.org \
--cc=axboe@kernel.dk \
--cc=bestswngs@gmail.com \
--cc=bpf@vger.kernel.org \
--cc=corbet@lwn.net \
--cc=daniel@iogearbox.net \
--cc=davem@davemloft.net \
--cc=dw@davidwei.uk \
--cc=eddyz87@gmail.com \
--cc=edumazet@kernel.org \
--cc=emil@etsalapatis.com \
--cc=hawk@kernel.org \
--cc=horms@kernel.org \
--cc=ihor.solodrai@linux.dev \
--cc=ilias.apalodimas@linaro.org \
--cc=io-uring@vger.kernel.org \
--cc=john.fastabend@gmail.com \
--cc=jolsa@kernel.org \
--cc=kernel-team@meta.com \
--cc=kuba@kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=maciej.fijalkowski@intel.com \
--cc=magnus.karlsson@intel.com \
--cc=martin.lau@linux.dev \
--cc=memxor@gmail.com \
--cc=mike.marciniszyn@gmail.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=razor@blackwall.org \
--cc=rdunlap@infradead.org \
--cc=sdf@fomichev.me \
--cc=skhan@linuxfoundation.org \
--cc=song@kernel.org \
--cc=yonghong.song@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.