mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH iwl-next v2 0/2] libeth, idpf: use GFP_KERNEL for the initial Rx ring fill
@ 2026-10-19 21:06 Luigi Rizzo
  2026-10-19 21:06 ` [PATCH iwl-next v2 1/2] libeth: add libeth_rx_alloc_gfp() to specify allocation flags Luigi Rizzo
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Luigi Rizzo @ 2026-10-19 21:06 UTC (permalink / raw)
  To: intel-wired-lan
  Cc: netdev, Tony Nguyen, Przemek Kitszel, Alexander Lobakin,
	Andrew Lunn, David S . Miller, Eric Dumazet, Luigi Rizzo,
	Brian Vazquez, Joshua Hay, Larysa Zaremba, Jakub Kicinski,
	Paolo Abeni, Simon Horman, linux-kernel, Luigi Rizzo

libeth_rx_alloc() always allocates with GFP_ATOMIC, including when a
driver fills its Rx rings at open or on queue reconfiguration. That
fill runs in process context, right after page_pool_create() and before
the queues' NAPI is enabled, so it may sleep, and GFP_ATOMIC is
needlessly restrictive there: it can neither reclaim nor compact, while
the initial fill can allocate tens of thousands of buffers across all
queues.

Patch 1 adds libeth_rx_alloc_gfp() taking a gfp_t parameter and turns
libeth_rx_alloc() into its GFP_ATOMIC wrapper.
Patch 2 switches idpf's initial Rx ring fill (both splitq and singleq)
to GFP_KERNEL.

v2:
  - split into two patches (libeth helper and idpf consumer)
v1: https://lore.kernel.org/r/20261016151835.2500807-1-lrizzo@google.com/

Luigi Rizzo (2):
  libeth: add libeth_rx_alloc_gfp() to specify allocation flags
  idpf: use GFP_KERNEL for the initial Rx ring fill

 .../ethernet/intel/idpf/idpf_singleq_txrx.c   |  7 +++---
 drivers/net/ethernet/intel/idpf/idpf_txrx.c   |  9 +++++---
 drivers/net/ethernet/intel/idpf/idpf_txrx.h   |  2 +-
 include/net/libeth/rx.h                       | 23 +++++++++++++++----
 4 files changed, 30 insertions(+), 11 deletions(-)

-- 
2.56.0.212.g129ede20d9-goog


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

* [PATCH iwl-next v2 1/2] libeth: add libeth_rx_alloc_gfp() to specify allocation flags
  2026-10-19 21:06 [PATCH iwl-next v2 0/2] libeth, idpf: use GFP_KERNEL for the initial Rx ring fill Luigi Rizzo
@ 2026-10-19 21:06 ` Luigi Rizzo
  2026-10-21 10:42   ` Loktionov, Aleksandr
  2026-10-23 13:34   ` Alexander Lobakin
  2026-10-19 21:06 ` [PATCH iwl-next v2 2/2] idpf: use GFP_KERNEL for the initial Rx ring fill Luigi Rizzo
  2026-10-21 14:57 ` [PATCH iwl-next v2 0/2] libeth, " Alexander Lobakin
  2 siblings, 2 replies; 9+ messages in thread
From: Luigi Rizzo @ 2026-10-19 21:06 UTC (permalink / raw)
  To: intel-wired-lan
  Cc: netdev, Tony Nguyen, Przemek Kitszel, Alexander Lobakin,
	Andrew Lunn, David S . Miller, Eric Dumazet, Luigi Rizzo,
	Brian Vazquez, Joshua Hay, Larysa Zaremba, Jakub Kicinski,
	Paolo Abeni, Simon Horman, linux-kernel, Luigi Rizzo

libeth_rx_alloc() calls page_pool_dev_alloc_netmem(), which always
allocates with GFP_ATOMIC | __GFP_NOWARN. Drivers also use it to fill
their Rx rings at open or on queue reconfiguration, which runs in
process context before the queues' NAPI is enabled. There, the caller
may sleep and GFP_ATOMIC is needlessly restrictive: it can neither
reclaim nor compact, while the initial fill can allocate tens of
thousands of buffers across all queues.

Add libeth_rx_alloc_gfp(), which takes a gfp_t parameter and passes
gfp | __GFP_NOWARN to page_pool_alloc_netmem(), and make
libeth_rx_alloc() its GFP_ATOMIC wrapper.

Signed-off-by: Luigi Rizzo <lrizzo@google.com>
---
 include/net/libeth/rx.h | 23 +++++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)

diff --git a/include/net/libeth/rx.h b/include/net/libeth/rx.h
index 0e736846c5e8a..14a528ea8a075 100644
--- a/include/net/libeth/rx.h
+++ b/include/net/libeth/rx.h
@@ -96,20 +96,23 @@ int libeth_rx_fq_create(struct libeth_fq *fq, void *napi_dev);
 void libeth_rx_fq_destroy(struct libeth_fq *fq);
 
 /**
- * libeth_rx_alloc - allocate a new Rx buffer
+ * libeth_rx_alloc_gfp - allocate a new Rx buffer
  * @fq: fill queue to allocate for
  * @i: index of the buffer within the queue
+ * @gfp: allocation flags: GFP_KERNEL where the caller may sleep (e.g. the
+ *	 initial fill of the ring), GFP_ATOMIC from NAPI
  *
  * Return: DMA address to be passed to HW for Rx on successful allocation,
  * ```DMA_MAPPING_ERROR``` otherwise.
  */
-static inline dma_addr_t libeth_rx_alloc(const struct libeth_fq_fp *fq, u32 i)
+static inline dma_addr_t libeth_rx_alloc_gfp(const struct libeth_fq_fp *fq,
+					     u32 i, gfp_t gfp)
 {
 	struct libeth_fqe *buf = &fq->fqes[i];
 
 	buf->truesize = fq->truesize;
-	buf->netmem = page_pool_dev_alloc_netmem(fq->pp, &buf->offset,
-						 &buf->truesize);
+	buf->netmem = page_pool_alloc_netmem(fq->pp, &buf->offset,
+					     &buf->truesize, gfp | __GFP_NOWARN);
 	if (unlikely(!buf->netmem))
 		return DMA_MAPPING_ERROR;
 
@@ -117,6 +120,18 @@ static inline dma_addr_t libeth_rx_alloc(const struct libeth_fq_fp *fq, u32 i)
 	       fq->pp->p.offset;
 }
 
+/**
+ * libeth_rx_alloc - allocate a new Rx buffer from NAPI context
+ * @fq: fill queue to allocate for
+ * @i: index of the buffer within the queue
+ *
+ * Return: as libeth_rx_alloc_gfp().
+ */
+static inline dma_addr_t libeth_rx_alloc(const struct libeth_fq_fp *fq, u32 i)
+{
+	return libeth_rx_alloc_gfp(fq, i, GFP_ATOMIC);
+}
+
 void libeth_rx_recycle_slow(netmem_ref netmem);
 
 /**
-- 
2.56.0.212.g129ede20d9-goog


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

* [PATCH iwl-next v2 2/2] idpf: use GFP_KERNEL for the initial Rx ring fill
  2026-10-19 21:06 [PATCH iwl-next v2 0/2] libeth, idpf: use GFP_KERNEL for the initial Rx ring fill Luigi Rizzo
  2026-10-19 21:06 ` [PATCH iwl-next v2 1/2] libeth: add libeth_rx_alloc_gfp() to specify allocation flags Luigi Rizzo
@ 2026-10-19 21:06 ` Luigi Rizzo
  2026-10-21 10:43   ` Loktionov, Aleksandr
  2026-10-21 14:57 ` [PATCH iwl-next v2 0/2] libeth, " Alexander Lobakin
  2 siblings, 1 reply; 9+ messages in thread
From: Luigi Rizzo @ 2026-10-19 21:06 UTC (permalink / raw)
  To: intel-wired-lan
  Cc: netdev, Tony Nguyen, Przemek Kitszel, Alexander Lobakin,
	Andrew Lunn, David S . Miller, Eric Dumazet, Luigi Rizzo,
	Brian Vazquez, Joshua Hay, Larysa Zaremba, Jakub Kicinski,
	Paolo Abeni, Simon Horman, linux-kernel, Luigi Rizzo

When idpf fills its Rx rings at open or on queue reconfiguration, the
allocation runs in process context, right after page_pool_create() and
before the queues' NAPI is enabled. Allocating tens of thousands of
buffers across all queues with GFP_ATOMIC is needlessly restrictive
when the caller may sleep.

In splitq mode, idpf_rx_post_buf_desc() is only used for this initial
fill, so switch its header and payload allocations to
libeth_rx_alloc_gfp(..., GFP_KERNEL).

In singleq mode, add a gfp_t parameter to
idpf_rx_singleq_buf_hw_alloc_all() and pass GFP_KERNEL from
idpf_rx_buf_alloc_singleq() and GFP_ATOMIC from idpf_rx_singleq_clean().

Signed-off-by: Luigi Rizzo <lrizzo@google.com>
---
 drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c | 7 ++++---
 drivers/net/ethernet/intel/idpf/idpf_txrx.c         | 9 ++++++---
 drivers/net/ethernet/intel/idpf/idpf_txrx.h         | 2 +-
 3 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
index e3ddf18dcbf51..d623e4ab8511f 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
@@ -885,11 +885,12 @@ static void idpf_rx_buf_hw_update(struct idpf_rx_queue *rxq, u32 val)
  * idpf_rx_singleq_buf_hw_alloc_all - Replace used receive buffers
  * @rx_q: queue for which the hw buffers are allocated
  * @cleaned_count: number of buffers to replace
+ * @gfp: GFP_KERNEL for the initial fill, GFP_ATOMIC from NAPI
  *
  * Returns false if all allocations were successful, true if any fail
  */
 bool idpf_rx_singleq_buf_hw_alloc_all(struct idpf_rx_queue *rx_q,
-				      u16 cleaned_count)
+				      u16 cleaned_count, gfp_t gfp)
 {
 	struct virtchnl2_singleq_rx_buf_desc *desc;
 	const struct libeth_fq_fp fq = {
@@ -908,7 +909,7 @@ bool idpf_rx_singleq_buf_hw_alloc_all(struct idpf_rx_queue *rx_q,
 	do {
 		dma_addr_t addr;
 
-		addr = libeth_rx_alloc(&fq, nta);
+		addr = libeth_rx_alloc_gfp(&fq, nta, gfp);
 		if (addr == DMA_MAPPING_ERROR)
 			break;
 
@@ -1095,7 +1096,7 @@ static int idpf_rx_singleq_clean(struct idpf_rx_queue *rx_q, int budget)
 
 	page_pool_nid_changed(rx_q->pp, numa_mem_id());
 	if (cleaned_count)
-		idpf_rx_singleq_buf_hw_alloc_all(rx_q, cleaned_count);
+		idpf_rx_singleq_buf_hw_alloc_all(rx_q, cleaned_count, GFP_ATOMIC);
 
 	u64_stats_update_begin(&rx_q->stats_sync);
 	u64_stats_add(&rx_q->q_stats.packets, rs.packets);
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
index 4311ffa30bb18..b1127ab48ef3f 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -600,6 +600,9 @@ static void idpf_post_buf_refill(struct idpf_sw_queue *refillq, u16 buf_id)
  * @bufq: buffer queue to post to
  * @buf_id: buffer id to post
  *
+ * Only used for the initial fill, from process context, so it allocates
+ * with GFP_KERNEL.
+ *
  * Return: %false if buffer could not be allocated, %true otherwise.
  */
 static bool idpf_rx_post_buf_desc(struct idpf_buf_queue *bufq, u16 buf_id)
@@ -618,7 +621,7 @@ static bool idpf_rx_post_buf_desc(struct idpf_buf_queue *bufq, u16 buf_id)
 		fq.fqes = bufq->hdr_buf;
 		fq.truesize = bufq->hdr_truesize;
 
-		addr = libeth_rx_alloc(&fq, buf_id);
+		addr = libeth_rx_alloc_gfp(&fq, buf_id, GFP_KERNEL);
 		if (addr == DMA_MAPPING_ERROR)
 			return false;
 
@@ -629,7 +632,7 @@ static bool idpf_rx_post_buf_desc(struct idpf_buf_queue *bufq, u16 buf_id)
 	fq.fqes = bufq->buf;
 	fq.truesize = bufq->truesize;
 
-	addr = libeth_rx_alloc(&fq, buf_id);
+	addr = libeth_rx_alloc_gfp(&fq, buf_id, GFP_KERNEL);
 	if (addr == DMA_MAPPING_ERROR)
 		return false;
 
@@ -675,7 +678,7 @@ static bool idpf_rx_post_init_bufs(struct idpf_buf_queue *bufq,
  */
 static int idpf_rx_buf_alloc_singleq(struct idpf_rx_queue *rxq)
 {
-	if (idpf_rx_singleq_buf_hw_alloc_all(rxq, rxq->desc_count - 1))
+	if (idpf_rx_singleq_buf_hw_alloc_all(rxq, rxq->desc_count - 1, GFP_KERNEL))
 		goto err;
 
 	return 0;
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
index 93547597efd2a..e27438c78ec79 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
@@ -1123,7 +1123,7 @@ netdev_tx_t idpf_tx_singleq_frame(struct sk_buff *skb,
 				  struct idpf_tx_queue *tx_q);
 netdev_tx_t idpf_tx_start(struct sk_buff *skb, struct net_device *netdev);
 bool idpf_rx_singleq_buf_hw_alloc_all(struct idpf_rx_queue *rxq,
-				      u16 cleaned_count);
+				      u16 cleaned_count, gfp_t gfp);
 bool idpf_rx_process_skb_fields(struct sk_buff *skb,
 				const struct libeth_xdp_buff *xdp,
 				struct libeth_rq_napi_stats *rs);
-- 
2.56.0.212.g129ede20d9-goog


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

* RE: [PATCH iwl-next v2 1/2] libeth: add libeth_rx_alloc_gfp() to specify allocation flags
  2026-10-19 21:06 ` [PATCH iwl-next v2 1/2] libeth: add libeth_rx_alloc_gfp() to specify allocation flags Luigi Rizzo
@ 2026-10-21 10:42   ` Loktionov, Aleksandr
  2026-10-23 13:34   ` Alexander Lobakin
  1 sibling, 0 replies; 9+ messages in thread
From: Loktionov, Aleksandr @ 2026-10-21 10:42 UTC (permalink / raw)
  To: Luigi Rizzo, intel-wired-lan
  Cc: netdev, Nguyen, Anthony L, Kitszel, Przemyslaw, Lobakin,
	Aleksander, Andrew Lunn, David S . Miller, Eric Dumazet,
	Luigi Rizzo, Brian Vazquez, Hay, Joshua A, Zaremba, Larysa,
	Jakub Kicinski, Paolo Abeni, Simon Horman, linux-kernel



> -----Original Message-----
> From: Luigi Rizzo <lrizzo@google.com>
> Sent: Monday, October 19, 2026 11:06 PM
> To: intel-wired-lan@lists.osuosl.org
> Cc: netdev@vger.kernel.org; Nguyen, Anthony L
> <anthony.l.nguyen@intel.com>; Kitszel, Przemyslaw
> <przemyslaw.kitszel@intel.com>; Lobakin, Aleksander
> <aleksander.lobakin@intel.com>; Andrew Lunn <andrew+netdev@lunn.ch>;
> David S . Miller <davem@davemloft.net>; Eric Dumazet
> <edumazet@kernel.org>; Luigi Rizzo <rizzo.unipi@gmail.com>; Brian
> Vazquez <brianvv@google.com>; Hay, Joshua A <joshua.a.hay@intel.com>;
> Zaremba, Larysa <larysa.zaremba@intel.com>; Jakub Kicinski
> <kuba@kernel.org>; Paolo Abeni <pabeni@redhat.com>; Simon Horman
> <horms@kernel.org>; linux-kernel@vger.kernel.org; Luigi Rizzo
> <lrizzo@google.com>
> Subject: [PATCH iwl-next v2 1/2] libeth: add libeth_rx_alloc_gfp() to
> specify allocation flags
> 
> libeth_rx_alloc() calls page_pool_dev_alloc_netmem(), which always
> allocates with GFP_ATOMIC | __GFP_NOWARN. Drivers also use it to fill
> their Rx rings at open or on queue reconfiguration, which runs in
> process context before the queues' NAPI is enabled. There, the caller
> may sleep and GFP_ATOMIC is needlessly restrictive: it can neither
> reclaim nor compact, while the initial fill can allocate tens of
> thousands of buffers across all queues.
> 
> Add libeth_rx_alloc_gfp(), which takes a gfp_t parameter and passes gfp
> | __GFP_NOWARN to page_pool_alloc_netmem(), and make
> libeth_rx_alloc() its GFP_ATOMIC wrapper.
> 
> Signed-off-by: Luigi Rizzo <lrizzo@google.com>
> ---
>  include/net/libeth/rx.h | 23 +++++++++++++++++++----
>  1 file changed, 19 insertions(+), 4 deletions(-)
> 
> diff --git a/include/net/libeth/rx.h b/include/net/libeth/rx.h index
> 0e736846c5e8a..14a528ea8a075 100644
> --- a/include/net/libeth/rx.h
> +++ b/include/net/libeth/rx.h
> @@ -96,20 +96,23 @@ int libeth_rx_fq_create(struct libeth_fq *fq, void
> *napi_dev);  void libeth_rx_fq_destroy(struct libeth_fq *fq);
> 
>  /**
> - * libeth_rx_alloc - allocate a new Rx buffer
> + * libeth_rx_alloc_gfp - allocate a new Rx buffer
>   * @fq: fill queue to allocate for
>   * @i: index of the buffer within the queue
> + * @gfp: allocation flags: GFP_KERNEL where the caller may sleep (e.g.
> the
> + *	 initial fill of the ring), GFP_ATOMIC from NAPI
>   *
>   * Return: DMA address to be passed to HW for Rx on successful
> allocation,
>   * ```DMA_MAPPING_ERROR``` otherwise.
>   */
> -static inline dma_addr_t libeth_rx_alloc(const struct libeth_fq_fp *fq,
> u32 i)
> +static inline dma_addr_t libeth_rx_alloc_gfp(const struct libeth_fq_fp
> *fq,
> +					     u32 i, gfp_t gfp)
>  {
>  	struct libeth_fqe *buf = &fq->fqes[i];
> 
>  	buf->truesize = fq->truesize;
> -	buf->netmem = page_pool_dev_alloc_netmem(fq->pp, &buf->offset,
> -						 &buf->truesize);
> +	buf->netmem = page_pool_alloc_netmem(fq->pp, &buf->offset,
> +					     &buf->truesize, gfp |
> __GFP_NOWARN);
>  	if (unlikely(!buf->netmem))
>  		return DMA_MAPPING_ERROR;
> 
> @@ -117,6 +120,18 @@ static inline dma_addr_t libeth_rx_alloc(const
> struct libeth_fq_fp *fq, u32 i)
>  	       fq->pp->p.offset;
>  }
> 
> +/**
> + * libeth_rx_alloc - allocate a new Rx buffer from NAPI context
> + * @fq: fill queue to allocate for
> + * @i: index of the buffer within the queue
> + *
> + * Return: as libeth_rx_alloc_gfp().
> + */
> +static inline dma_addr_t libeth_rx_alloc(const struct libeth_fq_fp *fq,
> +u32 i) {
> +	return libeth_rx_alloc_gfp(fq, i, GFP_ATOMIC); }
> +
>  void libeth_rx_recycle_slow(netmem_ref netmem);
> 
>  /**
> --
> 2.56.0.212.g129ede20d9-goog

Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>

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

* RE: [PATCH iwl-next v2 2/2] idpf: use GFP_KERNEL for the initial Rx ring fill
  2026-10-19 21:06 ` [PATCH iwl-next v2 2/2] idpf: use GFP_KERNEL for the initial Rx ring fill Luigi Rizzo
@ 2026-10-21 10:43   ` Loktionov, Aleksandr
  0 siblings, 0 replies; 9+ messages in thread
From: Loktionov, Aleksandr @ 2026-10-21 10:43 UTC (permalink / raw)
  To: Luigi Rizzo, intel-wired-lan
  Cc: netdev, Nguyen, Anthony L, Kitszel, Przemyslaw, Lobakin,
	Aleksander, Andrew Lunn, David S . Miller, Eric Dumazet,
	Luigi Rizzo, Brian Vazquez, Hay, Joshua A, Zaremba, Larysa,
	Jakub Kicinski, Paolo Abeni, Simon Horman, linux-kernel



> -----Original Message-----
> From: Luigi Rizzo <lrizzo@google.com>
> Sent: Monday, October 19, 2026 11:06 PM
> To: intel-wired-lan@lists.osuosl.org
> Cc: netdev@vger.kernel.org; Nguyen, Anthony L
> <anthony.l.nguyen@intel.com>; Kitszel, Przemyslaw
> <przemyslaw.kitszel@intel.com>; Lobakin, Aleksander
> <aleksander.lobakin@intel.com>; Andrew Lunn <andrew+netdev@lunn.ch>;
> David S . Miller <davem@davemloft.net>; Eric Dumazet
> <edumazet@kernel.org>; Luigi Rizzo <rizzo.unipi@gmail.com>; Brian
> Vazquez <brianvv@google.com>; Hay, Joshua A <joshua.a.hay@intel.com>;
> Zaremba, Larysa <larysa.zaremba@intel.com>; Jakub Kicinski
> <kuba@kernel.org>; Paolo Abeni <pabeni@redhat.com>; Simon Horman
> <horms@kernel.org>; linux-kernel@vger.kernel.org; Luigi Rizzo
> <lrizzo@google.com>
> Subject: [PATCH iwl-next v2 2/2] idpf: use GFP_KERNEL for the initial Rx
> ring fill
> 
> When idpf fills its Rx rings at open or on queue reconfiguration, the
> allocation runs in process context, right after page_pool_create() and
> before the queues' NAPI is enabled. Allocating tens of thousands of
> buffers across all queues with GFP_ATOMIC is needlessly restrictive when
> the caller may sleep.
> 
> In splitq mode, idpf_rx_post_buf_desc() is only used for this initial
> fill, so switch its header and payload allocations to
> libeth_rx_alloc_gfp(..., GFP_KERNEL).
> 
> In singleq mode, add a gfp_t parameter to
> idpf_rx_singleq_buf_hw_alloc_all() and pass GFP_KERNEL from
> idpf_rx_buf_alloc_singleq() and GFP_ATOMIC from idpf_rx_singleq_clean().
> 
> Signed-off-by: Luigi Rizzo <lrizzo@google.com>
> ---
>  drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c | 7 ++++---
>  drivers/net/ethernet/intel/idpf/idpf_txrx.c         | 9 ++++++---
>  drivers/net/ethernet/intel/idpf/idpf_txrx.h         | 2 +-
>  3 files changed, 11 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
> b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
> index e3ddf18dcbf51..d623e4ab8511f 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
> +++ b/drivers/net/ethernet/intel/idpf/idpf_singleq_txrx.c
> @@ -885,11 +885,12 @@ static void idpf_rx_buf_hw_update(struct
> idpf_rx_queue *rxq, u32 val)
>   * idpf_rx_singleq_buf_hw_alloc_all - Replace used receive buffers
>   * @rx_q: queue for which the hw buffers are allocated
>   * @cleaned_count: number of buffers to replace
> + * @gfp: GFP_KERNEL for the initial fill, GFP_ATOMIC from NAPI
>   *
>   * Returns false if all allocations were successful, true if any fail
>   */
>  bool idpf_rx_singleq_buf_hw_alloc_all(struct idpf_rx_queue *rx_q,
> -				      u16 cleaned_count)
> +				      u16 cleaned_count, gfp_t gfp)
>  {
>  	struct virtchnl2_singleq_rx_buf_desc *desc;
>  	const struct libeth_fq_fp fq = {
> @@ -908,7 +909,7 @@ bool idpf_rx_singleq_buf_hw_alloc_all(struct
> idpf_rx_queue *rx_q,
>  	do {
>  		dma_addr_t addr;
> 
> -		addr = libeth_rx_alloc(&fq, nta);
> +		addr = libeth_rx_alloc_gfp(&fq, nta, gfp);
>  		if (addr == DMA_MAPPING_ERROR)
>  			break;
> 
> @@ -1095,7 +1096,7 @@ static int idpf_rx_singleq_clean(struct
> idpf_rx_queue *rx_q, int budget)
> 
>  	page_pool_nid_changed(rx_q->pp, numa_mem_id());
>  	if (cleaned_count)
> -		idpf_rx_singleq_buf_hw_alloc_all(rx_q, cleaned_count);
> +		idpf_rx_singleq_buf_hw_alloc_all(rx_q, cleaned_count,
> GFP_ATOMIC);
> 
>  	u64_stats_update_begin(&rx_q->stats_sync);
>  	u64_stats_add(&rx_q->q_stats.packets, rs.packets); diff --git
> a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
> b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
> index 4311ffa30bb18..b1127ab48ef3f 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
> +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
> @@ -600,6 +600,9 @@ static void idpf_post_buf_refill(struct
> idpf_sw_queue *refillq, u16 buf_id)
>   * @bufq: buffer queue to post to
>   * @buf_id: buffer id to post
>   *
> + * Only used for the initial fill, from process context, so it
> + allocates
> + * with GFP_KERNEL.
> + *
>   * Return: %false if buffer could not be allocated, %true otherwise.
>   */
>  static bool idpf_rx_post_buf_desc(struct idpf_buf_queue *bufq, u16
> buf_id) @@ -618,7 +621,7 @@ static bool idpf_rx_post_buf_desc(struct
> idpf_buf_queue *bufq, u16 buf_id)
>  		fq.fqes = bufq->hdr_buf;
>  		fq.truesize = bufq->hdr_truesize;
> 
> -		addr = libeth_rx_alloc(&fq, buf_id);
> +		addr = libeth_rx_alloc_gfp(&fq, buf_id, GFP_KERNEL);
>  		if (addr == DMA_MAPPING_ERROR)
>  			return false;
> 
> @@ -629,7 +632,7 @@ static bool idpf_rx_post_buf_desc(struct
> idpf_buf_queue *bufq, u16 buf_id)
>  	fq.fqes = bufq->buf;
>  	fq.truesize = bufq->truesize;
> 
> -	addr = libeth_rx_alloc(&fq, buf_id);
> +	addr = libeth_rx_alloc_gfp(&fq, buf_id, GFP_KERNEL);
>  	if (addr == DMA_MAPPING_ERROR)
>  		return false;
> 
> @@ -675,7 +678,7 @@ static bool idpf_rx_post_init_bufs(struct
> idpf_buf_queue *bufq,
>   */
>  static int idpf_rx_buf_alloc_singleq(struct idpf_rx_queue *rxq)  {
> -	if (idpf_rx_singleq_buf_hw_alloc_all(rxq, rxq->desc_count - 1))
> +	if (idpf_rx_singleq_buf_hw_alloc_all(rxq, rxq->desc_count - 1,
> +GFP_KERNEL))
>  		goto err;
> 
>  	return 0;
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.h
> b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
> index 93547597efd2a..e27438c78ec79 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.h
> +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.h
> @@ -1123,7 +1123,7 @@ netdev_tx_t idpf_tx_singleq_frame(struct sk_buff
> *skb,
>  				  struct idpf_tx_queue *tx_q);
>  netdev_tx_t idpf_tx_start(struct sk_buff *skb, struct net_device
> *netdev);  bool idpf_rx_singleq_buf_hw_alloc_all(struct idpf_rx_queue
> *rxq,
> -				      u16 cleaned_count);
> +				      u16 cleaned_count, gfp_t gfp);
>  bool idpf_rx_process_skb_fields(struct sk_buff *skb,
>  				const struct libeth_xdp_buff *xdp,
>  				struct libeth_rq_napi_stats *rs);
> --
> 2.56.0.212.g129ede20d9-goog

Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>

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

* Re: [PATCH iwl-next v2 0/2] libeth, idpf: use GFP_KERNEL for the initial Rx ring fill
  2026-10-19 21:06 [PATCH iwl-next v2 0/2] libeth, idpf: use GFP_KERNEL for the initial Rx ring fill Luigi Rizzo
  2026-10-19 21:06 ` [PATCH iwl-next v2 1/2] libeth: add libeth_rx_alloc_gfp() to specify allocation flags Luigi Rizzo
  2026-10-19 21:06 ` [PATCH iwl-next v2 2/2] idpf: use GFP_KERNEL for the initial Rx ring fill Luigi Rizzo
@ 2026-10-21 14:57 ` Alexander Lobakin
  2026-10-21 15:50   ` Luigi Rizzo
  2 siblings, 1 reply; 9+ messages in thread
From: Alexander Lobakin @ 2026-10-21 14:57 UTC (permalink / raw)
  To: Luigi Rizzo
  Cc: intel-wired-lan, netdev, Tony Nguyen, Przemek Kitszel,
	Andrew Lunn, David S . Miller, Eric Dumazet, Luigi Rizzo,
	Brian Vazquez, Joshua Hay, Larysa Zaremba, Jakub Kicinski,
	Paolo Abeni, Simon Horman, linux-kernel

From: Luigi Rizzo <lrizzo@google.com>
Date: Mon, 19 Oct 2026 21:06:02 +0000

> libeth_rx_alloc() always allocates with GFP_ATOMIC, including when a
> driver fills its Rx rings at open or on queue reconfiguration. That
> fill runs in process context, right after page_pool_create() and before
> the queues' NAPI is enabled, so it may sleep, and GFP_ATOMIC is
> needlessly restrictive there: it can neither reclaim nor compact, while
> the initial fill can allocate tens of thousands of buffers across all
> queues.
> 
> Patch 1 adds libeth_rx_alloc_gfp() taking a gfp_t parameter and turns
> libeth_rx_alloc() into its GFP_ATOMIC wrapper.
> Patch 2 switches idpf's initial Rx ring fill (both splitq and singleq)
> to GFP_KERNEL.

This is done for simplicity and performance reasons (although I've just
realized that this helper is fully inline, so it will inline your new
GFP argument as well).

But could anyone explain me why the initial fill is bad to do with
GFP_ATOMIC?

> 
> v2:
>   - split into two patches (libeth helper and idpf consumer)
> v1: https://lore.kernel.org/r/20261016151835.2500807-1-lrizzo@google.com/
> 
> Luigi Rizzo (2):
>   libeth: add libeth_rx_alloc_gfp() to specify allocation flags
>   idpf: use GFP_KERNEL for the initial Rx ring fill
> 
>  .../ethernet/intel/idpf/idpf_singleq_txrx.c   |  7 +++---
>  drivers/net/ethernet/intel/idpf/idpf_txrx.c   |  9 +++++---
>  drivers/net/ethernet/intel/idpf/idpf_txrx.h   |  2 +-
>  include/net/libeth/rx.h                       | 23 +++++++++++++++----
>  4 files changed, 30 insertions(+), 11 deletions(-)

Thanks,
Olek

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

* Re: [PATCH iwl-next v2 0/2] libeth, idpf: use GFP_KERNEL for the initial Rx ring fill
  2026-10-21 14:57 ` [PATCH iwl-next v2 0/2] libeth, " Alexander Lobakin
@ 2026-10-21 15:50   ` Luigi Rizzo
  0 siblings, 0 replies; 9+ messages in thread
From: Luigi Rizzo @ 2026-10-21 15:50 UTC (permalink / raw)
  To: Alexander Lobakin
  Cc: intel-wired-lan, netdev, Tony Nguyen, Przemek Kitszel,
	Andrew Lunn, David S . Miller, Eric Dumazet, Luigi Rizzo,
	Brian Vazquez, Joshua Hay, Larysa Zaremba, Jakub Kicinski,
	Paolo Abeni, Simon Horman, linux-kernel

On Wed, Oct 21, 2026 at 4:57 PM Alexander Lobakin
<aleksander.lobakin@intel.com> wrote:
>
> From: Luigi Rizzo <lrizzo@google.com>
> Date: Mon, 19 Oct 2026 21:06:02 +0000
>
> > libeth_rx_alloc() always allocates with GFP_ATOMIC, including when a
> > driver fills its Rx rings at open or on queue reconfiguration. That
> > fill runs in process context, right after page_pool_create() and before
> > the queues' NAPI is enabled, so it may sleep, and GFP_ATOMIC is
> > needlessly restrictive there: it can neither reclaim nor compact, while
> > the initial fill can allocate tens of thousands of buffers across all
> > queues.
> >
> > Patch 1 adds libeth_rx_alloc_gfp() taking a gfp_t parameter and turns
> > libeth_rx_alloc() into its GFP_ATOMIC wrapper.
> > Patch 2 switches idpf's initial Rx ring fill (both splitq and singleq)
> > to GFP_KERNEL.
>
> This is done for simplicity and performance reasons (although I've just
> realized that this helper is fully inline, so it will inline your new
> GFP argument as well).
>
> But could anyone explain me why the initial fill is bad to do with
> GFP_ATOMIC?

It might not be so bad now, but consider something like DMA-PMD
https://lore.kernel.org/all/20261003212241.3432303-1-lrizzo@google.com/
that allocates buffers from larger chunks to reduce IOTLB pressure
and iommu-related costs.

An innocent request for one buffer could cause the pagepool provider
to request a higher order page, which in turn may require some
compaction work and sleeping.

Using GFP_ATOMIC could cause unnecessary allocation failures
if pages are not readily available (and in O(100K) allocations
something could easily go wrong).

FWIW other drivers are not very consistent in their use of flags for
initial allocations, but I think this is more to simplify code reuse
(as you pointed out) than for a real requirement.

cheers
luigi

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

* Re: [PATCH iwl-next v2 1/2] libeth: add libeth_rx_alloc_gfp() to specify allocation flags
  2026-10-19 21:06 ` [PATCH iwl-next v2 1/2] libeth: add libeth_rx_alloc_gfp() to specify allocation flags Luigi Rizzo
  2026-10-21 10:42   ` Loktionov, Aleksandr
@ 2026-10-23 13:34   ` Alexander Lobakin
  2026-10-23 13:52     ` Luigi Rizzo
  1 sibling, 1 reply; 9+ messages in thread
From: Alexander Lobakin @ 2026-10-23 13:34 UTC (permalink / raw)
  To: Luigi Rizzo
  Cc: intel-wired-lan, netdev, Tony Nguyen, Przemek Kitszel,
	Andrew Lunn, David S . Miller, Eric Dumazet, Luigi Rizzo,
	Brian Vazquez, Joshua Hay, Larysa Zaremba, Jakub Kicinski,
	Paolo Abeni, Simon Horman, linux-kernel

From: Luigi Rizzo <lrizzo@google.com>
Date: Mon, 19 Oct 2026 21:06:03 +0000

> libeth_rx_alloc() calls page_pool_dev_alloc_netmem(), which always
> allocates with GFP_ATOMIC | __GFP_NOWARN. Drivers also use it to fill
> their Rx rings at open or on queue reconfiguration, which runs in
> process context before the queues' NAPI is enabled. There, the caller
> may sleep and GFP_ATOMIC is needlessly restrictive: it can neither
> reclaim nor compact, while the initial fill can allocate tens of
> thousands of buffers across all queues.
> 
> Add libeth_rx_alloc_gfp(), which takes a gfp_t parameter and passes
> gfp | __GFP_NOWARN to page_pool_alloc_netmem(), and make
> libeth_rx_alloc() its GFP_ATOMIC wrapper.

If you'd really like to go ahead (I'm still not really convinced, even
with "O(100k)" which is not that realistic), here's a couple style
wishes from me:

> 
> Signed-off-by: Luigi Rizzo <lrizzo@google.com>
> ---
>  include/net/libeth/rx.h | 23 +++++++++++++++++++----
>  1 file changed, 19 insertions(+), 4 deletions(-)
> 
> diff --git a/include/net/libeth/rx.h b/include/net/libeth/rx.h
> index 0e736846c5e8a..14a528ea8a075 100644
> --- a/include/net/libeth/rx.h
> +++ b/include/net/libeth/rx.h
> @@ -96,20 +96,23 @@ int libeth_rx_fq_create(struct libeth_fq *fq, void *napi_dev);
>  void libeth_rx_fq_destroy(struct libeth_fq *fq);
>  
>  /**
> - * libeth_rx_alloc - allocate a new Rx buffer
> + * libeth_rx_alloc_gfp - allocate a new Rx buffer
>   * @fq: fill queue to allocate for
>   * @i: index of the buffer within the queue
> + * @gfp: allocation flags: GFP_KERNEL where the caller may sleep (e.g. the
> + *	 initial fill of the ring), GFP_ATOMIC from NAPI
>   *
>   * Return: DMA address to be passed to HW for Rx on successful allocation,
>   * ```DMA_MAPPING_ERROR``` otherwise.
>   */
> -static inline dma_addr_t libeth_rx_alloc(const struct libeth_fq_fp *fq, u32 i)
> +static inline dma_addr_t libeth_rx_alloc_gfp(const struct libeth_fq_fp *fq,
> +					     u32 i, gfp_t gfp)

Mayb just __libeth_rx_alloc()?

>  {
>  	struct libeth_fqe *buf = &fq->fqes[i];
>  
>  	buf->truesize = fq->truesize;
> -	buf->netmem = page_pool_dev_alloc_netmem(fq->pp, &buf->offset,
> -						 &buf->truesize);
> +	buf->netmem = page_pool_alloc_netmem(fq->pp, &buf->offset,
> +					     &buf->truesize, gfp | __GFP_NOWARN);

And here I'd also place the gfp argument on a separate line.

>  	if (unlikely(!buf->netmem))
>  		return DMA_MAPPING_ERROR;
>  
> @@ -117,6 +120,18 @@ static inline dma_addr_t libeth_rx_alloc(const struct libeth_fq_fp *fq, u32 i)
>  	       fq->pp->p.offset;
>  }
>  
> +/**
> + * libeth_rx_alloc - allocate a new Rx buffer from NAPI context
> + * @fq: fill queue to allocate for
> + * @i: index of the buffer within the queue
> + *
> + * Return: as libeth_rx_alloc_gfp().
> + */
> +static inline dma_addr_t libeth_rx_alloc(const struct libeth_fq_fp *fq, u32 i)
> +{
> +	return libeth_rx_alloc_gfp(fq, i, GFP_ATOMIC);
> +}
> +
>  void libeth_rx_recycle_slow(netmem_ref netmem);
>  
>  /**

Thanks,
Olek

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

* Re: [PATCH iwl-next v2 1/2] libeth: add libeth_rx_alloc_gfp() to specify allocation flags
  2026-10-23 13:34   ` Alexander Lobakin
@ 2026-10-23 13:52     ` Luigi Rizzo
  0 siblings, 0 replies; 9+ messages in thread
From: Luigi Rizzo @ 2026-10-23 13:52 UTC (permalink / raw)
  To: Alexander Lobakin
  Cc: intel-wired-lan, netdev, Tony Nguyen, Przemek Kitszel,
	Andrew Lunn, David S . Miller, Eric Dumazet, Luigi Rizzo,
	Brian Vazquez, Joshua Hay, Larysa Zaremba, Jakub Kicinski,
	Paolo Abeni, Simon Horman, linux-kernel

On Fri, Oct 23, 2026 at 3:35 PM Alexander Lobakin
<aleksander.lobakin@intel.com> wrote:
>
> From: Luigi Rizzo <lrizzo@google.com>
> Date: Mon, 19 Oct 2026 21:06:03 +0000
>
> > libeth_rx_alloc() calls page_pool_dev_alloc_netmem(), which always
> > allocates with GFP_ATOMIC | __GFP_NOWARN. Drivers also use it to fill
> > their Rx rings at open or on queue reconfiguration, which runs in
> > process context before the queues' NAPI is enabled. There, the caller
> > may sleep and GFP_ATOMIC is needlessly restrictive: it can neither
> > reclaim nor compact, while the initial fill can allocate tens of
> > thousands of buffers across all queues.
> >
> > Add libeth_rx_alloc_gfp(), which takes a gfp_t parameter and passes
> > gfp | __GFP_NOWARN to page_pool_alloc_netmem(), and make
> > libeth_rx_alloc() its GFP_ATOMIC wrapper.
>
> If you'd really like to go ahead (I'm still not really convinced, even

To be clear, GFP_ATOMIC is not a problem right now, but it becomes
a problem if we try to back the buffers with 2MB pages as in DMA_PMD,
and those 2MB pages may not be available without sleeping.

> with "O(100k)" which is not that realistic),

On a large system, which is definitely the target for a 200G NIC that uses idpf,
we can easily get there and above.
The system I am testing now uses 4096 slots per queue, 32 queues,
meaning 128K entries at initialization. Under load, the pool has grown
to 197K entries.

Ok for the style changes, will resend an updated version

cheers
luigi

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

end of thread, other threads:[~2026-10-23 13:52 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-19 21:06 [PATCH iwl-next v2 0/2] libeth, idpf: use GFP_KERNEL for the initial Rx ring fill Luigi Rizzo
2026-10-19 21:06 ` [PATCH iwl-next v2 1/2] libeth: add libeth_rx_alloc_gfp() to specify allocation flags Luigi Rizzo
2026-10-21 10:42   ` Loktionov, Aleksandr
2026-10-23 13:34   ` Alexander Lobakin
2026-10-23 13:52     ` Luigi Rizzo
2026-10-19 21:06 ` [PATCH iwl-next v2 2/2] idpf: use GFP_KERNEL for the initial Rx ring fill Luigi Rizzo
2026-10-21 10:43   ` Loktionov, Aleksandr
2026-10-21 14:57 ` [PATCH iwl-next v2 0/2] libeth, " Alexander Lobakin
2026-10-21 15:50   ` Luigi Rizzo

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®