mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH net-next] net: ena: reuse the whole RX page on 64kB page kernels
@ 2026-11-06  3:17 Harry Yoo (Meta)
  2026-11-06 10:09 ` Breno Leitao
  0 siblings, 1 reply; 3+ messages in thread
From: Harry Yoo (Meta) @ 2026-11-06  3:17 UTC (permalink / raw)
  To: Arthur Kiyanovski, David Arinzon, Andrew Lunn, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Breno Leitao
  Cc: kernel-team, netdev, linux-kernel, Harry Yoo (Meta)

Since commit ef5b0771d247 ("net: ena: fix driver when PAGE_SIZE ==
64kB"), the RX buffer given to the device is limited to ENA_PAGE_SIZE
(16kB) because the buffer length field in the RX descriptor is 16 bits.
However, the driver still allocates a full page for each RX buffer, so
on a 64kB page kernel only the first 16kB of the page is handed to the
device and the remaining 48kB is never used.

The dynamic RX buffer recycling added by commit f7d625adeb7b ("net: ena:
Add dynamic recycling mechanism for rx buffers") does not fully utilize
the page because ena_try_rx_buf_page_reuse() only reuses what is left
in the current buffer and ignores unused memory in the page.

This shows up when RX data stays in socket receive queues, as each
queued skb keeps the whole 64kB page alive while at most 16kB of it
holds data. On an EC2 t4g.large instance (64kB pages, 8GB memory) with
519MB left unread across 64 TCP sockets, RX pages pinned 2869MB of
memory while the socket layer accounted only 687MB.

Fix this by mapping the whole page and letting
ena_try_rx_buf_page_reuse() size the next buffer from the room left in
the page instead of from what is left of ena_buf->len. ena_buf->len is
then only the length written to the RX descriptor and stays capped at
ENA_PAGE_SIZE. With this fixed, a comparable workload pins only 497MB.

When PAGE_SIZE equals ENA_PAGE_SIZE, the room left in the page equals
ena_buf->len, so nothing changes.

Signed-off-by: Harry Yoo (Meta) <harry@kernel.org>
---
 drivers/net/ethernet/amazon/ena/ena_netdev.c | 23 ++++++++++++++++-------
 1 file changed, 16 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c
index 7eb6456ed0d5..4a35cb6a7785 100644
--- a/drivers/net/ethernet/amazon/ena/ena_netdev.c
+++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c
@@ -492,7 +492,7 @@ static struct page *ena_alloc_map_page(struct ena_ring *rx_ring,
 	/* To enable NIC-side port-mirroring, AKA SPAN port,
 	 * we make the buffer readable from the nic as well
 	 */
-	*dma = dma_map_page(rx_ring->dev, page, 0, ENA_PAGE_SIZE,
+	*dma = dma_map_page(rx_ring->dev, page, 0, PAGE_SIZE,
 			    DMA_BIDIRECTIONAL);
 	if (unlikely(dma_mapping_error(rx_ring->dev, *dma))) {
 		ena_increase_stat(&rx_ring->rx_stats.dma_mapping_err, 1,
@@ -544,7 +544,7 @@ static void ena_unmap_rx_buff_attrs(struct ena_ring *rx_ring,
 				    struct ena_rx_buffer *rx_info,
 				    unsigned long attrs)
 {
-	dma_unmap_page_attrs(rx_ring->dev, rx_info->dma_addr, ENA_PAGE_SIZE, DMA_BIDIRECTIONAL,
+	dma_unmap_page_attrs(rx_ring->dev, rx_info->dma_addr, PAGE_SIZE, DMA_BIDIRECTIONAL,
 			     attrs);
 }
 
@@ -926,19 +926,27 @@ static struct sk_buff *ena_alloc_skb(struct ena_ring *rx_ring, void *first_frag,
 	return skb;
 }
 
-static bool ena_try_rx_buf_page_reuse(struct ena_rx_buffer *rx_info, u16 buf_len,
+static bool ena_try_rx_buf_page_reuse(struct ena_ring *rx_ring,
+				      struct ena_rx_buffer *rx_info, u16 buf_len,
 				      u16 len, int pkt_offset)
 {
+	int tailroom = SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
 	struct ena_com_buf *ena_buf = &rx_info->ena_buf;
+	unsigned long room;
+
+	/* Room left up to the end of the page. On 64kB page kernels this
+	 * can be more than ena_buf->len, which is capped at ENA_PAGE_SIZE.
+	 */
+	room = PAGE_SIZE - rx_info->page_offset - rx_ring->rx_headroom - tailroom;
 
 	/* More than ENA_MIN_RX_BUF_SIZE left in the reused buffer
 	 * for data + headroom + tailroom.
 	 */
-	if (SKB_DATA_ALIGN(len + pkt_offset) + ENA_MIN_RX_BUF_SIZE <= ena_buf->len) {
+	if (SKB_DATA_ALIGN(len + pkt_offset) + ENA_MIN_RX_BUF_SIZE <= room) {
 		page_ref_inc(rx_info->page);
 		rx_info->page_offset += buf_len;
 		ena_buf->paddr += buf_len;
-		ena_buf->len -= buf_len;
+		ena_buf->len = min(room - buf_len, ENA_PAGE_SIZE);
 		return true;
 	}
 
@@ -1011,7 +1019,7 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring,
 
 	/* If XDP isn't loaded try to reuse part of the RX buffer */
 	reuse_rx_buf_page = !is_xdp_loaded &&
-			    ena_try_rx_buf_page_reuse(rx_info, buf_len, len, pkt_offset);
+			    ena_try_rx_buf_page_reuse(rx_ring, rx_info, buf_len, len, pkt_offset);
 
 	if (!reuse_rx_buf_page)
 		ena_unmap_rx_buff_attrs(rx_ring, rx_info, DMA_ATTR_SKIP_CPU_SYNC);
@@ -1055,7 +1063,8 @@ static struct sk_buff *ena_rx_skb(struct ena_ring *rx_ring,
 		pre_reuse_paddr = dma_unmap_addr(&rx_info->ena_buf, paddr);
 
 		reuse_rx_buf_page = !is_xdp_loaded &&
-				    ena_try_rx_buf_page_reuse(rx_info, buf_len, len, pkt_offset);
+				    ena_try_rx_buf_page_reuse(rx_ring, rx_info,
+							      buf_len, len, pkt_offset);
 
 		dma_sync_single_for_cpu(rx_ring->dev,
 					pre_reuse_paddr + pkt_offset,

---
base-commit: 0822d2fe38262e8b55c5ea55c970022bca8dd2a9
change-id: 20261106-ena-rx-reuse-64k-page-3769849b3e0e

Best regards,
--  
Cheers,
Harry / Hyeonggon


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-11-06 11:10 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-06  3:17 [PATCH net-next] net: ena: reuse the whole RX page on 64kB page kernels Harry Yoo (Meta)
2026-11-06 10:09 ` Breno Leitao
2026-11-06 11:10   ` Harry Yoo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®