@@ -1618,6 +1618,38 @@ static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
return err;
}
+static bool mv88e6xxx_port_offloads_vlans(struct dsa_switch *ds, int port)
+{
+ struct dsa_port *dp = dsa_to_port(ds, port);
+ struct mv88e6xxx_chip *chip = ds->priv;
+
+ if (!mv88e6xxx_max_vid(chip))
+ return false;
+
+ /* There are roughly two scenarios in which VLANs may be added
+ * to a non-bridged port:
+ * (a) (b) br0
+ * /
+ * vlan1 bond0
+ * / / \
+ * swp0 swp0 swp1
+ *
+ * Either (a) a VLAN upper is added to a non-bridged port; or
+ * (b) a port is an indirect lower to a bridge via some
+ * stacked interface that is not offloaded, e.g. a bond in
+ * broadcast mode.
+ *
+ * We still get a callback in these cases as there are other
+ * DSA devices which cannot control VLAN filtering per
+ * port. mv88e6xxx is not one of those, so we can safely
+ * fallback to software VLANs.
+ */
+ if (dsa_is_user_port(ds, port) && !dp->bridge_dev)
+ return false;
+
+ return true;
+}
+
static int
mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan)
@@ -1625,9 +1657,6 @@ mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
struct mv88e6xxx_chip *chip = ds->priv;
int err;
- if (!mv88e6xxx_max_vid(chip))
- return -EOPNOTSUPP;
-
/* If the requested port doesn't belong to the same bridge as the VLAN
* members, do not support it (yet) and fallback to software VLAN.
*/
@@ -1993,6 +2022,9 @@ static int mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
u8 member;
int err;
+ if (!mv88e6xxx_port_offloads_vlans(ds, port))
+ return -EOPNOTSUPP;
+
err = mv88e6xxx_port_vlan_prepare(ds, port, vlan);
if (err)
return err;
@@ -2081,7 +2113,7 @@ static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
int err = 0;
u16 pvid;
- if (!mv88e6xxx_max_vid(chip))
+ if (!mv88e6xxx_port_offloads_vlans(ds, port))
return -EOPNOTSUPP;
mv88e6xxx_reg_lock(chip);
Standalone ports always have VLAN filtering (Port Control 2, 802.1Q Mode) disabled. So adding VIDs for any VLAN uppers to the VTU does not make one bit of difference on the ingress filtering, the CPU will still receive traffic from all VLANs. It does however needlessly consume a precious global resource, namely a VID. Therefore, we refine the requirement for accepting a VLAN on a port by mandating that the port must be offloading a bridge, in which case the device will actually make use of the filtering. Fixes: 061f6a505ac3 ("net: dsa: Add ndo_vlan_rx_{add, kill}_vid implementation") Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com> --- drivers/net/dsa/mv88e6xxx/chip.c | 40 ++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-)