* [PATCH net-next 0/3] net: stmmac: page pool Tx buffer quirk
@ 2026-08-03 7:05 muhammad.nazim.amirul.nazle.asmade
2026-08-03 7:05 ` [PATCH net-next 1/3] dt-bindings: net: snps,dwmac: Add snps,pagepool-tx-buf-quirk muhammad.nazim.amirul.nazle.asmade
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: muhammad.nazim.amirul.nazle.asmade @ 2026-08-03 7:05 UTC (permalink / raw)
To: netdev, devicetree, dinguyen
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, robh, krzk+dt,
conor+dt, alexandre.torgue, peppe.cavallaro, joabreu,
mcoquelin.stm32, linux-stm32, linux-arm-kernel, linux-kernel
From: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
This series adds optional use of page pool buffers for stmmac transmit
instead of per-packet streaming dma map/unmap.
On platforms with an IOMMU, the invalidate cost of map/unmap can dominate
small-packet Tx performance. Copying into recycled, already-mapped page
pool buffers can be cheaper. The feature is opt-in via a new DT flag
snps,pagepool-tx-buf-quirk, and is enabled for Agilex5 GMACs.
Page pool Tx buffers are only used for single-fragment, non-TSO frames.
Patches 1-2 are based on netdev/net-next. Patch 3 (DTS) is based on
Dinh Nguyen's socfpga for-next tree.
Nazim Amirul (3):
dt-bindings: net: snps,dwmac: Add snps,pagepool-tx-buf-quirk
net: stmmac: Use pagepool instead of streaming buffers for Tx
arm64: dts: agilex5: Enable pagepool Tx buffer quirk
.../devicetree/bindings/net/snps,dwmac.yaml | 8 +++
.../boot/dts/intel/socfpga_agilex5.dtsi | 3 +
.../net/ethernet/stmicro/stmmac/stmmac.h | 3 +
.../ethernet/stmicro/stmmac/stmmac_main.c | 75 +++++++++++++++++--
.../ethernet/stmicro/stmmac/stmmac_platform.c | 2 +
include/linux/stmmac.h | 1 +
6 files changed, 81 insertions(+), 11 deletions(-)
--
2.43.7
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH net-next 1/3] dt-bindings: net: snps,dwmac: Add snps,pagepool-tx-buf-quirk
2026-08-03 7:05 [PATCH net-next 0/3] net: stmmac: page pool Tx buffer quirk muhammad.nazim.amirul.nazle.asmade
@ 2026-08-03 7:05 ` muhammad.nazim.amirul.nazle.asmade
2026-08-04 8:37 ` Krzysztof Kozlowski
2026-08-03 7:05 ` [PATCH net-next 2/3] net: stmmac: Use pagepool instead of streaming buffers for Tx muhammad.nazim.amirul.nazle.asmade
2026-08-03 7:05 ` [PATCH 3/3] arm64: dts: agilex5: Enable pagepool Tx buffer quirk muhammad.nazim.amirul.nazle.asmade
2 siblings, 1 reply; 7+ messages in thread
From: muhammad.nazim.amirul.nazle.asmade @ 2026-08-03 7:05 UTC (permalink / raw)
To: netdev, devicetree, dinguyen
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, robh, krzk+dt,
conor+dt, alexandre.torgue, peppe.cavallaro, joabreu,
mcoquelin.stm32, linux-stm32, linux-arm-kernel, linux-kernel
From: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
Add a DT flag to enable use of page pool buffers instead of streaming
skb buffers for transmit. This avoids IOMMU invalidate wait time on
platforms where that cost is high, with the trade-off of copying data
from the skb into dma-mapped page pool buffers.
Signed-off-by: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
---
Documentation/devicetree/bindings/net/snps,dwmac.yaml | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/Documentation/devicetree/bindings/net/snps,dwmac.yaml b/Documentation/devicetree/bindings/net/snps,dwmac.yaml
index 2449311c6d28..73045511446f 100644
--- a/Documentation/devicetree/bindings/net/snps,dwmac.yaml
+++ b/Documentation/devicetree/bindings/net/snps,dwmac.yaml
@@ -545,6 +545,14 @@ properties:
Enables the TSO feature otherwise it will be managed by MAC HW capability
register.
+ snps,pagepool-tx-buf-quirk:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description:
+ Enable use of page pool buffers instead of streaming buffers for transmit.
+ This avoids IOMMU invalidate wait time on platforms where that cost is
+ high, with the trade-off of copying data from the skb into dma-mapped
+ page pool buffers.
+
mdio:
$ref: mdio.yaml#
unevaluatedProperties: false
--
2.43.7
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH net-next 2/3] net: stmmac: Use pagepool instead of streaming buffers for Tx
2026-08-03 7:05 [PATCH net-next 0/3] net: stmmac: page pool Tx buffer quirk muhammad.nazim.amirul.nazle.asmade
2026-08-03 7:05 ` [PATCH net-next 1/3] dt-bindings: net: snps,dwmac: Add snps,pagepool-tx-buf-quirk muhammad.nazim.amirul.nazle.asmade
@ 2026-08-03 7:05 ` muhammad.nazim.amirul.nazle.asmade
2026-08-03 18:39 ` Mina Almasry
2026-08-03 7:05 ` [PATCH 3/3] arm64: dts: agilex5: Enable pagepool Tx buffer quirk muhammad.nazim.amirul.nazle.asmade
2 siblings, 1 reply; 7+ messages in thread
From: muhammad.nazim.amirul.nazle.asmade @ 2026-08-03 7:05 UTC (permalink / raw)
To: netdev, devicetree, dinguyen
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, robh, krzk+dt,
conor+dt, alexandre.torgue, peppe.cavallaro, joabreu,
mcoquelin.stm32, linux-stm32, linux-arm-kernel, linux-kernel
From: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
Use page pool buffers instead of streaming skb buffers in stmmac_xmit
when snps,pagepool-tx-buf-quirk is enabled. As page pool buffers are
recycled, the overhead of dma map/unmap for each transmit can be
avoided. There is a trade-off of copying from the skb into the page
pool buffer, but this helps where the copy is cheaper than dma
map/unmap (for example with IOMMU invalidate cost).
Currently page pool buffers are only used for single-fragment transmit
in the non-TSO path.
Signed-off-by: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
---
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 3 +
.../net/ethernet/stmicro/stmmac/stmmac_main.c | 75 ++++++++++++++++---
.../ethernet/stmicro/stmmac/stmmac_platform.c | 2 +
include/linux/stmmac.h | 1 +
4 files changed, 70 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 8ba8f03e1ce0..093c052b4908 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -41,6 +41,7 @@ struct stmmac_resources {
enum stmmac_txbuf_type {
STMMAC_TXBUF_T_SKB,
+ STMMAC_TXBUF_T_DMA,
STMMAC_TXBUF_T_XDP_TX,
STMMAC_TXBUF_T_XDP_NDO,
STMMAC_TXBUF_T_XSK_TX,
@@ -49,6 +50,7 @@ enum stmmac_txbuf_type {
struct stmmac_tx_info {
struct xsk_tx_metadata_compl xsk_meta;
dma_addr_t buf;
+ struct page *page;
unsigned len;
enum stmmac_txbuf_type buf_type;
bool map_as_page;
@@ -65,6 +67,7 @@ struct stmmac_tx_queue {
int tbs;
struct hrtimer txtimer;
u32 queue_index;
+ struct page_pool *page_pool;
struct stmmac_priv *priv_data;
struct dma_extended_desc *dma_etx ____cacheline_aligned_in_smp;
struct dma_edesc *dma_entx;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index ee44bd6f4d48..4aa6b1d1507b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1712,7 +1712,10 @@ static void stmmac_free_tx_buffer(struct stmmac_priv *priv,
if (tx_q->tx_skbuff_dma[i].buf &&
tx_q->tx_skbuff_dma[i].buf_type != STMMAC_TXBUF_T_XDP_TX) {
- if (tx_q->tx_skbuff_dma[i].map_as_page)
+ if (tx_q->tx_skbuff_dma[i].buf_type == STMMAC_TXBUF_T_DMA)
+ page_pool_recycle_direct(tx_q->page_pool,
+ tx_q->tx_skbuff_dma[i].page);
+ else if (tx_q->tx_skbuff_dma[i].map_as_page)
dma_unmap_page(priv->device,
tx_q->tx_skbuff_dma[i].buf,
tx_q->tx_skbuff_dma[i].len,
@@ -1735,7 +1738,8 @@ static void stmmac_free_tx_buffer(struct stmmac_priv *priv,
tx_q->xsk_frames_done++;
if (tx_q->tx_skbuff[i] &&
- tx_q->tx_skbuff_dma[i].buf_type == STMMAC_TXBUF_T_SKB) {
+ (tx_q->tx_skbuff_dma[i].buf_type == STMMAC_TXBUF_T_SKB ||
+ tx_q->tx_skbuff_dma[i].buf_type == STMMAC_TXBUF_T_DMA)) {
dev_kfree_skb_any(tx_q->tx_skbuff[i]);
tx_q->tx_skbuff[i] = NULL;
}
@@ -2201,6 +2205,8 @@ static void __free_dma_tx_desc_resources(struct stmmac_priv *priv,
kfree(tx_q->tx_skbuff_dma);
kfree(tx_q->tx_skbuff);
+ if (tx_q->page_pool)
+ page_pool_destroy(tx_q->page_pool);
}
static void free_dma_tx_desc_resources(struct stmmac_priv *priv,
@@ -2335,12 +2341,32 @@ static int __alloc_dma_tx_desc_resources(struct stmmac_priv *priv,
u32 queue)
{
struct stmmac_tx_queue *tx_q = &dma_conf->tx_queue[queue];
+ struct page_pool_params pp_params = { 0 };
+ unsigned int num_pages;
size_t size;
void *addr;
+ int ret;
tx_q->queue_index = queue;
tx_q->priv_data = priv;
+ pp_params.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV;
+ pp_params.pool_size = dma_conf->dma_tx_size;
+ num_pages = DIV_ROUND_UP(dma_conf->dma_buf_sz, PAGE_SIZE);
+ pp_params.order = ilog2(num_pages);
+ pp_params.nid = dev_to_node(priv->device);
+ pp_params.dev = priv->device;
+ pp_params.dma_dir = DMA_BIDIRECTIONAL;
+ pp_params.offset = 0;
+ pp_params.max_len = num_pages * PAGE_SIZE;
+
+ tx_q->page_pool = page_pool_create(&pp_params);
+ if (IS_ERR(tx_q->page_pool)) {
+ ret = PTR_ERR(tx_q->page_pool);
+ tx_q->page_pool = NULL;
+ return ret;
+ }
+
tx_q->tx_skbuff_dma = kzalloc_objs(*tx_q->tx_skbuff_dma,
dma_conf->dma_tx_size);
if (!tx_q->tx_skbuff_dma)
@@ -2836,7 +2862,8 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue,
tx_q->tx_skbuff_dma[entry].buf_type == STMMAC_TXBUF_T_XDP_NDO) {
xdpf = tx_q->xdpf[entry];
skb = NULL;
- } else if (tx_q->tx_skbuff_dma[entry].buf_type == STMMAC_TXBUF_T_SKB) {
+ } else if (tx_q->tx_skbuff_dma[entry].buf_type == STMMAC_TXBUF_T_SKB ||
+ tx_q->tx_skbuff_dma[entry].buf_type == STMMAC_TXBUF_T_DMA) {
xdpf = NULL;
skb = tx_q->tx_skbuff[entry];
} else {
@@ -2884,7 +2911,10 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue,
if (likely(tx_q->tx_skbuff_dma[entry].buf &&
tx_q->tx_skbuff_dma[entry].buf_type != STMMAC_TXBUF_T_XDP_TX)) {
- if (tx_q->tx_skbuff_dma[entry].map_as_page)
+ if (tx_q->tx_skbuff_dma[entry].buf_type == STMMAC_TXBUF_T_DMA)
+ page_pool_recycle_direct(tx_q->page_pool,
+ tx_q->tx_skbuff_dma[entry].page);
+ else if (tx_q->tx_skbuff_dma[entry].map_as_page)
dma_unmap_page(priv->device,
tx_q->tx_skbuff_dma[entry].buf,
tx_q->tx_skbuff_dma[entry].len,
@@ -2922,7 +2952,8 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue,
if (tx_q->tx_skbuff_dma[entry].buf_type == STMMAC_TXBUF_T_XSK_TX)
tx_q->xsk_frames_done++;
- if (tx_q->tx_skbuff_dma[entry].buf_type == STMMAC_TXBUF_T_SKB) {
+ if (tx_q->tx_skbuff_dma[entry].buf_type == STMMAC_TXBUF_T_SKB ||
+ tx_q->tx_skbuff_dma[entry].buf_type == STMMAC_TXBUF_T_DMA) {
if (likely(skb)) {
pkts_compl++;
bytes_compl += skb->len;
@@ -4742,12 +4773,14 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
bool enh_desc, has_vlan, set_ic, is_jumbo = false;
struct stmmac_priv *priv = netdev_priv(dev);
unsigned int nopaged_len = skb_headlen(skb);
+ gfp_t gfp = GFP_ATOMIC | __GFP_NOWARN;
u32 queue = skb_get_queue_mapping(skb);
int nfrags = skb_shinfo(skb)->nr_frags;
unsigned int first_entry, tx_packets;
struct stmmac_txq_stats *txq_stats;
struct dma_desc *desc, *first_desc;
struct stmmac_tx_queue *tx_q;
+ struct page *tx_buf_page;
int i, csum_insertion = 0;
int entry, first_tx;
dma_addr_t dma_addr;
@@ -4814,13 +4847,33 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
} else {
bool last_segment = (nfrags == 0);
- dma_addr = dma_map_single(priv->device, skb->data,
- nopaged_len, DMA_TO_DEVICE);
- if (dma_mapping_error(priv->device, dma_addr))
- goto dma_map_err;
+ if (!(last_segment && priv->plat->tx_buf_quirk)) {
+ dma_addr = dma_map_single(priv->device, skb->data,
+ nopaged_len, DMA_TO_DEVICE);
+ if (dma_mapping_error(priv->device, dma_addr))
+ goto dma_map_err;
- stmmac_set_tx_skb_dma_entry(tx_q, first_entry, dma_addr,
- nopaged_len, false);
+ stmmac_set_tx_skb_dma_entry(tx_q, first_entry, dma_addr,
+ nopaged_len, false);
+ } else {
+ tx_buf_page = page_pool_alloc_pages(tx_q->page_pool, gfp);
+ if (!tx_buf_page)
+ goto dma_map_err;
+
+ dma_addr = page_pool_get_dma_addr(tx_buf_page);
+ stmmac_set_tx_dma_entry(tx_q, first_entry,
+ STMMAC_TXBUF_T_DMA, dma_addr,
+ nopaged_len, false);
+ tx_q->tx_skbuff_dma[first_entry].page = tx_buf_page;
+
+ dma_sync_single_for_cpu(priv->device, dma_addr,
+ nopaged_len, DMA_BIDIRECTIONAL);
+ skb_copy_from_linear_data(skb, page_address(tx_buf_page),
+ nopaged_len);
+ dma_sync_single_for_device(priv->device, dma_addr,
+ nopaged_len,
+ DMA_BIDIRECTIONAL);
+ }
stmmac_set_desc_addr(priv, first_desc, dma_addr);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index dc5f951a311d..0f8d2fc61ce4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -575,6 +575,8 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
of_property_read_u32(np, "snps,ps-speed", &plat->mac_port_sel_speed);
+ plat->tx_buf_quirk = of_property_read_bool(np, "snps,pagepool-tx-buf-quirk");
+
plat->axi = stmmac_axi_setup(pdev);
rc = stmmac_mtl_setup(pdev, plat);
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index 4430b967abde..d4c9d77a6f81 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -268,6 +268,7 @@ struct plat_stmmacenet_data {
u8 tx_queues_to_use;
u8 rx_sched_algorithm;
u8 tx_sched_algorithm;
+ bool tx_buf_quirk;
struct stmmac_rxq_cfg rx_queues_cfg[MTL_MAX_RX_QUEUES];
struct stmmac_txq_cfg tx_queues_cfg[MTL_MAX_TX_QUEUES];
void (*get_interfaces)(struct stmmac_priv *priv, void *bsp_priv,
--
2.43.7
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 3/3] arm64: dts: agilex5: Enable pagepool Tx buffer quirk
2026-08-03 7:05 [PATCH net-next 0/3] net: stmmac: page pool Tx buffer quirk muhammad.nazim.amirul.nazle.asmade
2026-08-03 7:05 ` [PATCH net-next 1/3] dt-bindings: net: snps,dwmac: Add snps,pagepool-tx-buf-quirk muhammad.nazim.amirul.nazle.asmade
2026-08-03 7:05 ` [PATCH net-next 2/3] net: stmmac: Use pagepool instead of streaming buffers for Tx muhammad.nazim.amirul.nazle.asmade
@ 2026-08-03 7:05 ` muhammad.nazim.amirul.nazle.asmade
2 siblings, 0 replies; 7+ messages in thread
From: muhammad.nazim.amirul.nazle.asmade @ 2026-08-03 7:05 UTC (permalink / raw)
To: netdev, devicetree, dinguyen
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, robh, krzk+dt,
conor+dt, alexandre.torgue, peppe.cavallaro, joabreu,
mcoquelin.stm32, linux-stm32, linux-arm-kernel, linux-kernel
From: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
Enable snps,pagepool-tx-buf-quirk for Agilex5 gmac0/1/2. These ports
use an IOMMU, where avoiding per-packet dma map/unmap invalidate cost
improves Tx performance.
Signed-off-by: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
---
arch/arm64/boot/dts/intel/socfpga_agilex5.dtsi | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/arm64/boot/dts/intel/socfpga_agilex5.dtsi b/arch/arm64/boot/dts/intel/socfpga_agilex5.dtsi
index f54767d1526e..4ce4fa091385 100644
--- a/arch/arm64/boot/dts/intel/socfpga_agilex5.dtsi
+++ b/arch/arm64/boot/dts/intel/socfpga_agilex5.dtsi
@@ -605,6 +605,7 @@ gmac0: ethernet@10810000 {
snps,mtl-tx-config = <&mtl_tx_emac0_setup>;
snps,pbl = <32>;
snps,tso;
+ snps,pagepool-tx-buf-quirk;
altr,sysmgr-syscon = <&sysmgr 0x44 0>;
snps,clk-csr = <0>;
iommus = <&smmu 1>;
@@ -751,6 +752,7 @@ gmac1: ethernet@10820000 {
snps,mtl-tx-config = <&mtl_tx_emac1_setup>;
snps,pbl = <32>;
snps,tso;
+ snps,pagepool-tx-buf-quirk;
altr,sysmgr-syscon = <&sysmgr 0x48 0>;
snps,clk-csr = <0>;
iommus = <&smmu 2>;
@@ -897,6 +899,7 @@ gmac2: ethernet@10830000 {
snps,mtl-tx-config = <&mtl_tx_emac2_setup>;
snps,pbl = <32>;
snps,tso;
+ snps,pagepool-tx-buf-quirk;
altr,sysmgr-syscon = <&sysmgr 0x4c 0>;
snps,clk-csr = <0>;
iommus = <&smmu 3>;
--
2.43.7
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH net-next 2/3] net: stmmac: Use pagepool instead of streaming buffers for Tx
2026-08-03 7:05 ` [PATCH net-next 2/3] net: stmmac: Use pagepool instead of streaming buffers for Tx muhammad.nazim.amirul.nazle.asmade
@ 2026-08-03 18:39 ` Mina Almasry
2026-08-03 18:53 ` Mina Almasry
0 siblings, 1 reply; 7+ messages in thread
From: Mina Almasry @ 2026-08-03 18:39 UTC (permalink / raw)
To: muhammad.nazim.amirul.nazle.asmade, Jesper Dangaard Brouer,
Ilias Apalodimas
Cc: netdev, devicetree, dinguyen, andrew+netdev, davem, edumazet,
kuba, pabeni, robh, krzk+dt, conor+dt, alexandre.torgue,
peppe.cavallaro, joabreu, mcoquelin.stm32, linux-stm32,
linux-arm-kernel, linux-kernel
On Mon, Aug 3, 2026 at 12:08 AM
<muhammad.nazim.amirul.nazle.asmade@altera.com> wrote:
>
> From: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
>
> Use page pool buffers instead of streaming skb buffers in stmmac_xmit
> when snps,pagepool-tx-buf-quirk is enabled. As page pool buffers are
> recycled, the overhead of dma map/unmap for each transmit can be
> avoided. There is a trade-off of copying from the skb into the page
> pool buffer, but this helps where the copy is cheaper than dma
> map/unmap (for example with IOMMU invalidate cost).
>
> Currently page pool buffers are only used for single-fragment transmit
> in the non-TSO path.
>
> Signed-off-by: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
Whoa!
I haven't looked at the patch deeply to be honest, but using the
page-pool for tx is a bit interesting. There is no other code that
uses it like that I think. I can't think of any blockers off the top
of my head, but I think there are places where we keep a global list
of created page_pools on the system/netdev and the code parses those
lists may be assuming it's a normal page-pool, which is a pp used for
rx and attached to the an rx queue.
Just Ccing the maintainers of pp to know about this use case. I can't
think of issues again, but I wonder if a more-expert has thoughts.
--
Thanks,
Mina
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net-next 2/3] net: stmmac: Use pagepool instead of streaming buffers for Tx
2026-08-03 18:39 ` Mina Almasry
@ 2026-08-03 18:53 ` Mina Almasry
0 siblings, 0 replies; 7+ messages in thread
From: Mina Almasry @ 2026-08-03 18:53 UTC (permalink / raw)
To: muhammad.nazim.amirul.nazle.asmade, Jesper Dangaard Brouer,
Ilias Apalodimas
Cc: netdev, devicetree, dinguyen, andrew+netdev, davem, edumazet,
kuba, pabeni, robh, krzk+dt, conor+dt, alexandre.torgue,
peppe.cavallaro, joabreu, mcoquelin.stm32, linux-stm32,
linux-arm-kernel, linux-kernel
On Mon, Aug 3, 2026 at 11:39 AM Mina Almasry <almasrymina@google.com> wrote:
>
> On Mon, Aug 3, 2026 at 12:08 AM
> <muhammad.nazim.amirul.nazle.asmade@altera.com> wrote:
> >
> > From: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
> >
> > Use page pool buffers instead of streaming skb buffers in stmmac_xmit
> > when snps,pagepool-tx-buf-quirk is enabled. As page pool buffers are
> > recycled, the overhead of dma map/unmap for each transmit can be
> > avoided. There is a trade-off of copying from the skb into the page
> > pool buffer, but this helps where the copy is cheaper than dma
> > map/unmap (for example with IOMMU invalidate cost).
> >
> > Currently page pool buffers are only used for single-fragment transmit
> > in the non-TSO path.
> >
> > Signed-off-by: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
>
> Whoa!
>
> I haven't looked at the patch deeply to be honest, but using the
> page-pool for tx is a bit interesting. There is no other code that
> uses it like that I think. I can't think of any blockers off the top
> of my head, but I think there are places where we keep a global list
> of created page_pools on the system/netdev and the code parses those
> lists may be assuming it's a normal page-pool, which is a pp used for
> rx and attached to the an rx queue.
>
> Just Ccing the maintainers of pp to know about this use case. I can't
> think of issues again, but I wonder if a more-expert has thoughts.
>
Ah, yes, gemini reminded me of the most critical bit. The page_pool
actually doesn't do concurrency checks on allocation because it
assumes allocations only-ever come from the napi, and can't race with
allocations coming from another napi. Does your patch account for that
somehow? Or can allocations in tx come from multiple cpus in parallel?
Full feedback:
```
### 1. Concurrency & Memory Corruption (The Lockless Fast-Path)
page_pool allocations (page_pool_alloc_pages()) are lockless in the
fast path (pool->alloc cache). They inherently assume exactly one
allocator context (which natively maps to a single
RX NAPI softirq).
If this driver allows multiple CPUs to concurrently enter the TX
routine and allocate from the same page_pool, the lockless cache will
immediately corrupt. To use it in TX, they must
guarantee:
• They allocate 1 dedicated page_pool per TX ring.
• The TX ring is strictly protected by a spinlock (e.g.
__netif_tx_lock) during all allocations, or they are utilizing strict
CPU-bound XPS.
### 2. Slow-Path Contention (ptr_ring Thrashing)
Even if the locking is safe, performance will likely tank due to
NAPI mismatches.
page_pool keeps its speed because pages freed by the NAPI context
are dropped directly back into the lockless alloc array. If a page is
freed by a remote CPU or an unbound context, it
falls back to a spinlock-protected ptr_ring.
In a TX flow, if CPU A injects the packet (ndo_start_xmit) but CPU B
handles the hardware TX-completion IRQ, CPU B will constantly push
pages into the locked ptr_ring, and CPU A will
constantly pull from it. You lose all the lockless benefits of
page_pool and just burn cycles on cross-CPU spinlocks.
### 3. Memory Waste (Page Splitting)
TX injections are usually small (e.g., bouncing a fragmented
header). page_pool allocates strictly in PAGE_SIZE chunks unless you
heavily orchestrate page_pool_alloc_frag(). Standard
SLUB kmalloc() or skb_alloc() is almost always cheaper, more memory
efficient, and more cache-friendly for TX bounce-buffers than spinning
up dedicated page pools.
TL;DR: Unless the TX allocations and the TX completions are strictly
pinned to the identical NAPI context/CPU, and they are allocating
massive buffers, throwing page_pool at the TX
path usually results in lock contention and memory inefficiency.
They are almost certainly better off using standard kernel allocators,
or at minimum mapping DMA_TO_DEVICE correctly
over standard per-CPU locked pools.
```
--
Thanks,
Mina
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net-next 1/3] dt-bindings: net: snps,dwmac: Add snps,pagepool-tx-buf-quirk
2026-08-03 7:05 ` [PATCH net-next 1/3] dt-bindings: net: snps,dwmac: Add snps,pagepool-tx-buf-quirk muhammad.nazim.amirul.nazle.asmade
@ 2026-08-04 8:37 ` Krzysztof Kozlowski
0 siblings, 0 replies; 7+ messages in thread
From: Krzysztof Kozlowski @ 2026-08-04 8:37 UTC (permalink / raw)
To: muhammad.nazim.amirul.nazle.asmade
Cc: netdev, devicetree, dinguyen, andrew+netdev, davem, edumazet,
kuba, pabeni, robh, krzk+dt, conor+dt, alexandre.torgue,
peppe.cavallaro, joabreu, mcoquelin.stm32, linux-stm32,
linux-arm-kernel, linux-kernel
On Mon, Aug 03, 2026 at 12:05:11AM -0700, muhammad.nazim.amirul.nazle.asmade@altera.com wrote:
> From: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
>
> Add a DT flag to enable use of page pool buffers instead of streaming
> skb buffers for transmit. This avoids IOMMU invalidate wait time on
> platforms where that cost is high, with the trade-off of copying data
> from the skb into dma-mapped page pool buffers.
>
> Signed-off-by: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@altera.com>
> ---
> Documentation/devicetree/bindings/net/snps,dwmac.yaml | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/net/snps,dwmac.yaml b/Documentation/devicetree/bindings/net/snps,dwmac.yaml
> index 2449311c6d28..73045511446f 100644
> --- a/Documentation/devicetree/bindings/net/snps,dwmac.yaml
> +++ b/Documentation/devicetree/bindings/net/snps,dwmac.yaml
> @@ -545,6 +545,14 @@ properties:
> Enables the TSO feature otherwise it will be managed by MAC HW capability
> register.
>
> + snps,pagepool-tx-buf-quirk:
> + $ref: /schemas/types.yaml#/definitions/flag
> + description:
You described the desired Linux feature or behavior, not the actual
hardware. The bindings are about the latter, so instead you need to
rephrase the property and its description to match actual hardware
capabilities/features/configuration etc.
> + Enable use of page pool buffers instead of streaming buffers for transmit.
> + This avoids IOMMU invalidate wait time on platforms where that cost is
> + high, with the trade-off of copying data from the skb into dma-mapped
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-08-04 8:37 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-03 7:05 [PATCH net-next 0/3] net: stmmac: page pool Tx buffer quirk muhammad.nazim.amirul.nazle.asmade
2026-08-03 7:05 ` [PATCH net-next 1/3] dt-bindings: net: snps,dwmac: Add snps,pagepool-tx-buf-quirk muhammad.nazim.amirul.nazle.asmade
2026-08-04 8:37 ` Krzysztof Kozlowski
2026-08-03 7:05 ` [PATCH net-next 2/3] net: stmmac: Use pagepool instead of streaming buffers for Tx muhammad.nazim.amirul.nazle.asmade
2026-08-03 18:39 ` Mina Almasry
2026-08-03 18:53 ` Mina Almasry
2026-08-03 7:05 ` [PATCH 3/3] arm64: dts: agilex5: Enable pagepool Tx buffer quirk muhammad.nazim.amirul.nazle.asmade
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox