From mboxrd@z Thu Jan 1 00:00:00 1970 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 9479F3BD645; Thu, 19 Mar 2026 11:54:52 +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=1773921298; cv=none; b=leG/zS3/DsxIGSTYg9QSueP9eEh9XyACmgojy5PMDtL9EY5JkTh7hfemfrhEDm2cH66WeC9onpO2QhcWaMp7Gl9SQ7PC0WYRK9M1ne3FbYcxWRom/NT3ZbiJiOumc9XUZhjAEZ8aHis3385T42nKABp6LPPUwRNITbH1tZ+LDQo= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773921298; c=relaxed/simple; bh=9WlfOjv0nA41ABB5xhtaJEuLgb9OSrf7VNiYZem/1LI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=rhyFin9i6XyvDj4uukLUrCG+IfF3jG50gLXCJ+vf9Wkw3DTKU+JC9BOecUfnXFUw/Wkv1q63XaGJprh0VHlYJZfsBq04Bxk9twf/pv0YQqbHH+XEk2HxtyEyAX9Y60w5pgA3W2gGshb3pQdySMJE7m/I+qVcdbRM+FUbjQt5Qy4= 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=fDGF5SuU; 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="fDGF5SuU" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 27F61A57F5; Thu, 19 Mar 2026 12:54:50 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tipi-net.de; s=dkim; t=1773921290; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=wloz274ivT/nJSJRx/4zzPde6tMV95RvADkP6fjGqKU=; b=fDGF5SuU+7gIxp7u8gtDd2izZJJuOl+APS/vDl9Y3Xfs8GnGxGWfM/v7aTKFt0QyiGE+el wpt5rE4WR0sHocEDSmHQXV27h0+thr17oXasXNzg2MMpbKSJ2jbXNT94GplL5cTef3RG4H izqMLwZKBIlNyfvm4qKyAy8MhBCxrU+dFzzk/YpXqyzhFHlzdCb7ONGLgLfqZPdR6O98/D zs0B2HFC3HtaHiUTAzt8no3CDJE88YbAeD39HqL0j5/JtF2fn5ukZ1RBaTE2G9nN7jNQxI BrQRcxC7RmWLgIcD35HRYUcVioJDIFZOQWC8Ebb2mUN82QscVW+KAcEIuq1/ug== From: Nicolai Buchwitz To: netdev@vger.kernel.org Cc: Nicolai Buchwitz , Doug Berger , Florian Fainelli , Broadcom internal kernel review list , Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Alexei Starovoitov , Daniel Borkmann , Jesper Dangaard Brouer , John Fastabend , Stanislav Fomichev , linux-kernel@vger.kernel.org, bpf@vger.kernel.org Subject: [PATCH net-next v3 3/6] net: bcmgenet: add basic XDP support (PASS/DROP) Date: Thu, 19 Mar 2026 12:53:56 +0100 Message-ID: <20260319115402.353509-4-nb@tipi-net.de> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260319115402.353509-1-nb@tipi-net.de> References: <20260319115402.353509-1-nb@tipi-net.de> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Last-TLS-Session-Version: TLSv1.3 Add XDP program attachment via ndo_bpf and execute XDP programs in the RX path. XDP_PASS builds an SKB from the xdp_buff (handling xdp_adjust_head/tail), XDP_DROP returns the page to page_pool without SKB allocation. XDP_TX and XDP_REDIRECT are not yet supported and return XDP_ABORTED. Advertise NETDEV_XDP_ACT_BASIC in xdp_features. Signed-off-by: Nicolai Buchwitz --- .../net/ethernet/broadcom/genet/bcmgenet.c | 147 +++++++++++++++--- .../net/ethernet/broadcom/genet/bcmgenet.h | 4 + 2 files changed, 133 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 6e610e73e12f..e8f90d6b16a2 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 #include @@ -2274,6 +2276,53 @@ static int bcmgenet_rx_refill(struct bcmgenet_rx_ring *ring, return 0; } +static struct sk_buff *bcmgenet_xdp_build_skb(struct bcmgenet_rx_ring *ring, + struct xdp_buff *xdp, + struct page *rx_page) +{ + unsigned int metasize; + struct sk_buff *skb; + + skb = napi_build_skb(xdp->data_hard_start, PAGE_SIZE); + if (unlikely(!skb)) + return NULL; + + skb_mark_for_recycle(skb); + + metasize = 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 = 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 = &ring->stats64; struct bcmgenet_priv *priv = ring->priv; struct net_device *dev = 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; + xdp_prog = READ_ONCE(priv->xdp_prog); + /* Clear status before servicing to reduce spurious interrupts */ mask = 1 << (UMAC_IRQ1_RX_INTR_SHIFT + ring->index); bcmgenet_intrl2_1_writel(priv, mask, INTRL2_CPU_CLEAR); @@ -2403,26 +2455,52 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, goto next; } /* error packet */ - /* Build SKB from the page - data starts at hard_start, - * frame begins after RSB(64) + pad(2) = 66 bytes. - */ - skb = 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 = len - GENET_RSB_PAD; + if (priv->crc_fwd_en) + pkt_len -= 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, true); + + xdp_act = bcmgenet_run_xdp(ring, xdp_prog, &xdp, + rx_page); + if (xdp_act != XDP_PASS) + goto next; + + /* XDP_PASS: build SKB from (possibly modified) xdp */ + skb = 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 = 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; + } - /* 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); - if (priv->crc_fwd_en) { - skb_trim(skb, skb->len - ETH_FCS_LEN); - len -= ETH_FCS_LEN; + if (priv->crc_fwd_en) + skb_trim(skb, skb->len - ETH_FCS_LEN); } /* Set up checksum offload */ @@ -3743,6 +3821,37 @@ static int bcmgenet_change_carrier(struct net_device *dev, bool new_carrier) return 0; } +static int bcmgenet_xdp_setup(struct net_device *dev, + struct netdev_bpf *xdp) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + struct bpf_prog *old_prog; + struct bpf_prog *prog = 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 = 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 = { .ndo_open = bcmgenet_open, .ndo_stop = bcmgenet_close, @@ -3754,6 +3863,7 @@ static const struct net_device_ops bcmgenet_netdev_ops = { .ndo_set_features = bcmgenet_set_features, .ndo_get_stats64 = bcmgenet_get_stats64, .ndo_change_carrier = bcmgenet_change_carrier, + .ndo_bpf = bcmgenet_xdp, }; /* GENET hardware parameters/characteristics */ @@ -4056,6 +4166,7 @@ static int bcmgenet_probe(struct platform_device *pdev) NETIF_F_RXCSUM; dev->hw_features |= dev->features; dev->vlan_features |= dev->features; + dev->xdp_features = NETDEV_XDP_ACT_BASIC; netdev_sw_irq_coalesce_default_on(dev); diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/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 #include "../unimac.h" @@ -671,6 +672,9 @@ struct bcmgenet_priv { u8 sopass[SOPASS_MAX]; struct bcmgenet_mib_counters mib; + + /* XDP */ + struct bpf_prog *xdp_prog; }; static inline bool bcmgenet_has_40bits(struct bcmgenet_priv *priv) -- 2.51.0