From: Jakub Kicinski <kuba@kernel.org>
To: pvalerio@redhat.com
Cc: Jakub Kicinski <kuba@kernel.org>,
davem@davemloft.net, andrew+netdev@lunn.ch, pabeni@redhat.com,
lorenzo@kernel.org, claudiu.beznea@tuxon.dev,
nicolas.ferre@microchip.com, theo.lebrun@bootlin.com,
netdev@vger.kernel.org, edumazet@google.com
Subject: Re: [net-next,3/8] cadence: macb: Add page pool support handle multi-descriptor frame rx
Date: Mon, 19 Jan 2026 11:36:22 -0800 [thread overview]
Message-ID: <20260119193622.1255610-1-kuba@kernel.org> (raw)
In-Reply-To: <20260115222531.313002-4-pvalerio@redhat.com>
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
For local reproduction steps see https://netdev-ai.bots.linux.dev/ai-local.html
---
cadence: macb: Add page pool support handle multi-descriptor frame rx
This patch converts the MACB/GEM driver from netdev_alloc_skb() to
page pool allocation and adds support for receiving frames that span
multiple DMA descriptors.
> diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
> index 19782f3f46f2..464bb7b2c04d 100644
[ ... ]
> @@ -1350,17 +1339,21 @@ static void discard_partial_frame(struct macb_queue *queue, unsigned int begin,
> static int gem_rx(struct macb_queue *queue, struct napi_struct *napi,
> int budget)
> {
> + struct skb_shared_info *shinfo;
> struct macb *bp = queue->bp;
> - unsigned int len;
> - unsigned int entry;
> - struct sk_buff *skb;
> - struct macb_dma_desc *desc;
> - int count = 0;
> + struct macb_dma_desc *desc;
> + unsigned int entry;
> + struct page *page;
> + void *buff_head;
> + int count = 0;
> + int data_len;
> + int nr_frags;
> +
>
> while (count < budget) {
> - u32 ctrl;
> + bool rxused, first_frame, last_frame;
> dma_addr_t addr;
> - bool rxused;
> + u32 ctrl;
[ ... ]
> - if (!(ctrl & MACB_BIT(RX_SOF) && ctrl & MACB_BIT(RX_EOF))) {
> - netdev_err(bp->dev,
> - "not whole frame pointed by descriptor\n");
> - bp->dev->stats.rx_dropped++;
> - queue->stats.rx_dropped++;
> - break;
> - }
> - skb = queue->rx_buff[entry];
> - if (unlikely(!skb)) {
> + buff_head = queue->rx_buff[entry];
> + if (unlikely(!buff_head)) {
> netdev_err(bp->dev,
> "inconsistent Rx descriptor chain\n");
> bp->dev->stats.rx_dropped++;
> queue->stats.rx_dropped++;
> break;
> }
> - /* now everything is ready for receiving packet */
> - queue->rx_buff[entry] = NULL;
> - len = ctrl & bp->rx_frm_len_mask;
>
> - netdev_vdbg(bp->dev, "gem_rx %u (len %u)\n", entry, len);
> + first_frame = ctrl & MACB_BIT(RX_SOF);
> + last_frame = ctrl & MACB_BIT(RX_EOF);
> +
> + if (last_frame) {
> + data_len = ctrl & bp->rx_frm_len_mask;
> + if (!first_frame)
> + data_len -= queue->skb->len;
^^^^^^^^^^^^^^
If a descriptor arrives with RX_EOF set but RX_SOF clear (e.g., hardware
error or link reset mid-frame), and queue->skb is NULL from a previously
completed frame, this will dereference NULL. The check for queue->skb
being NULL at the "else" branch below happens after this calculation.
Should the data_len calculation be moved after the first_frame handling,
or should there be a NULL check on queue->skb before accessing its len?
> + } else {
> + data_len = bp->rx_buffer_size;
> + }
> +
> + if (first_frame) {
[ ... ]
> + } else {
> + if (!queue->skb) {
> + netdev_err(bp->dev,
> + "Received non-starting frame while expecting it\n");
> + goto free_frags;
> + }
> +
> + shinfo = skb_shinfo(queue->skb);
> + page = virt_to_head_page(buff_head);
> + nr_frags = shinfo->nr_frags;
> +
> + if (nr_frags >= ARRAY_SIZE(shinfo->frags))
> + goto free_frags;
> +
> + skb_add_rx_frag(queue->skb, nr_frags, page,
> + buff_head - page_address(page) + bp->rx_headroom,
> + data_len, gem_total_rx_buffer_size(bp));
> + }
[ ... ]
> + free_frags:
> + if (queue->skb) {
> + dev_kfree_skb(queue->skb);
> + queue->skb = NULL;
> + } else {
> + page_pool_put_full_page(queue->page_pool,
> + virt_to_head_page(buff_head),
> + false);
> + }
When the fragment overflow check (nr_frags >= ARRAY_SIZE) triggers,
queue->skb is non-NULL so dev_kfree_skb() runs. However, the current
buff_head (the fragment that could not be added) is not returned to
the page pool since the else branch is not taken. Does this leak the
page for that buffer?
> +
> + bp->dev->stats.rx_dropped++;
> + queue->stats.rx_dropped++;
> + queue->rx_buff[entry] = NULL;
> }
[ ... ]
> +static int gem_create_page_pool(struct macb_queue *queue)
> +{
> + struct page_pool_params pp_params = {
> + .order = 0,
> + .flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV,
> + .pool_size = queue->bp->rx_ring_size,
> + .nid = NUMA_NO_NODE,
> + .dma_dir = DMA_FROM_DEVICE,
> + .dev = &queue->bp->pdev->dev,
> + .napi = &queue->napi_rx,
> + .max_len = PAGE_SIZE,
> + };
> + struct page_pool *pool;
> + int err = 0;
> +
> + pool = page_pool_create(&pp_params);
> + if (IS_ERR(pool)) {
> + netdev_err(queue->bp->dev, "cannot create rx page pool\n");
> + err = PTR_ERR(pool);
> + pool = NULL;
> + }
> +
> + queue->page_pool = pool;
> +
> + return err;
> +}
[ ... ]
> @@ -2607,12 +2698,24 @@ static int gem_init_rings(struct macb *bp, bool fail_early)
> queue->rx_tail = 0;
> queue->rx_prepared_head = 0;
>
> + /* This is a hard failure, so the best we can do is try the
> + * next queue in case of HRESP error.
> + */
> + err = gem_create_page_pool(queue);
^^^^^^^^^^^^^^^^^^^^^^^^
When macb_hresp_error_task() calls gem_init_rings(bp, false), this
creates a new page pool without destroying the existing one. The old
queue->page_pool pointer is overwritten, leaking the previous page pool.
Additionally, the rx_buff[] entries still reference pages from the old
pool. When those buffers are later processed in gem_rx() and returned
via page_pool_put_full_page(), they would be returned to the new pool
instead of their original pool. Should the old page pool be destroyed
and rx buffers cleaned up before creating the new pool in the HRESP
recovery path?
> + if (err) {
> + last_err = err;
> + if (fail_early)
> + break;
> +
> + continue;
> + }
[ ... ]
next prev parent reply other threads:[~2026-01-19 19:36 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-15 22:25 [PATCH net-next 0/8] net: macb: Add XDP support and page pool integration Paolo Valerio
2026-01-15 22:25 ` [PATCH net-next 1/8] net: macb: move Rx buffers alloc from link up to open Paolo Valerio
2026-01-15 22:25 ` [PATCH net-next 2/8] net: macb: rename rx_skbuff into rx_buff Paolo Valerio
2026-01-15 22:25 ` [PATCH net-next 3/8] cadence: macb: Add page pool support handle multi-descriptor frame rx Paolo Valerio
2026-01-16 17:16 ` Andrew Lunn
2026-01-19 18:58 ` Paolo Valerio
2026-01-22 22:24 ` Paolo Valerio
2026-01-22 23:04 ` Andrew Lunn
2026-01-25 19:02 ` Paolo Valerio
2026-01-26 14:29 ` Andrew Lunn
2026-01-26 18:45 ` Théo Lebrun
2026-01-26 23:51 ` Paolo Valerio
2026-01-27 15:48 ` Théo Lebrun
2026-01-26 23:34 ` Paolo Valerio
2026-01-19 19:36 ` Jakub Kicinski [this message]
2026-01-22 14:39 ` [net-next,3/8] " Théo Lebrun
2026-01-22 15:16 ` Jakub Kicinski
2026-01-26 14:55 ` [PATCH net-next 3/8] " Théo Lebrun
2026-02-20 15:45 ` Théo Lebrun
2026-01-15 22:25 ` [PATCH net-next 4/8] cadence: macb: use the current queue number for stats Paolo Valerio
2026-01-15 22:25 ` [PATCH net-next 5/8] cadence: macb: add XDP support for gem Paolo Valerio
2026-01-19 19:36 ` [net-next,5/8] " Jakub Kicinski
2026-01-15 22:25 ` [PATCH net-next 6/8] cadence: macb: make macb_tx_skb generic Paolo Valerio
2026-01-15 22:25 ` [PATCH net-next 7/8] cadence: macb: make tx path skb agnostic Paolo Valerio
2026-01-15 22:25 ` [PATCH net-next 8/8] cadence: macb: introduce xmit support Paolo Valerio
2026-01-19 19:36 ` [net-next,8/8] " Jakub Kicinski
2026-02-02 16:31 ` [PATCH net-next 0/8] net: macb: Add XDP support and page pool integration Théo Lebrun
2026-02-13 16:57 ` [PATCH 1/6] net: macb: rename release_buff() -> macb_tx_release_buff() Théo Lebrun
2026-02-13 16:57 ` [PATCH 2/6] net: macb: drop two labels in gem_rx() Théo Lebrun
2026-02-13 16:57 ` [PATCH 3/6] net: macb: always use DMA_BIDIRECTIONAL on page pool buffers Théo Lebrun
2026-02-13 16:57 ` [PATCH 4/6] net: macb: account for stats in Rx XDP codepaths Théo Lebrun
2026-02-13 16:57 ` [PATCH 5/6] net: macb: improve Rx refill error message Théo Lebrun
2026-02-13 16:57 ` [PATCH 6/6] net: macb: rework macb_tx_complete() processing loop Théo Lebrun
2026-02-13 16:57 ` [PATCH net-next 0/8] net: macb: Add XDP support and page pool integration Théo Lebrun
2026-02-13 17:02 ` Théo Lebrun
2026-02-14 15:37 ` Paolo Valerio
2026-02-16 9:17 ` Théo Lebrun
2026-02-19 18:05 ` Paolo Valerio
2026-02-20 15:58 ` Théo Lebrun
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=20260119193622.1255610-1-kuba@kernel.org \
--to=kuba@kernel.org \
--cc=andrew+netdev@lunn.ch \
--cc=claudiu.beznea@tuxon.dev \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=lorenzo@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=nicolas.ferre@microchip.com \
--cc=pabeni@redhat.com \
--cc=pvalerio@redhat.com \
--cc=theo.lebrun@bootlin.com \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox