From nobody Tue Apr 7 12:53:41 2026 Received: from mail.tipi-net.de (mail.tipi-net.de [194.13.80.246]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 56159280318; Fri, 13 Mar 2026 09:21:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=194.13.80.246 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773393689; cv=none; b=GRrplwa5W2UhDnGxdEG09G9FFeOtSCtEF/Z+H+E7A6ay4mOSLsgOTZyKM69D7jPOsv4UPAXsF2EGeUtChxZJEBCMTtnt2CxLWKUTJz4iM0UEXPImbOPQMq2ld60VQM0Hn5uIxiUE0Hx2CovMr2UduWxwGYOG6MG1zvp7r1RZRXc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773393689; c=relaxed/simple; bh=XDJLQj9Zeq86KihZLsZtb9Fzn5W8iq7BnFgsbZAnagY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=RUM5mdufYQ3Ek81Ba/5swlbTGcMWzNrxfz8aWvSWVDRMPGxMGYCBclrUb7BiBw2R/e8+fqjHBEXX8dnrxjzvUDnU81zQUypgfkzfN9dDO6282HnyG4MaH0ykauwkOv8QAjLARnsRnQbidYS7ixTjfoCHdZSM7ZDHox9oc5kbbDw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=tipi-net.de; spf=pass smtp.mailfrom=tipi-net.de; dkim=pass (2048-bit key) header.d=tipi-net.de header.i=@tipi-net.de header.b=UhuCQdwL; arc=none smtp.client-ip=194.13.80.246 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=tipi-net.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tipi-net.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tipi-net.de header.i=@tipi-net.de header.b="UhuCQdwL" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id B52ABA56F9; Fri, 13 Mar 2026 10:21:18 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tipi-net.de; s=dkim; t=1773393679; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=TytaCUHwMv4JAgncx6FkvO7K51C15jH1S7rItCW0yaU=; b=UhuCQdwL7iUT5uQ3LR4UDcB27ZiLzyt+filZmJNC9xHHz+9ZIqEtCrFa2K9uEWEqu7hrj3 5FSKE3DP6QS3sG9K9S3pkOgmQMo5UwyUHd03wgyuLYaipvrL9UCxQHQ9H84ULvEm6Q6zM4 z4ZIrDrBfqzH994iLGP2/4JG7dVXgEI6vKbGZsWVkIsf55sED8iiAiqZSkkH4O8UywzGVo BSI+1lm04CEOhWFoPRZgNx5kYSp4vb0nx9Cz1DH75T11o0UpkH3griNVYu3Mn/CU/cWN7/ LbeS7P+nCm+hTOxgojT8XOdMG6n4vFY2jE8b+p/2Zv/VO3VNyENHVMIbtOmnRA== From: Nicolai Buchwitz To: Andrew Lunn , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Doug Berger , Florian Fainelli Cc: Broadcom internal kernel review list , Vikas Gupta , Bhargava Marreddy , Rajashekar Hudumula , Eric Biggers , Heiner Kallweit , =?UTF-8?q?Markus=20Bl=C3=B6chl?= , Arnd Bergmann , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Nicolai Buchwitz Subject: [PATCH net-next 1/6] net: bcmgenet: convert RX path to page_pool Date: Fri, 13 Mar 2026 10:20:56 +0100 Message-ID: <20260313092101.1344954-2-nb@tipi-net.de> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260313092101.1344954-1-nb@tipi-net.de> References: <20260313092101.1344954-1-nb@tipi-net.de> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Last-TLS-Session-Version: TLSv1.3 Content-Type: text/plain; charset="utf-8" Replace the per-packet __netdev_alloc_skb() + dma_map_single() in the RX path with page_pool, which provides efficient page recycling and DMA mapping management. This is a prerequisite for XDP support (which requires stable page-backed buffers rather than SKB linear data). Key changes: - Create a page_pool per RX ring (PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV) - bcmgenet_rx_refill() allocates pages via page_pool_alloc_pages() - bcmgenet_desc_rx() builds SKBs from pages via napi_build_skb() with skb_mark_for_recycle() for automatic page_pool return - Buffer layout reserves XDP_PACKET_HEADROOM (256 bytes) before the HW RSB (64 bytes) + alignment pad (2 bytes) for future XDP headroom Signed-off-by: Nicolai Buchwitz --- drivers/net/ethernet/broadcom/Kconfig | 1 + .../net/ethernet/broadcom/genet/bcmgenet.c | 210 ++++++++++++------ .../net/ethernet/broadcom/genet/bcmgenet.h | 4 + 3 files changed, 143 insertions(+), 72 deletions(-) diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/b= roadcom/Kconfig index cd7dddeb91dd..e3b9a5272406 100644 --- a/drivers/net/ethernet/broadcom/Kconfig +++ b/drivers/net/ethernet/broadcom/Kconfig @@ -78,6 +78,7 @@ config BCMGENET select BCM7XXX_PHY select MDIO_BCM_UNIMAC select DIMLIB + select PAGE_POOL select BROADCOM_PHY if ARCH_BCM2835 help This driver supports the built-in Ethernet MACs found in the diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/e= thernet/broadcom/genet/bcmgenet.c index 482a31e7b72b..bf3f881108f8 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -52,6 +52,14 @@ #define RX_BUF_LENGTH 2048 #define SKB_ALIGNMENT 32 =20 +/* Page pool RX buffer layout: + * XDP_PACKET_HEADROOM | RSB(64) + pad(2) | frame data | skb_shared_info + * The HW writes the 64B RSB + 2B alignment padding before the frame. + */ +#define GENET_XDP_HEADROOM XDP_PACKET_HEADROOM +#define GENET_RSB_PAD (sizeof(struct status_64) + 2) +#define GENET_RX_HEADROOM (GENET_XDP_HEADROOM + GENET_RSB_PAD) + /* Tx/Rx DMA register offset, skip 256 descriptors */ #define WORDS_PER_BD(p) (p->hw_params->words_per_bd) #define DMA_DESC_SIZE (WORDS_PER_BD(priv) * sizeof(u32)) @@ -1895,21 +1903,13 @@ static struct sk_buff *bcmgenet_free_tx_cb(struct d= evice *dev, } =20 /* Simple helper to free a receive control block's resources */ -static struct sk_buff *bcmgenet_free_rx_cb(struct device *dev, - struct enet_cb *cb) +static void bcmgenet_free_rx_cb(struct enet_cb *cb, + struct page_pool *pool) { - struct sk_buff *skb; - - skb =3D cb->skb; - cb->skb =3D NULL; - - if (dma_unmap_addr(cb, dma_addr)) { - dma_unmap_single(dev, dma_unmap_addr(cb, dma_addr), - dma_unmap_len(cb, dma_len), DMA_FROM_DEVICE); - dma_unmap_addr_set(cb, dma_addr, 0); + if (cb->rx_page) { + page_pool_put_full_page(pool, cb->rx_page, false); + cb->rx_page =3D NULL; } - - return skb; } =20 /* Unlocked version of the reclaim routine */ @@ -2248,46 +2248,30 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *sk= b, struct net_device *dev) goto out; } =20 -static struct sk_buff *bcmgenet_rx_refill(struct bcmgenet_priv *priv, - struct enet_cb *cb) +static int bcmgenet_rx_refill(struct bcmgenet_rx_ring *ring, + struct enet_cb *cb) { - struct device *kdev =3D &priv->pdev->dev; - struct sk_buff *skb; - struct sk_buff *rx_skb; + struct bcmgenet_priv *priv =3D ring->priv; dma_addr_t mapping; + struct page *page; =20 - /* Allocate a new Rx skb */ - skb =3D __netdev_alloc_skb(priv->dev, priv->rx_buf_len + SKB_ALIGNMENT, - GFP_ATOMIC | __GFP_NOWARN); - if (!skb) { + page =3D page_pool_alloc_pages(ring->page_pool, + GFP_ATOMIC | __GFP_NOWARN); + if (!page) { priv->mib.alloc_rx_buff_failed++; netif_err(priv, rx_err, priv->dev, - "%s: Rx skb allocation failed\n", __func__); - return NULL; - } - - /* DMA-map the new Rx skb */ - mapping =3D dma_map_single(kdev, skb->data, priv->rx_buf_len, - DMA_FROM_DEVICE); - if (dma_mapping_error(kdev, mapping)) { - priv->mib.rx_dma_failed++; - dev_kfree_skb_any(skb); - netif_err(priv, rx_err, priv->dev, - "%s: Rx skb DMA mapping failed\n", __func__); - return NULL; + "%s: Rx page allocation failed\n", __func__); + return -ENOMEM; } =20 - /* Grab the current Rx skb from the ring and DMA-unmap it */ - rx_skb =3D bcmgenet_free_rx_cb(kdev, cb); + /* page_pool handles DMA mapping via PP_FLAG_DMA_MAP */ + mapping =3D page_pool_get_dma_addr(page) + GENET_XDP_HEADROOM; =20 - /* Put the new Rx skb on the ring */ - cb->skb =3D skb; - dma_unmap_addr_set(cb, dma_addr, mapping); - dma_unmap_len_set(cb, dma_len, priv->rx_buf_len); + cb->rx_page =3D page; + cb->rx_page_offset =3D GENET_XDP_HEADROOM; dmadesc_set_addr(priv, cb->bd_addr, mapping); =20 - /* Return the current Rx skb to caller */ - return rx_skb; + return 0; } =20 /* bcmgenet_desc_rx - descriptor based rx process. @@ -2339,23 +2323,32 @@ static unsigned int bcmgenet_desc_rx(struct bcmgene= t_rx_ring *ring, while ((rxpktprocessed < rxpkttoprocess) && (rxpktprocessed < budget)) { struct status_64 *status; + struct page *rx_page; + unsigned int rx_off; __be16 rx_csum; + void *hard_start; =20 cb =3D &priv->rx_cbs[ring->read_ptr]; - skb =3D bcmgenet_rx_refill(priv, cb); =20 - if (unlikely(!skb)) { + /* Save the received page before refilling */ + rx_page =3D cb->rx_page; + rx_off =3D cb->rx_page_offset; + + if (bcmgenet_rx_refill(ring, cb)) { BCMGENET_STATS64_INC(stats, dropped); goto next; } =20 - status =3D (struct status_64 *)skb->data; + page_pool_dma_sync_for_cpu(ring->page_pool, rx_page, 0, + RX_BUF_LENGTH); + + hard_start =3D page_address(rx_page) + rx_off; + status =3D (struct status_64 *)hard_start; dma_length_status =3D status->length_status; if (dev->features & NETIF_F_RXCSUM) { rx_csum =3D (__force __be16)(status->rx_csum & 0xffff); if (rx_csum) { - skb->csum =3D (__force __wsum)ntohs(rx_csum); - skb->ip_summed =3D CHECKSUM_COMPLETE; + /* defer csum setup to after skb is built */ } } =20 @@ -2373,7 +2366,8 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_= rx_ring *ring, if (unlikely(len > RX_BUF_LENGTH)) { netif_err(priv, rx_status, dev, "oversized packet\n"); BCMGENET_STATS64_INC(stats, length_errors); - dev_kfree_skb_any(skb); + page_pool_put_full_page(ring->page_pool, rx_page, + true); goto next; } =20 @@ -2381,7 +2375,8 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_= rx_ring *ring, netif_err(priv, rx_status, dev, "dropping fragmented packet!\n"); BCMGENET_STATS64_INC(stats, fragmented_errors); - dev_kfree_skb_any(skb); + page_pool_put_full_page(ring->page_pool, rx_page, + true); goto next; } =20 @@ -2409,24 +2404,48 @@ static unsigned int bcmgenet_desc_rx(struct bcmgene= t_rx_ring *ring, DMA_RX_RXER)) =3D=3D DMA_RX_RXER) u64_stats_inc(&stats->errors); u64_stats_update_end(&stats->syncp); - dev_kfree_skb_any(skb); + page_pool_put_full_page(ring->page_pool, rx_page, + true); goto next; } /* error packet */ =20 - skb_put(skb, len); + /* Build SKB from the page - data starts at hard_start, + * frame begins after RSB(64) + pad(2) =3D 66 bytes. + */ + skb =3D napi_build_skb(hard_start, PAGE_SIZE - GENET_XDP_HEADROOM); + if (unlikely(!skb)) { + BCMGENET_STATS64_INC(stats, dropped); + page_pool_put_full_page(ring->page_pool, rx_page, + true); + goto next; + } + + skb_mark_for_recycle(skb); =20 - /* remove RSB and hardware 2bytes added for IP alignment */ - skb_pull(skb, 66); - len -=3D 66; + /* Reserve the RSB + pad, then set the data length */ + skb_reserve(skb, GENET_RSB_PAD); + __skb_put(skb, len - GENET_RSB_PAD); =20 if (priv->crc_fwd_en) { - skb_trim(skb, len - ETH_FCS_LEN); + skb_trim(skb, skb->len - ETH_FCS_LEN); len -=3D ETH_FCS_LEN; } =20 + /* Set up checksum offload */ + if (dev->features & NETIF_F_RXCSUM) { + rx_csum =3D (__force __be16)(status->rx_csum & 0xffff); + if (rx_csum) { + skb->csum =3D (__force __wsum)ntohs(rx_csum); + skb->ip_summed =3D CHECKSUM_COMPLETE; + } + } + + len =3D skb->len; bytes_processed +=3D len; =20 - /*Finish setting up the received SKB and send it to the kernel*/ + /* Finish setting up the received SKB and send it to the + * kernel. + */ skb->protocol =3D eth_type_trans(skb, priv->dev); =20 u64_stats_update_begin(&stats->syncp); @@ -2495,12 +2514,11 @@ static void bcmgenet_dim_work(struct work_struct *w= ork) dim->state =3D DIM_START_MEASURE; } =20 -/* Assign skb to RX DMA descriptor. */ +/* Assign page_pool pages to RX DMA descriptors. */ static int bcmgenet_alloc_rx_buffers(struct bcmgenet_priv *priv, struct bcmgenet_rx_ring *ring) { struct enet_cb *cb; - struct sk_buff *skb; int i; =20 netif_dbg(priv, hw, priv->dev, "%s\n", __func__); @@ -2508,10 +2526,7 @@ static int bcmgenet_alloc_rx_buffers(struct bcmgenet= _priv *priv, /* loop here for each buffer needing assign */ for (i =3D 0; i < ring->size; i++) { cb =3D ring->cbs + i; - skb =3D bcmgenet_rx_refill(priv, cb); - if (skb) - dev_consume_skb_any(skb); - if (!cb->skb) + if (bcmgenet_rx_refill(ring, cb)) return -ENOMEM; } =20 @@ -2520,16 +2535,19 @@ static int bcmgenet_alloc_rx_buffers(struct bcmgene= t_priv *priv, =20 static void bcmgenet_free_rx_buffers(struct bcmgenet_priv *priv) { - struct sk_buff *skb; + struct bcmgenet_rx_ring *ring; struct enet_cb *cb; - int i; - - for (i =3D 0; i < priv->num_rx_bds; i++) { - cb =3D &priv->rx_cbs[i]; + int q, i; =20 - skb =3D bcmgenet_free_rx_cb(&priv->pdev->dev, cb); - if (skb) - dev_consume_skb_any(skb); + for (q =3D 0; q <=3D priv->hw_params->rx_queues; q++) { + ring =3D &priv->rx_rings[q =3D=3D priv->hw_params->rx_queues ? + DESC_INDEX : q]; + if (!ring->page_pool) + continue; + for (i =3D 0; i < ring->size; i++) { + cb =3D ring->cbs + i; + bcmgenet_free_rx_cb(cb, ring->page_pool); + } } } =20 @@ -2747,6 +2765,31 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_pr= iv *priv, netif_napi_add_tx(priv->dev, &ring->napi, bcmgenet_tx_poll); } =20 +static int bcmgenet_rx_ring_create_pool(struct bcmgenet_priv *priv, + struct bcmgenet_rx_ring *ring) +{ + struct page_pool_params pp_params =3D { + .order =3D 0, + .flags =3D PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV, + .pool_size =3D ring->size, + .nid =3D NUMA_NO_NODE, + .dev =3D &priv->pdev->dev, + .dma_dir =3D DMA_FROM_DEVICE, + .offset =3D GENET_XDP_HEADROOM, + .max_len =3D RX_BUF_LENGTH, + }; + + ring->page_pool =3D page_pool_create(&pp_params); + if (IS_ERR(ring->page_pool)) { + int err =3D PTR_ERR(ring->page_pool); + + ring->page_pool =3D NULL; + return err; + } + + return 0; +} + /* Initialize a RDMA ring */ static int bcmgenet_init_rx_ring(struct bcmgenet_priv *priv, unsigned int index, unsigned int size, @@ -2765,10 +2808,17 @@ static int bcmgenet_init_rx_ring(struct bcmgenet_pr= iv *priv, ring->cb_ptr =3D start_ptr; ring->end_ptr =3D end_ptr - 1; =20 - ret =3D bcmgenet_alloc_rx_buffers(priv, ring); + ret =3D bcmgenet_rx_ring_create_pool(priv, ring); if (ret) return ret; =20 + ret =3D bcmgenet_alloc_rx_buffers(priv, ring); + if (ret) { + page_pool_destroy(ring->page_pool); + ring->page_pool =3D NULL; + return ret; + } + bcmgenet_init_dim(ring, bcmgenet_dim_work); bcmgenet_init_rx_coalesce(ring); =20 @@ -2961,6 +3011,20 @@ static void bcmgenet_fini_rx_napi(struct bcmgenet_pr= iv *priv) } } =20 +static void bcmgenet_destroy_rx_page_pools(struct bcmgenet_priv *priv) +{ + struct bcmgenet_rx_ring *ring; + unsigned int i; + + for (i =3D 0; i <=3D priv->hw_params->rx_queues; ++i) { + ring =3D &priv->rx_rings[i]; + if (ring->page_pool) { + page_pool_destroy(ring->page_pool); + ring->page_pool =3D NULL; + } + } +} + /* Initialize Rx queues * * Queues 0-15 are priority queues. Hardware Filtering Block (HFB) can be @@ -3032,6 +3096,7 @@ static void bcmgenet_fini_dma(struct bcmgenet_priv *p= riv) } =20 bcmgenet_free_rx_buffers(priv); + bcmgenet_destroy_rx_page_pools(priv); kfree(priv->rx_cbs); kfree(priv->tx_cbs); } @@ -3108,6 +3173,7 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *pr= iv, bool flush_rx) if (ret) { netdev_err(priv->dev, "failed to initialize Rx queues\n"); bcmgenet_free_rx_buffers(priv); + bcmgenet_destroy_rx_page_pools(priv); kfree(priv->rx_cbs); kfree(priv->tx_cbs); return ret; diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/e= thernet/broadcom/genet/bcmgenet.h index 9e4110c7fdf6..11a0ec563a89 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -15,6 +15,7 @@ #include #include #include +#include =20 #include "../unimac.h" =20 @@ -469,6 +470,8 @@ struct bcmgenet_rx_stats64 { =20 struct enet_cb { struct sk_buff *skb; + struct page *rx_page; + unsigned int rx_page_offset; void __iomem *bd_addr; DEFINE_DMA_UNMAP_ADDR(dma_addr); DEFINE_DMA_UNMAP_LEN(dma_len); @@ -575,6 +578,7 @@ struct bcmgenet_rx_ring { struct bcmgenet_net_dim dim; u32 rx_max_coalesced_frames; u32 rx_coalesce_usecs; + struct page_pool *page_pool; struct bcmgenet_priv *priv; }; =20 --=20 2.51.0 From nobody Tue Apr 7 12:53:41 2026 Received: from mail.tipi-net.de (mail.tipi-net.de [194.13.80.246]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 520212DF144; Fri, 13 Mar 2026 09:21:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=194.13.80.246 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773393689; cv=none; b=CDpsIUbUDlFZO5oobeljX2tOuQHR4v3ZlxhHa8k+IWjeN9eOUoz6lf4szSxRYtL0QG1pdwwngoy2THUsE1V8HwSMG1iRdMCXW6dYNFroLwHXz/moeB4GYmhq7tAIHlhgmvDn9WUavL0mVthwARgJDttAbZo0dHjoLYoO6Y+lKB0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773393689; c=relaxed/simple; bh=X8oVtkQ1LRgNEBrAzXB9fC6F1+wRx4/wLXbM9tVgjuU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tZ52dSJGJTnXa5NI23q/e1WdBNKAEAyXsSp/WTLNNMBydCQ5OhBQti1RgMRxPRlLLnGXPTF+7B11H4hEpExwpFF+sIRw87XQceiJkE3i85eSt8MIsQoTMh3ouQneAHFEq/3Qy9P8BiYCzjkT3TXG0x9yil/6P6nplu6RYS4vFcM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=tipi-net.de; spf=pass smtp.mailfrom=tipi-net.de; dkim=pass (2048-bit key) header.d=tipi-net.de header.i=@tipi-net.de header.b=08bagvCg; arc=none smtp.client-ip=194.13.80.246 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=tipi-net.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tipi-net.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tipi-net.de header.i=@tipi-net.de header.b="08bagvCg" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id D6ACAA5701; Fri, 13 Mar 2026 10:21:19 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tipi-net.de; s=dkim; t=1773393680; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=/58tjQlP+ie0EoTynhZFfffkn/JQewlQiGY/O7UjX+Q=; b=08bagvCgHLziTk/6KtnWH0El+5BWo5r+jHs1oi4apTrFlGwRYl6j2h3Kb57H/OSZLxVy1q 2F3D+9mLFC4ltEVy1wAB5pQgmtfGJc0He4KrJInSNHll9ZV2QWmwq/qTQTP4qPbhDJDV5B 6F4O1CwRWWtzU08nCf7IwzEAEAsU4tfvZE4jYOHU+mYxt9nEe+UG+Zo2bjQq2QGemDl/V0 uSBhxoZDZME2u1x0oPdkZTaa67tdExqLuXMQqOXTxuieQPHR2SU8+ZT2H0qUChQjOOiWQv zcs+pCVrMTCj0JAvdjBOi1ZQaJtrDsPuUt9DF1YVIbCR5K9MHWelvrAlaAI3zg== From: Nicolai Buchwitz To: Andrew Lunn , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Doug Berger , Florian Fainelli Cc: Broadcom internal kernel review list , Vikas Gupta , Bhargava Marreddy , Rajashekar Hudumula , Eric Biggers , Heiner Kallweit , =?UTF-8?q?Markus=20Bl=C3=B6chl?= , Arnd Bergmann , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Nicolai Buchwitz Subject: [PATCH net-next 2/6] net: bcmgenet: register xdp_rxq_info for each RX ring Date: Fri, 13 Mar 2026 10:20:57 +0100 Message-ID: <20260313092101.1344954-3-nb@tipi-net.de> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260313092101.1344954-1-nb@tipi-net.de> References: <20260313092101.1344954-1-nb@tipi-net.de> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Last-TLS-Session-Version: TLSv1.3 Content-Type: text/plain; charset="utf-8" Register an xdp_rxq_info per RX ring and associate it with the ring's page_pool via MEM_TYPE_PAGE_POOL. This is required infrastructure for XDP program execution: the XDP framework needs to know the memory model backing each RX queue for correct page lifecycle management. No functional change - XDP programs are not yet attached or executed. Signed-off-by: Nicolai Buchwitz --- .../net/ethernet/broadcom/genet/bcmgenet.c | 22 +++++++++++++++++-- .../net/ethernet/broadcom/genet/bcmgenet.h | 2 ++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/e= thernet/broadcom/genet/bcmgenet.c index bf3f881108f8..dd70e5af2b1e 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -2778,16 +2778,32 @@ static int bcmgenet_rx_ring_create_pool(struct bcmg= enet_priv *priv, .offset =3D GENET_XDP_HEADROOM, .max_len =3D RX_BUF_LENGTH, }; + int err; =20 ring->page_pool =3D page_pool_create(&pp_params); if (IS_ERR(ring->page_pool)) { - int err =3D PTR_ERR(ring->page_pool); - + err =3D PTR_ERR(ring->page_pool); ring->page_pool =3D NULL; return err; } =20 + err =3D xdp_rxq_info_reg(&ring->xdp_rxq, priv->dev, ring->index, 0); + if (err) + goto err_free_pp; + + err =3D xdp_rxq_info_reg_mem_model(&ring->xdp_rxq, MEM_TYPE_PAGE_POOL, + ring->page_pool); + if (err) + goto err_unreg_rxq; + return 0; + +err_unreg_rxq: + xdp_rxq_info_unreg(&ring->xdp_rxq); +err_free_pp: + page_pool_destroy(ring->page_pool); + ring->page_pool =3D NULL; + return err; } =20 /* Initialize a RDMA ring */ @@ -2814,6 +2830,7 @@ static int bcmgenet_init_rx_ring(struct bcmgenet_priv= *priv, =20 ret =3D bcmgenet_alloc_rx_buffers(priv, ring); if (ret) { + xdp_rxq_info_unreg(&ring->xdp_rxq); page_pool_destroy(ring->page_pool); ring->page_pool =3D NULL; return ret; @@ -3019,6 +3036,7 @@ static void bcmgenet_destroy_rx_page_pools(struct bcm= genet_priv *priv) for (i =3D 0; i <=3D priv->hw_params->rx_queues; ++i) { ring =3D &priv->rx_rings[i]; if (ring->page_pool) { + xdp_rxq_info_unreg(&ring->xdp_rxq); page_pool_destroy(ring->page_pool); ring->page_pool =3D NULL; } diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/e= thernet/broadcom/genet/bcmgenet.h index 11a0ec563a89..82a6d29f481d 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -16,6 +16,7 @@ #include #include #include +#include =20 #include "../unimac.h" =20 @@ -579,6 +580,7 @@ struct bcmgenet_rx_ring { u32 rx_max_coalesced_frames; u32 rx_coalesce_usecs; struct page_pool *page_pool; + struct xdp_rxq_info xdp_rxq; struct bcmgenet_priv *priv; }; =20 --=20 2.51.0 From nobody Tue Apr 7 12:53:41 2026 Received: from mail.tipi-net.de (mail.tipi-net.de [194.13.80.246]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 52094305E3B; Fri, 13 Mar 2026 09:21:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=194.13.80.246 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773393690; cv=none; b=Fu8VFhQxyk7G0E/nN9B0srpUVd1dVDm9uJqbwuF82Z4oUV4E4jnWUPZdHorraa0768acfQ72GhwOX61lBqCEvb1Gkrco3e09mzK2UYDF/pkoMJOu0PlaN+CBO2aNfILygaUMUbzh++ZyTvVfSsXYcGIKeLwbaQDAyfFHFdu2qJw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773393690; c=relaxed/simple; bh=MbnJQdSNcFqOWql5mRLiNxcRZbqDnDIjGYtTvtNHtic=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=UJbngFn2u9IPF3/Cx2VCv69EGuYeJJklqPDVfoZ2/vvkdG920rtAY7tXcqLGxahuT4cS90ra2onMIlXlKWJ1eDJx0lV1OmJgaSWckSi3xO6Em0GhoPQwDxrfCFJoDn6knwD1Wc42aOClt6epMhkDLTmu1H03BuQqnGA3oCOzWsk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=tipi-net.de; spf=pass smtp.mailfrom=tipi-net.de; dkim=pass (2048-bit key) header.d=tipi-net.de header.i=@tipi-net.de header.b=oan2ZMwe; arc=none smtp.client-ip=194.13.80.246 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=tipi-net.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tipi-net.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tipi-net.de header.i=@tipi-net.de header.b="oan2ZMwe" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id AB77EA5703; Fri, 13 Mar 2026 10:21:20 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tipi-net.de; s=dkim; t=1773393681; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=fKVAA6EH0rNf/n0LrOeoSx0T22QsKnVt3p/nUXBzg5A=; b=oan2ZMweOwy3VeCZpaoP4ytIGyzxcQWcmrFoUpHbr0zVodT8TpvOs5xPbfyV6AoitQCc29 kxH+GQHwjoq6a5NH8XP/Ht3ja+Roer0gyR3yQhDFwsEZPHA0hmwG1LxSe1ieK6Yz63NXd+ q8UbXKUe+0vqudk6LxEoKsSc9Nm/sVjInrCoOt9FMlEsv90Jd/SCXhZP6SdY8cwwUJrXpm Xk/zGFfUivLqcP8t3C+TgXEmS21J9OlnxTpFN4yViKzHKZA9W5Xv4Oi5Gk3d7I/qsB0N6c BuxGwC+9z5EoLU4mT+W9ioINWhAoDg8Jfbp/oHPAzLI2mhBFxlm0OK/3kkDQRw== From: Nicolai Buchwitz To: Andrew Lunn , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Doug Berger , Florian Fainelli Cc: Broadcom internal kernel review list , Vikas Gupta , Bhargava Marreddy , Rajashekar Hudumula , Eric Biggers , Heiner Kallweit , =?UTF-8?q?Markus=20Bl=C3=B6chl?= , Arnd Bergmann , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Nicolai Buchwitz Subject: [PATCH net-next 3/6] net: bcmgenet: add basic XDP support (PASS/DROP) Date: Fri, 13 Mar 2026 10:20:58 +0100 Message-ID: <20260313092101.1344954-4-nb@tipi-net.de> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260313092101.1344954-1-nb@tipi-net.de> References: <20260313092101.1344954-1-nb@tipi-net.de> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Last-TLS-Session-Version: TLSv1.3 Content-Type: text/plain; charset="utf-8" Add XDP program attachment via ndo_bpf and execute XDP programs in the RX path. Supported actions: - XDP_PASS: build SKB from the (possibly modified) xdp_buff and pass to the network stack, handling xdp_adjust_head/tail correctly - XDP_DROP: return the page to page_pool, no SKB allocated - XDP_ABORTED: same as DROP with trace_xdp_exception XDP_TX and XDP_REDIRECT are not yet supported and will return XDP_ABORTED. The XDP hook runs after the HW error checks but before SKB construction, so dropped packets avoid all SKB allocation overhead. Advertise NETDEV_XDP_ACT_BASIC in xdp_features. Signed-off-by: Nicolai Buchwitz --- .../net/ethernet/broadcom/genet/bcmgenet.c | 153 +++++++++++++++--- .../net/ethernet/broadcom/genet/bcmgenet.h | 4 + 2 files changed, 133 insertions(+), 24 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/e= thernet/broadcom/genet/bcmgenet.c index dd70e5af2b1e..d43729fc2b1b 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -35,6 +35,8 @@ #include #include #include +#include +#include =20 #include =20 @@ -2274,6 +2276,53 @@ static int bcmgenet_rx_refill(struct bcmgenet_rx_rin= g *ring, return 0; } =20 +static struct sk_buff *bcmgenet_xdp_build_skb(struct bcmgenet_rx_ring *rin= g, + struct xdp_buff *xdp, + struct page *rx_page) +{ + unsigned int metasize; + struct sk_buff *skb; + + skb =3D napi_build_skb(xdp->data_hard_start, PAGE_SIZE); + if (unlikely(!skb)) + return NULL; + + skb_mark_for_recycle(skb); + + metasize =3D xdp->data - xdp->data_meta; + skb_reserve(skb, xdp->data - xdp->data_hard_start); + __skb_put(skb, xdp->data_end - xdp->data); + + if (metasize) + skb_metadata_set(skb, metasize); + + return skb; +} + +static unsigned int +bcmgenet_run_xdp(struct bcmgenet_rx_ring *ring, struct bpf_prog *prog, + struct xdp_buff *xdp, struct page *rx_page) +{ + unsigned int act; + + act =3D bpf_prog_run_xdp(prog, xdp); + + switch (act) { + case XDP_PASS: + return XDP_PASS; + case XDP_DROP: + page_pool_put_full_page(ring->page_pool, rx_page, true); + return XDP_DROP; + default: + bpf_warn_invalid_xdp_action(ring->priv->dev, prog, act); + fallthrough; + case XDP_ABORTED: + trace_xdp_exception(ring->priv->dev, prog, act); + page_pool_put_full_page(ring->page_pool, rx_page, true); + return XDP_ABORTED; + } +} + /* bcmgenet_desc_rx - descriptor based rx process. * this could be called from bottom half, or from NAPI polling method. */ @@ -2283,6 +2332,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_= rx_ring *ring, struct bcmgenet_rx_stats64 *stats =3D &ring->stats64; struct bcmgenet_priv *priv =3D ring->priv; struct net_device *dev =3D priv->dev; + struct bpf_prog *xdp_prog; struct enet_cb *cb; struct sk_buff *skb; u32 dma_length_status; @@ -2293,6 +2343,8 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_= rx_ring *ring, unsigned int p_index, mask; unsigned int discards; =20 + xdp_prog =3D READ_ONCE(priv->xdp_prog); + /* Clear status before servicing to reduce spurious interrupts */ mask =3D 1 << (UMAC_IRQ1_RX_INTR_SHIFT + ring->index); bcmgenet_intrl2_1_writel(priv, mask, INTRL2_CPU_CLEAR); @@ -2345,12 +2397,6 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet= _rx_ring *ring, hard_start =3D page_address(rx_page) + rx_off; status =3D (struct status_64 *)hard_start; dma_length_status =3D status->length_status; - if (dev->features & NETIF_F_RXCSUM) { - rx_csum =3D (__force __be16)(status->rx_csum & 0xffff); - if (rx_csum) { - /* defer csum setup to after skb is built */ - } - } =20 /* DMA flags and length are still valid no matter how * we got the Receive Status Vector (64B RSB or register) @@ -2409,26 +2455,52 @@ static unsigned int bcmgenet_desc_rx(struct bcmgene= t_rx_ring *ring, goto next; } /* error packet */ =20 - /* Build SKB from the page - data starts at hard_start, - * frame begins after RSB(64) + pad(2) =3D 66 bytes. - */ - skb =3D napi_build_skb(hard_start, PAGE_SIZE - GENET_XDP_HEADROOM); - if (unlikely(!skb)) { - BCMGENET_STATS64_INC(stats, dropped); - page_pool_put_full_page(ring->page_pool, rx_page, - true); - goto next; - } - - skb_mark_for_recycle(skb); + /* XDP: frame data starts after RSB + pad */ + if (xdp_prog) { + struct xdp_buff xdp; + unsigned int xdp_act; + int pkt_len; + + pkt_len =3D len - GENET_RSB_PAD; + if (priv->crc_fwd_en) + pkt_len -=3D ETH_FCS_LEN; + + xdp_init_buff(&xdp, PAGE_SIZE, &ring->xdp_rxq); + xdp_prepare_buff(&xdp, page_address(rx_page), + GENET_RX_HEADROOM, pkt_len, false); + + xdp_act =3D bcmgenet_run_xdp(ring, xdp_prog, &xdp, + rx_page); + if (xdp_act !=3D XDP_PASS) + goto next; + + /* XDP_PASS: build SKB from (possibly modified) xdp */ + skb =3D bcmgenet_xdp_build_skb(ring, &xdp, rx_page); + if (unlikely(!skb)) { + BCMGENET_STATS64_INC(stats, dropped); + page_pool_put_full_page(ring->page_pool, + rx_page, true); + goto next; + } + } else { + /* Build SKB from the page - data starts at + * hard_start, frame begins after RSB(64) + pad(2). + */ + skb =3D napi_build_skb(hard_start, + PAGE_SIZE - GENET_XDP_HEADROOM); + if (unlikely(!skb)) { + BCMGENET_STATS64_INC(stats, dropped); + page_pool_put_full_page(ring->page_pool, + rx_page, true); + goto next; + } =20 - /* Reserve the RSB + pad, then set the data length */ - skb_reserve(skb, GENET_RSB_PAD); - __skb_put(skb, len - GENET_RSB_PAD); + skb_mark_for_recycle(skb); + skb_reserve(skb, GENET_RSB_PAD); + __skb_put(skb, len - GENET_RSB_PAD); =20 - if (priv->crc_fwd_en) { - skb_trim(skb, skb->len - ETH_FCS_LEN); - len -=3D ETH_FCS_LEN; + if (priv->crc_fwd_en) + skb_trim(skb, skb->len - ETH_FCS_LEN); } =20 /* Set up checksum offload */ @@ -3750,6 +3822,37 @@ static int bcmgenet_change_carrier(struct net_device= *dev, bool new_carrier) return 0; } =20 +static int bcmgenet_xdp_setup(struct net_device *dev, + struct netdev_bpf *xdp) +{ + struct bcmgenet_priv *priv =3D netdev_priv(dev); + struct bpf_prog *old_prog; + struct bpf_prog *prog =3D xdp->prog; + + if (prog && dev->mtu > PAGE_SIZE - GENET_RX_HEADROOM - + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) { + NL_SET_ERR_MSG_MOD(xdp->extack, + "MTU too large for single-page XDP buffer"); + return -EOPNOTSUPP; + } + + old_prog =3D xchg(&priv->xdp_prog, prog); + if (old_prog) + bpf_prog_put(old_prog); + + return 0; +} + +static int bcmgenet_xdp(struct net_device *dev, struct netdev_bpf *xdp) +{ + switch (xdp->command) { + case XDP_SETUP_PROG: + return bcmgenet_xdp_setup(dev, xdp); + default: + return -EOPNOTSUPP; + } +} + static const struct net_device_ops bcmgenet_netdev_ops =3D { .ndo_open =3D bcmgenet_open, .ndo_stop =3D bcmgenet_close, @@ -3761,6 +3864,7 @@ static const struct net_device_ops bcmgenet_netdev_op= s =3D { .ndo_set_features =3D bcmgenet_set_features, .ndo_get_stats64 =3D bcmgenet_get_stats64, .ndo_change_carrier =3D bcmgenet_change_carrier, + .ndo_bpf =3D bcmgenet_xdp, }; =20 /* GENET hardware parameters/characteristics */ @@ -4063,6 +4167,7 @@ static int bcmgenet_probe(struct platform_device *pde= v) NETIF_F_RXCSUM; dev->hw_features |=3D dev->features; dev->vlan_features |=3D dev->features; + dev->xdp_features =3D NETDEV_XDP_ACT_BASIC; =20 netdev_sw_irq_coalesce_default_on(dev); =20 diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/e= thernet/broadcom/genet/bcmgenet.h index 82a6d29f481d..1459473ac1b0 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -16,6 +16,7 @@ #include #include #include +#include #include =20 #include "../unimac.h" @@ -671,6 +672,9 @@ struct bcmgenet_priv { u8 sopass[SOPASS_MAX]; =20 struct bcmgenet_mib_counters mib; + + /* XDP */ + struct bpf_prog *xdp_prog; }; =20 static inline bool bcmgenet_has_40bits(struct bcmgenet_priv *priv) --=20 2.51.0 From nobody Tue Apr 7 12:53:41 2026 Received: from mail.tipi-net.de (mail.tipi-net.de [194.13.80.246]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8C92A1C84C0; Fri, 13 Mar 2026 09:21:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=194.13.80.246 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773393691; cv=none; b=WkA2PUclKLbpbaGOrt72thdWbkq9VIz6HO0IQIpUdbcwf1fZUSXveJ+RYhAFaJTgxrZsvaPKqSCdMznk0G6WbmUTuTh38pMNx7IW1+S++3AfmACLSg9kTKux4gcrp9aGbm7yEjbpKuq8oYCBbRvvm52rNZvSPL730nsAHLX+s7k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773393691; c=relaxed/simple; bh=NvfHN+YwB5Uh1b17ClXrK/yAJiY1ImX9zrosgTCVRM4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=JoNOI8Iv0zO79sFrIfY23D0cY2/FwOlI9lnMeaXsdFlR8dRiQmm4WI3kzOSUHin6MbF0nQ+sELjtdoO8Sg/VR05M8N2P4R49mR2rqesJkP+iBwpqxNwKFxdMOPwtxAVCbPzMr32fXx/JaZWnpd9GJ0Q2/iayXxKg6aVEzlRyv78= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=tipi-net.de; spf=pass smtp.mailfrom=tipi-net.de; dkim=pass (2048-bit key) header.d=tipi-net.de header.i=@tipi-net.de header.b=fv9patpJ; arc=none smtp.client-ip=194.13.80.246 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=tipi-net.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tipi-net.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tipi-net.de header.i=@tipi-net.de header.b="fv9patpJ" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 7DBCFA5705; Fri, 13 Mar 2026 10:21:21 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tipi-net.de; s=dkim; t=1773393682; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=JlNTVCCEMpLe+QdV6Hc3TyF9BpdyJ2SM/Cy6iXmvFjA=; b=fv9patpJsg3eCa8jIZIvcWWwRH87qJRg3cCD0ytJlVuhF36FQKuZ8qMFbHexYkdROTEZ7Y DRu6q2MB9lJ8Ua7JRKxJtDfq6kTuIZqFF7JPwrHU7uqFCCTyxI+9MDm81FiBt2TrsD4Vtb ei25C7+LAqdDDY0jVdhErEaUgqW/+2vbJ36nRlJ0cDfiERZE1EnaIZcrfap5AdAGRkHay5 7TTl0oOQJScFCOanuOOu7vzm5+qn0uHNWci5jGm0azzCMeG6ns8pxOrmE5Qf3iry2qGP6A z+jxVrvEDZdz1t95DSVHVhm1qSZ1L+tZPmfHKq2VZrGW11oTT2VPhhdKxRkdCg== From: Nicolai Buchwitz To: Andrew Lunn , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Doug Berger , Florian Fainelli Cc: Broadcom internal kernel review list , Vikas Gupta , Bhargava Marreddy , Rajashekar Hudumula , Eric Biggers , Heiner Kallweit , =?UTF-8?q?Markus=20Bl=C3=B6chl?= , Arnd Bergmann , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Nicolai Buchwitz Subject: [PATCH net-next 4/6] net: bcmgenet: add XDP_TX support Date: Fri, 13 Mar 2026 10:20:59 +0100 Message-ID: <20260313092101.1344954-5-nb@tipi-net.de> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260313092101.1344954-1-nb@tipi-net.de> References: <20260313092101.1344954-1-nb@tipi-net.de> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Last-TLS-Session-Version: TLSv1.3 Content-Type: text/plain; charset="utf-8" Implement XDP_TX by submitting XDP frames through the default TX ring (DESC_INDEX). The frame is DMA-mapped and placed into a single TX descriptor with SOP|EOP|APPEND_CRC flags. The xdp_frame pointer is stored in the TX control block so that bcmgenet_free_tx_cb() can call xdp_return_frame() on TX completion, returning the page to the originating page_pool. The page_pool DMA direction is changed from DMA_FROM_DEVICE to DMA_BIDIRECTIONAL to support the TX DMA mapping of received pages. Signed-off-by: Nicolai Buchwitz --- .../net/ethernet/broadcom/genet/bcmgenet.c | 73 ++++++++++++++++++- .../net/ethernet/broadcom/genet/bcmgenet.h | 1 + 2 files changed, 71 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/e= thernet/broadcom/genet/bcmgenet.c index d43729fc2b1b..373ba5878ca1 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1893,6 +1893,12 @@ static struct sk_buff *bcmgenet_free_tx_cb(struct de= vice *dev, if (cb =3D=3D GENET_CB(skb)->last_cb) return skb; =20 + } else if (cb->xdpf) { + dma_unmap_single(dev, dma_unmap_addr(cb, dma_addr), + dma_unmap_len(cb, dma_len), DMA_TO_DEVICE); + dma_unmap_addr_set(cb, dma_addr, 0); + xdp_return_frame(cb->xdpf); + cb->xdpf =3D NULL; } else if (dma_unmap_addr(cb, dma_addr)) { dma_unmap_page(dev, dma_unmap_addr(cb, dma_addr), @@ -2299,10 +2305,62 @@ static struct sk_buff *bcmgenet_xdp_build_skb(struc= t bcmgenet_rx_ring *ring, return skb; } =20 +static bool bcmgenet_xdp_xmit_frame(struct bcmgenet_priv *priv, + struct xdp_frame *xdpf) +{ + struct bcmgenet_tx_ring *ring =3D &priv->tx_rings[DESC_INDEX]; + struct device *kdev =3D &priv->pdev->dev; + struct enet_cb *tx_cb_ptr; + dma_addr_t mapping; + u32 len_stat; + + spin_lock(&ring->lock); + + if (ring->free_bds < 1) { + spin_unlock(&ring->lock); + return false; + } + + tx_cb_ptr =3D bcmgenet_get_txcb(priv, ring); + + mapping =3D dma_map_single(kdev, xdpf->data, xdpf->len, DMA_TO_DEVICE); + if (dma_mapping_error(kdev, mapping)) { + tx_cb_ptr->skb =3D NULL; + tx_cb_ptr->xdpf =3D NULL; + bcmgenet_put_txcb(priv, ring); + spin_unlock(&ring->lock); + return false; + } + + dma_unmap_addr_set(tx_cb_ptr, dma_addr, mapping); + dma_unmap_len_set(tx_cb_ptr, dma_len, xdpf->len); + tx_cb_ptr->skb =3D NULL; + tx_cb_ptr->xdpf =3D xdpf; + + len_stat =3D (xdpf->len << DMA_BUFLENGTH_SHIFT) | + (priv->hw_params->qtag_mask << DMA_TX_QTAG_SHIFT) | + DMA_TX_APPEND_CRC | DMA_SOP | DMA_EOP; + + dmadesc_set(priv, tx_cb_ptr->bd_addr, mapping, len_stat); + + ring->free_bds--; + ring->prod_index++; + ring->prod_index &=3D DMA_P_INDEX_MASK; + + bcmgenet_tdma_ring_writel(priv, ring->index, ring->prod_index, + TDMA_PROD_INDEX); + + spin_unlock(&ring->lock); + + return true; +} + static unsigned int bcmgenet_run_xdp(struct bcmgenet_rx_ring *ring, struct bpf_prog *prog, struct xdp_buff *xdp, struct page *rx_page) { + struct bcmgenet_priv *priv =3D ring->priv; + struct xdp_frame *xdpf; unsigned int act; =20 act =3D bpf_prog_run_xdp(prog, xdp); @@ -2310,14 +2368,23 @@ bcmgenet_run_xdp(struct bcmgenet_rx_ring *ring, str= uct bpf_prog *prog, switch (act) { case XDP_PASS: return XDP_PASS; + case XDP_TX: + xdpf =3D xdp_convert_buff_to_frame(xdp); + if (unlikely(!xdpf) || + unlikely(!bcmgenet_xdp_xmit_frame(priv, xdpf))) { + page_pool_put_full_page(ring->page_pool, rx_page, + true); + return XDP_DROP; + } + return XDP_TX; case XDP_DROP: page_pool_put_full_page(ring->page_pool, rx_page, true); return XDP_DROP; default: - bpf_warn_invalid_xdp_action(ring->priv->dev, prog, act); + bpf_warn_invalid_xdp_action(priv->dev, prog, act); fallthrough; case XDP_ABORTED: - trace_xdp_exception(ring->priv->dev, prog, act); + trace_xdp_exception(priv->dev, prog, act); page_pool_put_full_page(ring->page_pool, rx_page, true); return XDP_ABORTED; } @@ -2846,7 +2913,7 @@ static int bcmgenet_rx_ring_create_pool(struct bcmgen= et_priv *priv, .pool_size =3D ring->size, .nid =3D NUMA_NO_NODE, .dev =3D &priv->pdev->dev, - .dma_dir =3D DMA_FROM_DEVICE, + .dma_dir =3D DMA_BIDIRECTIONAL, .offset =3D GENET_XDP_HEADROOM, .max_len =3D RX_BUF_LENGTH, }; diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/e= thernet/broadcom/genet/bcmgenet.h index 1459473ac1b0..192db0defbfc 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -472,6 +472,7 @@ struct bcmgenet_rx_stats64 { =20 struct enet_cb { struct sk_buff *skb; + struct xdp_frame *xdpf; struct page *rx_page; unsigned int rx_page_offset; void __iomem *bd_addr; --=20 2.51.0 From nobody Tue Apr 7 12:53:41 2026 Received: from mail.tipi-net.de (mail.tipi-net.de [194.13.80.246]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 133EB38C406; Fri, 13 Mar 2026 09:21:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=194.13.80.246 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773393692; cv=none; b=Z3v5RWmFxso54DtGpVLJ3WmdbV411Q60U6SML2XI+LF4o98L6bhhWZpi4z1CbDSB5JKi1LwgaNntTtswce8uiFUwcGNVZRttkc7dWF5OwGmUkdl9od2B5c/1wjgI9+aC6j3CFICA65WCniCyG2dJ6MvnqVBNeykMxKcmnoKMiPI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773393692; c=relaxed/simple; bh=3kA9lM7oCDmwBK8M854mec3iiuzF6TGWVkELDzJqUno=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=AX6ceSG/3OXiNbZgtd1TzGZb0mHar7OYrvmiZ91pATOmTU20RDj/nyhXVEw1G4kuzr2HqzcXtLN3wkL7tD1cp5a5J2Lbyh3laK0rrggW+0OeiyWmELImUR3sRO0mvypVVCaxVgB/xmy+s4bE37t3g8AE8jOQI5wEbfxL1TdzH+k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=tipi-net.de; spf=pass smtp.mailfrom=tipi-net.de; dkim=pass (2048-bit key) header.d=tipi-net.de header.i=@tipi-net.de header.b=g/AiXdG2; arc=none smtp.client-ip=194.13.80.246 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=tipi-net.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tipi-net.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tipi-net.de header.i=@tipi-net.de header.b="g/AiXdG2" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 4C946A5707; Fri, 13 Mar 2026 10:21:22 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tipi-net.de; s=dkim; t=1773393683; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=sUBslANvz1iK7buw/1PFrNaGDaQNEW2r48m8snuZBHw=; b=g/AiXdG2441GysUrJsgQlQZUg9YWTsI8GD16OlJSlofhqQbCEuWMjqkeAtfXdkCPOVo0Y+ 8sENIDnCOC6mwyhrBwEJsEgC6sR+UXffqknD+Kl5oyrvEztlN6ou+UAR09ERKwZlIBU0P1 n/XAUu4LGj0Ddou+atCcTGqJMhIr1BRIvuAjdSTp4fxgdwsE/xtsR9FVD8TDVrY8Dvnwc0 VHWHcMet+x0Ay+NduqAhsafQHj1jeXhzZNawSxK3N+VySHLHpcTM7SOJibojGgQhAxQh+y WSzmKSgrzRjfyFgNMrGbIAhmaH5qwqRuSYH1QLi4hvdJajRV+CoElXGKpxdF/Q== From: Nicolai Buchwitz To: Andrew Lunn , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Doug Berger , Florian Fainelli Cc: Broadcom internal kernel review list , Vikas Gupta , Bhargava Marreddy , Rajashekar Hudumula , Eric Biggers , Heiner Kallweit , =?UTF-8?q?Markus=20Bl=C3=B6chl?= , Arnd Bergmann , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Nicolai Buchwitz Subject: [PATCH net-next 5/6] net: bcmgenet: add XDP_REDIRECT and ndo_xdp_xmit support Date: Fri, 13 Mar 2026 10:21:00 +0100 Message-ID: <20260313092101.1344954-6-nb@tipi-net.de> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260313092101.1344954-1-nb@tipi-net.de> References: <20260313092101.1344954-1-nb@tipi-net.de> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Last-TLS-Session-Version: TLSv1.3 Content-Type: text/plain; charset="utf-8" Add XDP_REDIRECT support and implement ndo_xdp_xmit for receiving redirected frames from other devices. XDP_REDIRECT uses xdp_do_redirect() in the RX path with xdp_do_flush() called once per NAPI poll cycle. ndo_xdp_xmit batches multiple frames into the default TX ring under a single spinlock acquisition, ringing the doorbell once after all frames are queued. Call xdp_features_set/clear_redirect_target in the setup path. Advertise NETDEV_XDP_ACT_REDIRECT and NETDEV_XDP_ACT_NDO_XMIT in xdp_features. Signed-off-by: Nicolai Buchwitz --- .../net/ethernet/broadcom/genet/bcmgenet.c | 93 +++++++++++++++---- 1 file changed, 76 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/e= thernet/broadcom/genet/bcmgenet.c index 373ba5878ca1..30181f9cff98 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -2305,21 +2305,21 @@ static struct sk_buff *bcmgenet_xdp_build_skb(struc= t bcmgenet_rx_ring *ring, return skb; } =20 +/* Submit a single XDP frame to the TX ring. Caller must hold ring->lock. + * Returns true on success. Does not ring the doorbell - caller must + * write TDMA_PROD_INDEX after batching. + */ static bool bcmgenet_xdp_xmit_frame(struct bcmgenet_priv *priv, + struct bcmgenet_tx_ring *ring, struct xdp_frame *xdpf) { - struct bcmgenet_tx_ring *ring =3D &priv->tx_rings[DESC_INDEX]; struct device *kdev =3D &priv->pdev->dev; struct enet_cb *tx_cb_ptr; dma_addr_t mapping; u32 len_stat; =20 - spin_lock(&ring->lock); - - if (ring->free_bds < 1) { - spin_unlock(&ring->lock); + if (ring->free_bds < 1) return false; - } =20 tx_cb_ptr =3D bcmgenet_get_txcb(priv, ring); =20 @@ -2328,7 +2328,6 @@ static bool bcmgenet_xdp_xmit_frame(struct bcmgenet_p= riv *priv, tx_cb_ptr->skb =3D NULL; tx_cb_ptr->xdpf =3D NULL; bcmgenet_put_txcb(priv, ring); - spin_unlock(&ring->lock); return false; } =20 @@ -2347,12 +2346,14 @@ static bool bcmgenet_xdp_xmit_frame(struct bcmgenet= _priv *priv, ring->prod_index++; ring->prod_index &=3D DMA_P_INDEX_MASK; =20 + return true; +} + +static void bcmgenet_xdp_ring_doorbell(struct bcmgenet_priv *priv, + struct bcmgenet_tx_ring *ring) +{ bcmgenet_tdma_ring_writel(priv, ring->index, ring->prod_index, TDMA_PROD_INDEX); - - spin_unlock(&ring->lock); - - return true; } =20 static unsigned int @@ -2368,16 +2369,30 @@ bcmgenet_run_xdp(struct bcmgenet_rx_ring *ring, str= uct bpf_prog *prog, switch (act) { case XDP_PASS: return XDP_PASS; - case XDP_TX: + case XDP_TX: { + struct bcmgenet_tx_ring *tx_ring; + + tx_ring =3D &priv->tx_rings[DESC_INDEX]; xdpf =3D xdp_convert_buff_to_frame(xdp); - if (unlikely(!xdpf) || - unlikely(!bcmgenet_xdp_xmit_frame(priv, xdpf))) { - page_pool_put_full_page(ring->page_pool, rx_page, - true); + if (unlikely(!xdpf)) + goto drop_page; + + spin_lock(&tx_ring->lock); + if (unlikely(!bcmgenet_xdp_xmit_frame(priv, tx_ring, xdpf))) { + spin_unlock(&tx_ring->lock); + xdp_return_frame_rx_napi(xdpf); return XDP_DROP; } + bcmgenet_xdp_ring_doorbell(priv, tx_ring); + spin_unlock(&tx_ring->lock); return XDP_TX; + } + case XDP_REDIRECT: + if (unlikely(xdp_do_redirect(priv->dev, xdp, prog))) + goto drop_page; + return XDP_REDIRECT; case XDP_DROP: +drop_page: page_pool_put_full_page(ring->page_pool, rx_page, true); return XDP_DROP; default: @@ -2400,6 +2415,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_= rx_ring *ring, struct bcmgenet_priv *priv =3D ring->priv; struct net_device *dev =3D priv->dev; struct bpf_prog *xdp_prog; + bool xdp_flush =3D false; struct enet_cb *cb; struct sk_buff *skb; u32 dma_length_status; @@ -2538,6 +2554,8 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_= rx_ring *ring, =20 xdp_act =3D bcmgenet_run_xdp(ring, xdp_prog, &xdp, rx_page); + if (xdp_act =3D=3D XDP_REDIRECT) + xdp_flush =3D true; if (xdp_act !=3D XDP_PASS) goto next; =20 @@ -2611,6 +2629,9 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_= rx_ring *ring, bcmgenet_rdma_ring_writel(priv, ring->index, ring->c_index, RDMA_CONS_IN= DEX); } =20 + if (xdp_flush) + xdp_do_flush(); + ring->dim.bytes =3D bytes_processed; ring->dim.packets =3D rxpktprocessed; =20 @@ -3903,10 +3924,16 @@ static int bcmgenet_xdp_setup(struct net_device *de= v, return -EOPNOTSUPP; } =20 + if (!prog) + xdp_features_clear_redirect_target(dev); + old_prog =3D xchg(&priv->xdp_prog, prog); if (old_prog) bpf_prog_put(old_prog); =20 + if (prog) + xdp_features_set_redirect_target(dev, false); + return 0; } =20 @@ -3920,6 +3947,36 @@ static int bcmgenet_xdp(struct net_device *dev, stru= ct netdev_bpf *xdp) } } =20 +static int bcmgenet_xdp_xmit(struct net_device *dev, int num_frames, + struct xdp_frame **frames, u32 flags) +{ + struct bcmgenet_priv *priv =3D netdev_priv(dev); + struct bcmgenet_tx_ring *ring =3D &priv->tx_rings[DESC_INDEX]; + int sent =3D 0; + int i; + + if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) + return -EINVAL; + + if (unlikely(!netif_running(dev))) + return -ENETDOWN; + + spin_lock(&ring->lock); + + for (i =3D 0; i < num_frames; i++) { + if (!bcmgenet_xdp_xmit_frame(priv, ring, frames[i])) + break; + sent++; + } + + if (sent) + bcmgenet_xdp_ring_doorbell(priv, ring); + + spin_unlock(&ring->lock); + + return sent; +} + static const struct net_device_ops bcmgenet_netdev_ops =3D { .ndo_open =3D bcmgenet_open, .ndo_stop =3D bcmgenet_close, @@ -3932,6 +3989,7 @@ static const struct net_device_ops bcmgenet_netdev_op= s =3D { .ndo_get_stats64 =3D bcmgenet_get_stats64, .ndo_change_carrier =3D bcmgenet_change_carrier, .ndo_bpf =3D bcmgenet_xdp, + .ndo_xdp_xmit =3D bcmgenet_xdp_xmit, }; =20 /* GENET hardware parameters/characteristics */ @@ -4234,7 +4292,8 @@ static int bcmgenet_probe(struct platform_device *pde= v) NETIF_F_RXCSUM; dev->hw_features |=3D dev->features; dev->vlan_features |=3D dev->features; - dev->xdp_features =3D NETDEV_XDP_ACT_BASIC; + dev->xdp_features =3D NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | + NETDEV_XDP_ACT_NDO_XMIT; =20 netdev_sw_irq_coalesce_default_on(dev); =20 --=20 2.51.0 From nobody Tue Apr 7 12:53:41 2026 Received: from mail.tipi-net.de (mail.tipi-net.de [194.13.80.246]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1336338C401; Fri, 13 Mar 2026 09:21:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=194.13.80.246 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773393692; cv=none; b=K78VF59gH7XePKfEKnhVSM0lY4f10E291rf/QGjykWxlJFP4UpxdUb8H4MHRdf69tq6R83ACzVLlpOT89+mBC4Bcj0+ndu521Ybvb7Tb7ppd3S7s2spBb7DgoBL1cWRpKOQQBasvU/iSXJThoAltIIMhtr0mR6nkhAQp2zZPndQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773393692; c=relaxed/simple; bh=dje9lwINpGzPAN2nD/Zpfzj7I3u4WC3MpushQKChics=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=cpdPNB+/S+8Us8OI+diQ0PliClYHdzGlonhArrzQhNjANXMarz46LD9+W7tcl+dVnyG9/1ghM3Z3KWDWC893RsjQEvjKdDaT4WBel/GKVQkEJDvpRb/+V+RXTnMCvAJN89TztB9nB4hC2n5UDrAobsq/PjiE7PDuePu7+r83FmI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=tipi-net.de; spf=pass smtp.mailfrom=tipi-net.de; dkim=pass (2048-bit key) header.d=tipi-net.de header.i=@tipi-net.de header.b=vBsSO7rU; arc=none smtp.client-ip=194.13.80.246 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=tipi-net.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=tipi-net.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=tipi-net.de header.i=@tipi-net.de header.b="vBsSO7rU" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 3CDEBA570A; Fri, 13 Mar 2026 10:21:23 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tipi-net.de; s=dkim; t=1773393683; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=nEAFoVy10TP5FGA/AYLXcX4sh50SwTFGkPjXzFPbrqw=; b=vBsSO7rUUTqM4e7o1EAfqqYpMFznIs8fHA0LHuqRJ0kdcVOE3UbpWTFZrBlwUCkWoEj1F6 XBGNge+9op8r+17hMRziiq3g/H7KUxh77iqZm8CD1VhpLdtB0hSKeiV/irQxfc4YuLZv7f WkWyrNmKB1J/crrW0IBXkRvi2aNRSnqp0wu0HlCxiOTcecwNSZQTdNZ9TnEFnhaPjrwi1a UpVNSCKGmHl1hk8ng2rMgYe+0Xqi3B7xOXNzCqVQA1SbZgXCePXc3/tjmKPsh4V8NG7696 DIfjw7uGY4ptzJfetKi3WCgMZtSmQX404dEy95ESbH8L2WTf0oTXzGKdZ8IVWg== From: Nicolai Buchwitz To: Andrew Lunn , "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Doug Berger , Florian Fainelli Cc: Broadcom internal kernel review list , Vikas Gupta , Bhargava Marreddy , Rajashekar Hudumula , Eric Biggers , Heiner Kallweit , =?UTF-8?q?Markus=20Bl=C3=B6chl?= , Arnd Bergmann , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Nicolai Buchwitz Subject: [PATCH net-next 6/6] net: bcmgenet: add XDP statistics counters Date: Fri, 13 Mar 2026 10:21:01 +0100 Message-ID: <20260313092101.1344954-7-nb@tipi-net.de> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260313092101.1344954-1-nb@tipi-net.de> References: <20260313092101.1344954-1-nb@tipi-net.de> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Last-TLS-Session-Version: TLSv1.3 Content-Type: text/plain; charset="utf-8" Expose per-action XDP counters via ethtool -S: xdp_pass, xdp_drop, xdp_tx, xdp_tx_err, xdp_redirect, and xdp_redirect_err. These use the existing soft MIB infrastructure and are incremented in bcmgenet_run_xdp() alongside the existing driver statistics. Signed-off-by: Nicolai Buchwitz --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 17 ++++++++++++++++- drivers/net/ethernet/broadcom/genet/bcmgenet.h | 6 ++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/e= thernet/broadcom/genet/bcmgenet.c index 30181f9cff98..ef499192b325 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1168,6 +1168,13 @@ static const struct bcmgenet_stats bcmgenet_gstrings= _stats[] =3D { STAT_GENET_SOFT_MIB("tx_realloc_tsb", mib.tx_realloc_tsb), STAT_GENET_SOFT_MIB("tx_realloc_tsb_failed", mib.tx_realloc_tsb_failed), + /* XDP counters */ + STAT_GENET_SOFT_MIB("xdp_pass", mib.xdp_pass), + STAT_GENET_SOFT_MIB("xdp_drop", mib.xdp_drop), + STAT_GENET_SOFT_MIB("xdp_tx", mib.xdp_tx), + STAT_GENET_SOFT_MIB("xdp_tx_err", mib.xdp_tx_err), + STAT_GENET_SOFT_MIB("xdp_redirect", mib.xdp_redirect), + STAT_GENET_SOFT_MIB("xdp_redirect_err", mib.xdp_redirect_err), /* Per TX queues */ STAT_GENET_Q(0), STAT_GENET_Q(1), @@ -2368,6 +2375,7 @@ bcmgenet_run_xdp(struct bcmgenet_rx_ring *ring, struc= t bpf_prog *prog, =20 switch (act) { case XDP_PASS: + priv->mib.xdp_pass++; return XDP_PASS; case XDP_TX: { struct bcmgenet_tx_ring *tx_ring; @@ -2381,18 +2389,24 @@ bcmgenet_run_xdp(struct bcmgenet_rx_ring *ring, str= uct bpf_prog *prog, if (unlikely(!bcmgenet_xdp_xmit_frame(priv, tx_ring, xdpf))) { spin_unlock(&tx_ring->lock); xdp_return_frame_rx_napi(xdpf); + priv->mib.xdp_tx_err++; return XDP_DROP; } bcmgenet_xdp_ring_doorbell(priv, tx_ring); spin_unlock(&tx_ring->lock); + priv->mib.xdp_tx++; return XDP_TX; } case XDP_REDIRECT: - if (unlikely(xdp_do_redirect(priv->dev, xdp, prog))) + if (unlikely(xdp_do_redirect(priv->dev, xdp, prog))) { + priv->mib.xdp_redirect_err++; goto drop_page; + } + priv->mib.xdp_redirect++; return XDP_REDIRECT; case XDP_DROP: drop_page: + priv->mib.xdp_drop++; page_pool_put_full_page(ring->page_pool, rx_page, true); return XDP_DROP; default: @@ -2400,6 +2414,7 @@ bcmgenet_run_xdp(struct bcmgenet_rx_ring *ring, struc= t bpf_prog *prog, fallthrough; case XDP_ABORTED: trace_xdp_exception(priv->dev, prog, act); + priv->mib.xdp_drop++; page_pool_put_full_page(ring->page_pool, rx_page, true); return XDP_ABORTED; } diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/e= thernet/broadcom/genet/bcmgenet.h index 192db0defbfc..b3f1b7ed604a 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -156,6 +156,12 @@ struct bcmgenet_mib_counters { u32 tx_dma_failed; u32 tx_realloc_tsb; u32 tx_realloc_tsb_failed; + u32 xdp_pass; + u32 xdp_drop; + u32 xdp_tx; + u32 xdp_tx_err; + u32 xdp_redirect; + u32 xdp_redirect_err; }; =20 struct bcmgenet_tx_stats64 { --=20 2.51.0