net: dsa: rtl8366: Properly clear member config
authorLinus Walleij <linus.walleij@linaro.org>
Sat, 5 Sep 2020 10:32:33 +0000 (12:32 +0200)
committerJakub Kicinski <kuba@kernel.org>
Sun, 6 Sep 2020 19:32:07 +0000 (12:32 -0700)
When removing a port from a VLAN we are just erasing the
member config for the VLAN, which is wrong: other ports
can be using it.

Just mask off the port and only zero out the rest of the
member config once ports using of the VLAN are removed
from it.

Reported-by: Florian Fainelli <f.fainelli@gmail.com>
Fixes: d8652956cf37 ("net: dsa: realtek-smi: Add Realtek SMI driver")
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/dsa/rtl8366.c

index 8f40fbf70a82b83d33931e1ccc7fc3eadbf6e942..a8c5a934c3d308ac4ee77e65f22d7b07b2756a6b 100644 (file)
@@ -452,13 +452,19 @@ int rtl8366_vlan_del(struct dsa_switch *ds, int port,
                                return ret;
 
                        if (vid == vlanmc.vid) {
-                               /* clear VLAN member configurations */
-                               vlanmc.vid = 0;
-                               vlanmc.priority = 0;
-                               vlanmc.member = 0;
-                               vlanmc.untag = 0;
-                               vlanmc.fid = 0;
-
+                               /* Remove this port from the VLAN */
+                               vlanmc.member &= ~BIT(port);
+                               vlanmc.untag &= ~BIT(port);
+                               /*
+                                * If no ports are members of this VLAN
+                                * anymore then clear the whole member
+                                * config so it can be reused.
+                                */
+                               if (!vlanmc.member && vlanmc.untag) {
+                                       vlanmc.vid = 0;
+                                       vlanmc.priority = 0;
+                                       vlanmc.fid = 0;
+                               }
                                ret = smi->ops->set_vlan_mc(smi, i, &vlanmc);
                                if (ret) {
                                        dev_err(smi->dev,