From nobody Sat Sep 26 19:33:47 2026 Received: from mail-wr1-f48.google.com (mail-wr1-f48.google.com [209.85.221.48]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 33A013D1CBE for ; Mon, 31 Aug 2026 08:52:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788166363; cv=none; b=PaCB+byNXWRHD4lBB50UTvXn8Re57KXZSdtwrlIVUcvqktYF4O0Xd15hCWwHiS3DHgmiulAU6AL3OuUpASlO1wXDyRBrSvc+2IHCcvE4V9B99QKRCHCaSnOndwSlIO3yqA7k5Vc+IBPPKHeqYIxEzq3fQJRd6m97yg2zOioTg/8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788166363; c=relaxed/simple; bh=cKoXIHb2ZuYycMu8ZqrpbWLAyXEe2FutGWvTbc17nDM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Ea23SoOmJbbKDXgWtVIXNBD72xF9ZfvSb/i3jbW2Ue4ngfZhsEUALgAv3Su6lQKLzQo2pxZo3DxhOguys2Y+dYPV0KMqzZlb80jXQ9DYXrh4375qu4mj/lW/7Ldli1E1z9bhmX2QlorEjIeoz7cEpcRQqJVNF7WVYthE+/VqdNM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=XaXMfyo+; arc=none smtp.client-ip=209.85.221.48 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="XaXMfyo+" Received: by mail-wr1-f48.google.com with SMTP id ffacd0b85a97d-482e5733a5aso1893790f8f.0 for ; Mon, 31 Aug 2026 01:52:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1788166359; x=1788771159; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:from:to:cc:subject:date :message-id:reply-to:content-type; bh=rX7O4Cyu214edbufKKR6tV50lN9glgVksMzMntzrD6w=; b=XaXMfyo+lEkcQOa1TZb/plqpI2z9SfhTjBTiZYLhCihSreDPBLAWx+QI0t5ezIc1jC 6NVAk7WvZ9Or9h5MsVmLEmYQQp4fs30ItWJn6T0j2ru/pdISuvqg3sIXY8bfaLMgUhBQ mCBSyu3oVhGrsvkBROUtQueM3GNeCA81kpQ67Vx0x7IlKTcekK7Yev4R/yp2a+N40fl4 Bj8BA5GEazznuzWDTiP0gLt1NksCXsnFmRJkGHyi/x2qG8K1mbWLXr86kTME1xioK6LM /fh9Z4XTyzdAY1o61rf8KZ4NSZ7RS5Fshm5LoG22xyY5Jac/D01ejhVCIuQHDeZb33s5 i6Rw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788166359; x=1788771159; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=rX7O4Cyu214edbufKKR6tV50lN9glgVksMzMntzrD6w=; b=A/OcX31Zgr1DCLxPkFP5J+az7YwScuvH5DH6r34z5OSf+cxzi6MD1CEKMuDOqLc25U m/QA3UmXcLtamv5eHHMlv9c7SrDGHdQkoMZ3Mi+yaumYk3g8TwkoBNhMf+IZTqUCdCyC P6jEAENmxf7jR9uFM8LvFMJizUsx+OJ7OLiiGDlp3Zt2DGkMpdKHWl0AKjQaJpvo8fm7 QvZB2t9O6MotAqSUmx4LkRKEB834e/pRvxvg5khfNnOfO2kGWyL5JrixuR0L+s1RnjqP lwhhqA3hcQeIfGwP1taI6FLnxbR1OWzV8oqzMP/yb2U4WlZhsGH+9UVsWU3uX2Uj9Z6H DlAw== X-Forwarded-Encrypted: i=1; AKwUvByFfhBR35wVdjOgX12rjgXB79lkJrS0WGnhUFSF8T1npGclWgJCIm/Artawae8etJ2JiI0QLyfmjGiyOZA=@vger.kernel.org X-Gm-Message-State: AFuF++mLrFYq4zvyOe3D9tsfJYNT16KGsDfP5PKCF7JIlEnJMGY3hj+l Az8LVYg0gTULSZOFpeWVhgitpXD0Wtz/IsHjluEzra9eQFM1Q9Q5/0Fr X-Gm-Gg: AYBFou0+yAL5omOsUzpL4ohH7N96IqwO0N0Fe4yyzarSORSPhxfZkeQpYCoxx0ax+pi 0nMG241U6Gd4F50LsVV//iWgRF9BFK8EVPri2vPxw6QaTUn6WSFRgHu5YlZ1THhm7yQGGNjn7FR MTGeNZzzR7AeBv9KrLUcxqivaWGLUFoN4BpdPekRFjYKFb9YGLnw0nKO8pFboM3raxOQO11IGRT mAyGtdKMV0NiYt3ehH0DJsY6RO5uRdhppwB9L7oH0uX0+iktXrbYbyQL0FKHPThIUgw9n27siV7 OTUUJ3E257eZG71iGghqdsm9lfIuwvePhyB64sXxe2KhB8KosKkfadZqKjXpxN0Vyo0/gqAKZxJ yVemzAPOpx3rLY10cFrHCFKDS0a3VAyw8TxM4MdMsi/Ds2Jwr2PzKHrJevESSyOigHUEQGhunsN WpwUzRrBQLYzhFd7e429ZIv872A63lpf2yBnFfWxtexwqkojTTJND0KeGCgh/Nt54= X-Received: by 2002:a05:6000:4b10:b0:483:8040:449a with SMTP id ffacd0b85a97d-4843efbb9efmr2786355f8f.12.1788166358924; Mon, 31 Aug 2026 01:52:38 -0700 (PDT) Received: from SVR.localdomain ([185.179.67.170]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-484397f33fesm7786600f8f.15.2026.08.31.01.52.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 31 Aug 2026 01:52:38 -0700 (PDT) Sender: Semih Baskan From: Semih Baskan To: florian.fainelli@broadcom.com, jonas.gorski@gmail.com, andrew@lunn.ch, olteanv@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com Cc: vladimir.oltean@nxp.com, horms@kernel.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH net v3 1/2] net: dsa: let drivers offload 8021q uppers on standalone ports Date: Mon, 31 Aug 2026 11:52:16 +0300 Message-ID: <20260831085217.391-2-strst.gs@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260831085217.391-1-strst.gs@gmail.com> References: <20260831085217.391-1-strst.gs@gmail.com> 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 Content-Type: text/plain; charset="utf-8" Before v5.15, DSA delivered the VIDs of 8021q uppers to switch drivers unconditionally: user ports advertised NETIF_F_HW_VLAN_CTAG_FILTER, the 8021q layer reported upper VIDs to .ndo_vlan_rx_add_vid, and .port_vlan_add programmed them whether or not a bridge had enabled VLAN filtering. Commit 06cfb2df7eb0 ("net: dsa: don't advertise 'rx-vlan-filter' when not needed") stopped the delivery for standalone ports and commit f089652b6b16 ("net: dsa: b53: do not program vlans when vlan filtering is off") stopped the programming, on the model that a standalone port is VLAN-unaware and any 8021q upper is a software VLAN. That model does not fit hardware whose VID lookup cannot be turned off. b53 keeps its lookup enabled at all times, because disabling it moves the ARL to shared VLAN learning: the hash that selects the ARL slot then treats every VID as 0, entries keyed by a real VID become unreachable, and the hardware table drifts away from the bridge fdb. With the lookup active, a tagged frame whose VID is absent from the table is discarded before it reaches the CPU, measured on bcm5301x. Such a port is never VLAN-unaware, whatever the bridge asked for. Commit 06cfb2df7eb0 ("net: dsa: don't advertise 'rx-vlan-filter' when not needed") lists the reasons a driver may keep it on, and this is its first case, standalone ports that would otherwise drop VLAN-tagged traffic, except that here the VLAN awareness is held on by the silicon itself rather than by a VLAN-aware bridge elsewhere on the switch. The existing opt-in, ds->needs_standalone_vlan_filtering, is not a fit. It exists for hellcreek, whose traffic separation depends on per-port VLANs, so standalone operation there needs the vlan_filtering state itself forced on: dsa_port_reset_vlan_filtering() forces vlan_filtering=3D1 when a port leaves a VLAN-unaware bridge, and with vlan_filtering_is_global that lands the whole switch in the state hellcreek wants. On b53 the same flip is a user-visible mode change for every port on the switch: bridge VLANs that were committed while inactive become enforced, and the unknown-VID ingress drop modes turn on chip-wide. b53 needs the VIDs, not the state. Add ds->needs_standalone_vlan_offload for that narrower need. It advertises NETIF_F_HW_VLAN_CTAG_FILTER on user ports permanently, so upper VIDs reach .port_vlan_add again, and it leaves the vlan_filtering state alone. This restores the pre-v5.15 delivery pipeline for drivers that opt in and changes nothing for drivers that do not. A permanent feature bit also means dsa_user_manage_vlan_filtering() must not run on vlan_filtering toggles of such a switch. The ds->ops->port_vlan_filtering call is unchanged and the driver still sees every toggle; what is skipped only toggles the feature bit and replays or clears the VID list, and both halves are wrong when the bit never goes away. The replay re-adds VIDs that were never cleared, so vlan_vid_add() refcounts every upper VID twice. The clear strips the feature bit and the VIDs from a port that happens to be bridged at toggle time, and its uppers then stay dead even after it leaves the bridge, because nothing re-offloads them once the feature bit is gone. Both effects were measured on bcm5301x hardware. The conduit change path keeps its explicit teardown and restore of the 8021q upper VLANs, and now runs it for every port of such a switch, bridged or not, because with the permanent feature bit every port with uppers has VLANs on the CPU port. Fixes: 06cfb2df7eb0 ("net: dsa: don't advertise 'rx-vlan-filter' when not n= eeded") Cc: stable@vger.kernel.org Signed-off-by: Semih Baskan --- include/net/dsa.h | 3 +++ net/dsa/port.c | 22 +++++++++++++++------- net/dsa/user.c | 4 +++- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/include/net/dsa.h b/include/net/dsa.h index 7507d632e7c6..67a01fc5f81e 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -405,6 +405,9 @@ struct dsa_switch { /* Keep VLAN filtering enabled on ports not offloading any upper */ u32 needs_standalone_vlan_filtering:1; =20 + /* Offload 8021q uppers of standalone ports even when not filtering */ + u32 needs_standalone_vlan_offload:1; + /* Pass .port_vlan_add and .port_vlan_del to drivers even for bridges * that have vlan_filtering=3D0. All drivers should ideally set this (and * then the option would get removed), but it is unknown whether this diff --git a/net/dsa/port.c b/net/dsa/port.c index 1f5536c0dffc..e61abc7c74f7 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -831,6 +831,9 @@ int dsa_port_vlan_filtering(struct dsa_port *dp, bool v= lan_filtering, if (!user) continue; =20 + if (ds->needs_standalone_vlan_offload) + continue; + err =3D dsa_user_manage_vlan_filtering(user, vlan_filtering); if (err) @@ -839,10 +842,12 @@ int dsa_port_vlan_filtering(struct dsa_port *dp, bool= vlan_filtering, } else { dp->vlan_filtering =3D vlan_filtering; =20 - err =3D dsa_user_manage_vlan_filtering(dp->user, - vlan_filtering); - if (err) - goto restore; + if (!ds->needs_standalone_vlan_offload) { + err =3D dsa_user_manage_vlan_filtering(dp->user, + vlan_filtering); + if (err) + goto restore; + } } =20 return 0; @@ -1445,10 +1450,13 @@ int dsa_port_change_conduit(struct dsa_port *dp, st= ruct net_device *conduit, =20 /* The port might still be VLAN filtering even if it's no longer * under a bridge, either due to ds->vlan_filtering_is_global or - * ds->needs_standalone_vlan_filtering. In turn this means VLANs - * on the CPU port. + * ds->needs_standalone_vlan_filtering, and every port of a + * ds->needs_standalone_vlan_offload switch keeps its 8021q upper + * VLANs whether bridged or not. In turn this means VLANs on the + * CPU port. */ - vlan_filtering =3D dsa_port_is_vlan_filtering(dp); + vlan_filtering =3D dsa_port_is_vlan_filtering(dp) || + ds->needs_standalone_vlan_offload; if (vlan_filtering) { err =3D dsa_user_manage_vlan_filtering(dev, false); if (err) { diff --git a/net/dsa/user.c b/net/dsa/user.c index 041f9060c8ef..fda6ba4fdd13 100644 --- a/net/dsa/user.c +++ b/net/dsa/user.c @@ -1946,6 +1946,7 @@ static int dsa_user_clear_vlan(struct net_device *vde= v, int vid, void *arg) * * - If standalone (this includes software bridge, software LAG): * - if ds->needs_standalone_vlan_filtering =3D true, OR if + * ds->needs_standalone_vlan_offload =3D true, OR if * (ds->vlan_filtering_is_global =3D true AND there are bridges span= ning * this switch chip which have vlan_filtering=3D1) * - the 8021q upper VLANs @@ -2717,7 +2718,8 @@ void dsa_user_setup_tagger(struct net_device *user) user->hw_features |=3D NETIF_F_HW_TC; if (user->needed_tailroom) user->features &=3D ~(NETIF_F_SG | NETIF_F_FRAGLIST); - if (ds->needs_standalone_vlan_filtering) + if (ds->needs_standalone_vlan_filtering || + ds->needs_standalone_vlan_offload) user->features |=3D NETIF_F_HW_VLAN_CTAG_FILTER; =20 user->lltx =3D true; --=20 2.53.0.windows.1 From nobody Sat Sep 26 19:33:47 2026 Received: from mail-wr1-f51.google.com (mail-wr1-f51.google.com [209.85.221.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B84A23D45C3 for ; Mon, 31 Aug 2026 08:52:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788166365; cv=none; b=n9MmBYzzq71PKVMzfOw0/CAG0Hgia50aaJCS72iXaqN0jh/vuWy2OtlciNwtWFMGqBF3RrYznPsbStOcu/3oL45151FY1dvdhdPTDPFFItjpjOvu9GkOkzWMFzp1SkWnix7XHsJICriJ5lPKKG4tpblp5hn3EgOKVVcHhgNP8Ao= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788166365; c=relaxed/simple; bh=7OoavN0jjEp5vlSvlLaV2gsBP9dR4yCX4OyLvdsj3Ic=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=h4AM8tco/rFW9CcVmaoxiBC7YmxX7gFLZckGlY9pNKTw2NGJ3f25f5iWcAsq6MNe+n6Ebtyt3O7BsfuPY2nLanfUTczL+BSMptbJ3M8okbM8PPfmlL/cYRHLoaHVw2UIMenE5fs9P2QlwfuQebWdj0edIhJyiIm+38uNoUOkS8c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=p/b+y5a4; arc=none smtp.client-ip=209.85.221.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="p/b+y5a4" Received: by mail-wr1-f51.google.com with SMTP id ffacd0b85a97d-482e29049adso1298795f8f.2 for ; Mon, 31 Aug 2026 01:52:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1788166361; x=1788771161; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:from:to:cc:subject:date :message-id:reply-to:content-type; bh=dJw3jrgZrFFiWj2Vn921uZhc33JcuGGDxQ3rYF99UdI=; b=p/b+y5a4tClvgLnfsvOeJwTJaxGqMyHhjTAQFl7H1Igu01stUHf9aFLxvJTmbj9jsL drxT5iNgDKF9cRrjI5Jzm/AR1ATYKBY28QexKj12wLZueKaFIwHT0+OTtjNLE5aBXlLk 0jqd6/rENltVOiKLXXOfSc4xC5unc4+Zvsuw45Vh7wnpODoPZMz/uWwNSYlObAo5TRqz Zk2kb4Lv8sux5zSCpVMpWpZsUTO49oPUSoqKPnd8jYlgjiEyZxczBlcriYIgNIgcCTUp ua2uP6fj9tebYovvPtjw7+0Kt8hUQSSaqSJeJcFIhamenMq9JIFr3JTufhDYWqNRnQPo FGdA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788166361; x=1788771161; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=dJw3jrgZrFFiWj2Vn921uZhc33JcuGGDxQ3rYF99UdI=; b=Bf7kLysvoHpdDnw4dkY4kIuVsh332uTlx6GVKS9B/4p0m6BjoFqXg5Ey4miIP79OLQ s7O4PDn7zdmMR4KQCJbFF+Y0CBd+dru830smQSgKEjgQJGUZ8AOMr2eFhTlrPOrRRUIl IfuHPGIZSwlhmoe/uM73TYXOiaSX3MWgo75J6DIH26P7pSkApkZ3/1y1EvYbYu/rOqQW enAfFpmCWq/ho8icWjZ9krcgGgHGrUFAXIqVcHbq/q0MMKlHZEKgP3t5KnyoArd17x1x rJqQiQPmvS2HSDdGhxamG1N+N55D6LoAFSxZv/W2Q/8+6aP1xE7jJAROSS/W+W3QyVQL GXyQ== X-Forwarded-Encrypted: i=1; AKwUvBw2EnCv5N6Po1AtqUSupY16LmAcdOBGEo6MMEcklx/fX7YngDeu6m1XZI5YlY1mNAWjOcor2wuV+XfGJFU=@vger.kernel.org X-Gm-Message-State: AFuF++ljaj/lLX2U+O4kV/I/hXKz/5XxFfE98eROVDVJbGwemsCOrdyW 08Jiu135sdhjxkrgsOZ0P8MDfVtHfXXeF2HSpVP0eON0pE11YCn1VUX0kI0WeVcH X-Gm-Gg: AYBFou04skwgwLmI0CWOnhQrlY3aH+MOK/nXu6jwn8IZoMJHkJXJZNrOpJxrLXV97hf IVpMKo39jid4raagnK5FxLFt/DrDzLN7jfl8oAXJLikWuAJwc3VlXx8MxeteCS46IEszvbMKIaO jJLP66pC9y38JLmL6KNBfO5w4waIzs5AEND4go8T2vmCVeNE78vgZR4XlI6+EKHjw40M/fuivZX QNBUCvUY/f4C8L2mrAe4oWg/Y0Hb73GWOMfCZaTdSvzBOJ0NGjhcbDKN5Dk6L+L2sKopNNDEaUY Lpdm/EfimPuwYtyjk2bajJsp2ShRnIJkn9Mc8N2ItTdPU9TyiTYCTZBOtjjUJ+pB+Piyo8D1DzH WoHMAhETmCOU8ZXUeLIfmij37yDMDutDS+CosXlHFjE9v10+MvAO67WKt8EE6tvXLmeO5h+Ds45 HhRvXVhlln7e1BCyvfo1OXQAAkFyUOBTNIGbuHubnkfYkuKrFesmHVlEVuP3rhZHE= X-Received: by 2002:a05:6000:2284:b0:482:fc30:a1b4 with SMTP id ffacd0b85a97d-4843efa9d62mr2681887f8f.5.1788166360562; Mon, 31 Aug 2026 01:52:40 -0700 (PDT) Received: from SVR.localdomain ([185.179.67.170]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-484397f33fesm7786600f8f.15.2026.08.31.01.52.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 31 Aug 2026 01:52:40 -0700 (PDT) Sender: Semih Baskan From: Semih Baskan To: florian.fainelli@broadcom.com, jonas.gorski@gmail.com, andrew@lunn.ch, olteanv@gmail.com, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com Cc: vladimir.oltean@nxp.com, horms@kernel.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH net v3 2/2] net: dsa: b53: offload 8021q uppers on standalone ports Date: Mon, 31 Aug 2026 11:52:17 +0300 Message-ID: <20260831085217.391-3-strst.gs@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260831085217.391-1-strst.gs@gmail.com> References: <20260831085217.391-1-strst.gs@gmail.com> 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 Content-Type: text/plain; charset="utf-8" b53 keeps the hardware VID lookup enabled at all times: b53_switch_alloc() sets dev->vlan_enabled and nothing ever clears it. On bcm5301x switches, a tagged frame whose VID is absent from the VLAN table is forwarded only toward the IMP0 management port, which the in-tree topology leaves disabled, so it never reaches the CPU. Jonas Gorski reports that other family members still deliver such frames, older BCM5325/5365 by forwarding them and BCM63268/BCM53115 to the CPU only, and the entries this patch programs are correct on BCM63268 and BCM53115 as well. Disabling the lookup is not an option either, because that moves the ARL to shared VLAN learning, where ARL operations force VID 0 and the hardware table drifts away from the bridge fdb. Commit 06cfb2df7eb0 ("net: dsa: don't advertise 'rx-vlan-filter' when not needed") stopped advertising NETIF_F_HW_VLAN_CTAG_FILTER on ports that do not offload a VLAN-aware bridge, so creating an 8021q upper on a standalone port no longer reaches .ndo_vlan_rx_add_vid and the VID is never offloaded. Commit f089652b6b16 ("net: dsa: b53: do not program vlans when vlan filtering is off") then made .port_vlan_add skip the hardware write while dev->vlan_filtering is false, which it is for a standalone port. Together they leave standalone ports unable to receive their own tagged traffic. This breaks a common configuration, a VLAN-tagged WAN for a PPPoE ISP. The PADI leaves the port correctly tagged, the concentrator answers, and the switch discards the tagged PADO, so the session never establishes. The breakage reached users when OpenWrt 23.05 shipped v5.15 and is still reproducible. Take the new needs_standalone_vlan_offload opt-in so DSA reports upper VIDs again, and program VLAN entries that carry a standalone port even while not filtering. Only the standalone members and the CPU port are written to such an entry. A VID used by both an 8021q upper and a bridge VLAN therefore does not gain the bridged ports as members, so bridge VLANs keep having no effect while filtering is off, which is what Documentation/networking/switchdev.rst requires and what that commit implements. The PVID register writes stay gated on vlan_filtering for the same reason. BCM5325 and BCM5365 stay out of the opt-in, which is why the flag is set after chip detection rather than in b53_switch_alloc(). Both forward a table miss, so a standalone port there already receives its uppers' traffic with no entry. Their tables also hold only 16 and 256 VLANs, and with the feature bit back on b53_vlan_prepare() would refuse any upper whose VID lies beyond the table, an interface that works today. b53_configure_vlan() used to restore entries only while filtering, so restore the standalone ones there as well, otherwise the next b53_apply_config() wipes them. Bridge join and leave rewrite the entries of the moved port, because its standalone state is part of the masking decision: joining removes the port from its uppers' entries, and leaving adds it back, including uppers that were created while the port was still bridged. When the last standalone member leaves a VID, the entry is written back empty, so deleting an upper or bridging its port returns the hardware to the state it had before the upper existed. A tagged upper on BCM7278 port 7 now fails at creation: b53_vlan_prepare() rejects tagged VLANs on that port, which cannot receive tagged frames. Previously the ndo was never called, so the upper was silently created broken. Measured on an Asus RT-N18U (BCM53011 rev 5) against a peer device. A probe over an 8021q upper on the standalone WAN port received 0 frames before and 7 of 7 after, with the outbound direction as a positive control and vlan_filtering staying 0 throughout. A static fdb entry with VID 100 survived a vlan_filtering 1->0 toggle in hardware, since dev->vlan_enabled is never touched and the ARL keeps using independent VLAN learning. The PPPoE session establishes. Fixes: 06cfb2df7eb0 ("net: dsa: don't advertise 'rx-vlan-filter' when not n= eeded") Cc: stable@vger.kernel.org Signed-off-by: Semih Baskan --- drivers/net/dsa/b53/b53_common.c | 119 ++++++++++++++++++++++++++----- 1 file changed, 101 insertions(+), 18 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_com= mon.c index 0880310c9ce3..b57c0bdacb27 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -898,10 +898,52 @@ static bool b53_vlan_port_may_join_untagged(struct ds= a_switch *ds, int port) return dp->bridge =3D=3D NULL; } =20 +static bool b53_vlan_hw_entry(struct dsa_switch *ds, const struct b53_vlan= *vl, + struct b53_vlan *hw) +{ + struct b53_device *dev =3D ds->priv; + bool standalone =3D false; + struct dsa_port *dp; + unsigned int port; + + *hw =3D *vl; + + if (dev->vlan_filtering) + return true; + + hw->members =3D 0; + hw->untag =3D 0; + + b53_for_each_port(dev, port) { + if (!(vl->members & BIT(port))) + continue; + + dp =3D dsa_to_port(ds, port); + + if (!dsa_port_is_cpu(dp)) { + if (dp->bridge) + continue; + + standalone =3D true; + } + + hw->members |=3D BIT(port); + hw->untag |=3D vl->untag & BIT(port); + } + + if (!standalone) { + hw->members =3D 0; + hw->untag =3D 0; + } + + return standalone; +} + int b53_configure_vlan(struct dsa_switch *ds) { struct b53_device *dev =3D ds->priv; struct b53_vlan vl =3D { 0 }; + struct b53_vlan hw; struct b53_vlan *v; int i, def_vid; u16 vid; @@ -937,20 +979,23 @@ int b53_configure_vlan(struct dsa_switch *ds) } b53_set_vlan_entry(dev, def_vid, &vl); =20 - if (dev->vlan_filtering) { - /* Upon initial call we have not set-up any VLANs, but upon - * system resume, we need to restore all VLAN entries. - */ - for (vid =3D def_vid + 1; vid < dev->num_vlans; vid++) { - v =3D &dev->vlans[vid]; + /* Upon initial call we have not set-up any VLANs, but upon + * system resume, we need to restore all VLAN entries. + */ + for (vid =3D def_vid + 1; vid < dev->num_vlans; vid++) { + v =3D &dev->vlans[vid]; =20 - if (!v->members) - continue; + if (!v->members) + continue; =20 - b53_set_vlan_entry(dev, vid, v); - b53_fast_age_vlan(dev, vid); - } + if (!b53_vlan_hw_entry(ds, v, &hw)) + continue; + + b53_set_vlan_entry(dev, vid, &hw); + b53_fast_age_vlan(dev, vid); + } =20 + if (dev->vlan_filtering) { b53_for_each_port(dev, i) { if (!dsa_is_cpu_port(ds, i)) b53_write16(dev, B53_VLAN_PAGE, @@ -1720,6 +1765,7 @@ int b53_vlan_add(struct dsa_switch *ds, int port, struct b53_device *dev =3D ds->priv; bool untagged =3D vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; bool pvid =3D vlan->flags & BRIDGE_VLAN_INFO_PVID; + struct b53_vlan hw; struct b53_vlan *vl; u16 old_pvid, new_pvid; int err; @@ -1751,13 +1797,14 @@ int b53_vlan_add(struct dsa_switch *ds, int port, else vl->untag &=3D ~BIT(port); =20 - if (!dev->vlan_filtering) + if (!b53_vlan_hw_entry(ds, vl, &hw)) return 0; =20 - b53_set_vlan_entry(dev, vlan->vid, vl); + b53_set_vlan_entry(dev, vlan->vid, &hw); b53_fast_age_vlan(dev, vlan->vid); =20 - if (!dsa_is_cpu_port(ds, port) && new_pvid !=3D old_pvid) { + if (dev->vlan_filtering && + !dsa_is_cpu_port(ds, port) && new_pvid !=3D old_pvid) { b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port), new_pvid); b53_fast_age_vlan(dev, old_pvid); @@ -1772,7 +1819,9 @@ int b53_vlan_del(struct dsa_switch *ds, int port, { struct b53_device *dev =3D ds->priv; bool untagged =3D vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED; + struct b53_vlan hw; struct b53_vlan *vl; + bool needs_hw; u16 pvid; =20 if (vlan->vid =3D=3D 0) @@ -1782,6 +1831,8 @@ int b53_vlan_del(struct dsa_switch *ds, int port, =20 vl =3D &dev->vlans[vlan->vid]; =20 + needs_hw =3D b53_vlan_hw_entry(ds, vl, &hw); + vl->members &=3D ~BIT(port); =20 if (pvid =3D=3D vlan->vid) @@ -1791,14 +1842,18 @@ int b53_vlan_del(struct dsa_switch *ds, int port, if (untagged && !b53_vlan_port_needs_forced_tagged(ds, port)) vl->untag &=3D ~(BIT(port)); =20 - if (!dev->vlan_filtering) + if (!needs_hw) return 0; =20 - b53_set_vlan_entry(dev, vlan->vid, vl); + b53_vlan_hw_entry(ds, vl, &hw); + b53_set_vlan_entry(dev, vlan->vid, &hw); b53_fast_age_vlan(dev, vlan->vid); =20 - b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port), pvid); - b53_fast_age_vlan(dev, pvid); + if (dev->vlan_filtering) { + b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port), + pvid); + b53_fast_age_vlan(dev, pvid); + } =20 return 0; } @@ -2261,6 +2316,28 @@ int b53_mdb_del(struct dsa_switch *ds, int port, } EXPORT_SYMBOL(b53_mdb_del); =20 +static void b53_standalone_vlan_resync(struct dsa_switch *ds, int port) +{ + struct b53_device *dev =3D ds->priv; + struct b53_vlan hw; + struct b53_vlan *vl; + u16 vid; + + if (dev->vlan_filtering) + return; + + for (vid =3D b53_default_pvid(dev) + 1; vid < dev->num_vlans; vid++) { + vl =3D &dev->vlans[vid]; + + if (!(vl->members & BIT(port))) + continue; + + b53_vlan_hw_entry(ds, vl, &hw); + b53_set_vlan_entry(dev, vid, &hw); + b53_fast_age_vlan(dev, vid); + } +} + int b53_br_join(struct dsa_switch *ds, int port, struct dsa_bridge bridge, bool *tx_fwd_offload, struct netlink_ext_ack *extack) { @@ -2324,6 +2401,8 @@ int b53_br_join(struct dsa_switch *ds, int port, stru= ct dsa_bridge bridge, b53_write16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), pvlan); dev->ports[port].vlan_ctl_mask =3D pvlan; =20 + b53_standalone_vlan_resync(ds, port); + return 0; } EXPORT_SYMBOL(b53_br_join); @@ -2376,6 +2455,8 @@ void b53_br_leave(struct dsa_switch *ds, int port, st= ruct dsa_bridge bridge) vl->members |=3D BIT(port); b53_set_vlan_entry(dev, pvid, vl); } + + b53_standalone_vlan_resync(ds, port); } EXPORT_SYMBOL(b53_br_leave); =20 @@ -3172,6 +3253,8 @@ static int b53_switch_init(struct b53_device *dev) if (!dev->vlans) return -ENOMEM; =20 + dev->ds->needs_standalone_vlan_offload =3D !is5325(dev) && !is5365(dev); + dev->reset_gpio =3D b53_switch_get_reset_gpio(dev); =20 if (PTR_ERR(dev->reset_gpio) =3D=3D -EPROBE_DEFER) --=20 2.53.0.windows.1