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 7B121317171; Mon, 6 Apr 2026 08:36:40 +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=1775464602; cv=none; b=S3oOw2ak906TeaE/LlSmGsSfbQMXqZDAVSjjLvqAsj4JfbE4Agh3qcgSdvqui/P0sBqbvavRmegtoKcWmEgl3s4jR0mLfxkWF/6iWQHK2jslvr6auAhGZepFxT5PnF2z0TGYNRxKGJvLTx7lBxZ9nat4qBIuKgFnJN/KWYH3NJ8= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775464602; c=relaxed/simple; bh=dSxiLXfM6C9CSoJnIOH4PyAKIiMM+BaKbRh8gouGvN0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=rBkPSVrag+uN/rRWTHlmfXVcm5G5ZcLxHu/shaTaqv1SlWObZG814s4uQjdpxsRmHQG2/CVQN8NsP0g7gOe6OdRwVKdEv+wzBkH5C5+Gj+SnEMRE7Hv7D4mL1MESPTKRovyUO0gXbCp5JQKryQll8xlR/YcaaNDAYoEwddLor6M= 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=Am1L6bx2; 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="Am1L6bx2" Received: from [127.0.0.1] (localhost [127.0.0.1]) by localhost (Mailerdaemon) with ESMTPSA id 29BCDA58A4; Mon, 6 Apr 2026 10:36:38 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tipi-net.de; s=dkim; t=1775464599; h=from:subject:date:message-id:to:cc:mime-version: content-transfer-encoding:in-reply-to:references; bh=7+LuL26pphWLOY/03TcB3lUXTfBvBqPM9e3JvHJll4U=; b=Am1L6bx2uxhqDV86SiRVg1zgmyLsIjQUk62DllmVqNUto0xWzvmLq3i4+TMr2aX1dDHRAv zwycLFSdZXa49jf/8ZLVDz8o9Sdd5MZmJNBZim0UFB7BrhnVhFYM5EhTihMnGttiUCJFbV OZyyqBiUP5SYmlGXnxplPjqT93p5AStBLVgqVI+U2xLH2theBZfw1MT//gF3C69+Lmvw48 RYDmyGouLpgL5iZNsrbdhOGuL93gZjXpSvZAqVKZPhWczsTMFNCWTPDPq8p/nR4CZfRmxs pc+gCSbMOCSdsf/JAzHBeJRwwRcAHHpCI4cVgDa/gTmTCvuGWufd2QxkW0yygw== From: Nicolai Buchwitz To: netdev@vger.kernel.org Cc: Justin Chen , Simon Horman , Mohsin Bashir , Doug Berger , Florian Fainelli , Broadcom internal kernel review list , Andrew Lunn , Eric Dumazet , Paolo Abeni , Nicolai Buchwitz , "David S. Miller" , Jakub Kicinski , Alexei Starovoitov , Daniel Borkmann , Jesper Dangaard Brouer , John Fastabend , Stanislav Fomichev , linux-kernel@vger.kernel.org, bpf@vger.kernel.org Subject: [PATCH net-next v6 5/7] net: bcmgenet: add XDP_REDIRECT and ndo_xdp_xmit support Date: Mon, 6 Apr 2026 10:35:29 +0200 Message-ID: <20260406083536.839517-6-nb@tipi-net.de> X-Mailer: git-send-email 2.51.0 In-Reply-To: <20260406083536.839517-1-nb@tipi-net.de> References: <20260406083536.839517-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_REDIRECT support and implement ndo_xdp_xmit for receiving redirected frames from other devices. XDP_REDIRECT calls xdp_do_redirect() in the RX path with xdp_do_flush() once per NAPI poll cycle. ndo_xdp_xmit batches frames into ring 16 under a single spinlock acquisition. 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 | 87 ++++++++++++++++--- 1 file changed, 73 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index afaa991ff23a..b725ffa9c746 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -2327,22 +2327,22 @@ static struct sk_buff *bcmgenet_xdp_build_skb(struct bcmgenet_rx_ring *ring, return skb; } +/* 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, bool dma_map) { - struct bcmgenet_tx_ring *ring = &priv->xdp_tx_ring; struct device *kdev = &priv->pdev->dev; struct enet_cb *tx_cb_ptr; dma_addr_t mapping; unsigned int dma_len; u32 len_stat; - spin_lock(&ring->lock); - - if (ring->free_bds < 1) { - spin_unlock(&ring->lock); + if (ring->free_bds < 1) return false; - } tx_cb_ptr = bcmgenet_get_txcb(priv, ring); @@ -2356,7 +2356,6 @@ static bool bcmgenet_xdp_xmit_frame(struct bcmgenet_priv *priv, */ if (unlikely(xdpf->headroom < sizeof(struct status_64))) { bcmgenet_put_txcb(priv, ring); - spin_unlock(&ring->lock); return false; } @@ -2370,7 +2369,6 @@ static bool bcmgenet_xdp_xmit_frame(struct bcmgenet_priv *priv, tx_cb_ptr->skb = NULL; tx_cb_ptr->xdpf = NULL; bcmgenet_put_txcb(priv, ring); - spin_unlock(&ring->lock); return false; } } else { @@ -2402,12 +2400,14 @@ static bool bcmgenet_xdp_xmit_frame(struct bcmgenet_priv *priv, ring->prod_index++; ring->prod_index &= DMA_P_INDEX_MASK; + 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; } static unsigned int bcmgenet_run_xdp(struct bcmgenet_rx_ring *ring, @@ -2416,6 +2416,7 @@ static unsigned int bcmgenet_run_xdp(struct bcmgenet_rx_ring *ring, struct page *rx_page) { struct bcmgenet_priv *priv = ring->priv; + struct bcmgenet_tx_ring *tx_ring; struct xdp_frame *xdpf; unsigned int act; @@ -2447,11 +2448,25 @@ static unsigned int bcmgenet_run_xdp(struct bcmgenet_rx_ring *ring, true); return XDP_DROP; } - if (unlikely(!bcmgenet_xdp_xmit_frame(priv, xdpf, false))) { + + tx_ring = &priv->xdp_tx_ring; + spin_lock(&tx_ring->lock); + if (unlikely(!bcmgenet_xdp_xmit_frame(priv, tx_ring, + xdpf, false))) { + 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))) { + page_pool_put_full_page(ring->page_pool, rx_page, + true); + return XDP_DROP; + } + return XDP_REDIRECT; case XDP_DROP: page_pool_put_full_page(ring->page_pool, rx_page, true); return XDP_DROP; @@ -2475,6 +2490,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, struct bcmgenet_priv *priv = ring->priv; struct net_device *dev = priv->dev; struct bpf_prog *xdp_prog; + bool xdp_flush = false; struct enet_cb *cb; struct sk_buff *skb; u32 dma_length_status; @@ -2620,6 +2636,8 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, if (xdp_prog) { xdp_act = bcmgenet_run_xdp(ring, xdp_prog, &xdp, rx_page); + if (xdp_act == XDP_REDIRECT) + xdp_flush = true; if (xdp_act != XDP_PASS) goto next; } @@ -2673,6 +2691,9 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, bcmgenet_rdma_ring_writel(priv, ring->index, ring->c_index, RDMA_CONS_INDEX); } + if (xdp_flush) + xdp_do_flush(); + ring->dim.bytes = bytes_processed; ring->dim.packets = rxpktprocessed; @@ -4003,10 +4024,16 @@ static int bcmgenet_xdp_setup(struct net_device *dev, return -EOPNOTSUPP; } + if (!prog) + xdp_features_clear_redirect_target(dev); + old_prog = xchg(&priv->xdp_prog, prog); if (old_prog) bpf_prog_put(old_prog); + if (prog) + xdp_features_set_redirect_target(dev, false); + return 0; } @@ -4020,6 +4047,36 @@ static int bcmgenet_xdp(struct net_device *dev, struct netdev_bpf *xdp) } } +static int bcmgenet_xdp_xmit(struct net_device *dev, int num_frames, + struct xdp_frame **frames, u32 flags) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + struct bcmgenet_tx_ring *ring = &priv->xdp_tx_ring; + int sent = 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 = 0; i < num_frames; i++) { + if (!bcmgenet_xdp_xmit_frame(priv, ring, frames[i], true)) + 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 = { .ndo_open = bcmgenet_open, .ndo_stop = bcmgenet_close, @@ -4032,6 +4089,7 @@ static const struct net_device_ops bcmgenet_netdev_ops = { .ndo_get_stats64 = bcmgenet_get_stats64, .ndo_change_carrier = bcmgenet_change_carrier, .ndo_bpf = bcmgenet_xdp, + .ndo_xdp_xmit = bcmgenet_xdp_xmit, }; /* GENET hardware parameters/characteristics */ @@ -4334,7 +4392,8 @@ 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; + dev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT | + NETDEV_XDP_ACT_NDO_XMIT; netdev_sw_irq_coalesce_default_on(dev); -- 2.51.0