mvsw61xx: track and set per-VLAN port state in STU
authorLuka Perkov <luka@openwrt.org>
Sun, 11 Jan 2015 17:20:16 +0000 (17:20 +0000)
committerLuka Perkov <luka@openwrt.org>
Sun, 11 Jan 2015 17:20:16 +0000 (17:20 +0000)
Since the driver doesn't know anything about (M)STP
we just hard-set the ports to be enabled if they are
part of the VLAN.

Signed-off-by: Claudio Leite <leitec@staticky.com>
SVN-Revision: 43938

target/linux/generic/files/drivers/net/phy/mvsw61xx.c
target/linux/generic/files/drivers/net/phy/mvsw61xx.h

index 7ddb13e0d44da4f69e6422bb55235e490f2e8fce..116f6cf5d65dccd2bc73884229ce575747abd3f1 100644 (file)
@@ -2,6 +2,7 @@
  * Marvell 88E61xx switch driver
  *
  * Copyright (c) 2014 Claudio Leite <leitec@staticky.com>
+ * Copyright (c) 2014 Nikita Nazarenko <nnazarenko@radiofid.com>
  *
  * Based on code (c) 2008 Felix Fietkau <nbd@openwrt.org>
  *
@@ -27,6 +28,7 @@
 
 MODULE_DESCRIPTION("Marvell 88E61xx Switch driver");
 MODULE_AUTHOR("Claudio Leite <leitec@staticky.com>");
+MODULE_AUTHOR("Nikita Nazarenko <nnazarenko@radiofid.com>");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:mvsw61xx");
 
@@ -333,6 +335,7 @@ static int mvsw61xx_set_vlan_ports(struct switch_dev *dev,
 
        state->vlans[vno].mask = 0;
        state->vlans[vno].port_mode = 0;
+       state->vlans[vno].port_sstate = 0;
 
        if(state->vlans[vno].vid == 0)
                state->vlans[vno].vid = vno;
@@ -348,6 +351,8 @@ static int mvsw61xx_set_vlan_ports(struct switch_dev *dev,
                        mode = MV_VTUCTL_EGRESS_UNTAGGED;
 
                state->vlans[vno].port_mode |= mode << (pno * 4);
+               state->vlans[vno].port_sstate |=
+                       MV_STUCTL_STATE_FORWARDING << (pno * 4 + 2);
        }
 
        /*
@@ -447,7 +452,7 @@ static int mvsw61xx_set_enable_vlan(struct switch_dev *dev,
 static int mvsw61xx_vtu_program(struct switch_dev *dev)
 {
        struct mvsw61xx_state *state = get_state(dev);
-       u16 v1, v2;
+       u16 v1, v2, s1, s2;
        int i;
 
        /* Flush */
@@ -466,14 +471,32 @@ static int mvsw61xx_vtu_program(struct switch_dev *dev)
                mvsw61xx_wait_mask_s(dev, MV_GLOBALREG(VTU_OP),
                                MV_VTUOP_INPROGRESS, 0);
 
-               sw16(dev, MV_GLOBALREG(VTU_VID),
-                               MV_VTU_VID_VALID | state->vlans[i].vid);
+               /* Write per-VLAN port state into STU */
+               s1 = (u16) (state->vlans[i].port_sstate & 0xffff);
+               s2 = (u16) ((state->vlans[i].port_sstate >> 16) & 0xffff);
+
+               sw16(dev, MV_GLOBALREG(VTU_VID), MV_VTU_VID_VALID);
+               sw16(dev, MV_GLOBALREG(VTU_SID), i);
+               sw16(dev, MV_GLOBALREG(VTU_DATA1), s1);
+               sw16(dev, MV_GLOBALREG(VTU_DATA2), s2);
+               sw16(dev, MV_GLOBALREG(VTU_DATA3), 0);
+
+               sw16(dev, MV_GLOBALREG(VTU_OP),
+                               MV_VTUOP_INPROGRESS | MV_VTUOP_STULOAD);
+               mvsw61xx_wait_mask_s(dev, MV_GLOBALREG(VTU_OP),
+                               MV_VTUOP_INPROGRESS, 0);
 
-               v1 = (u16)(state->vlans[i].port_mode & 0xffff);
-               v2 = (u16)((state->vlans[i].port_mode >> 16) & 0xffff);
+               /* Write VLAN information into VTU */
+               v1 = (u16) (state->vlans[i].port_mode & 0xffff);
+               v2 = (u16) ((state->vlans[i].port_mode >> 16) & 0xffff);
 
+               sw16(dev, MV_GLOBALREG(VTU_VID),
+                               MV_VTU_VID_VALID | state->vlans[i].vid);
+               sw16(dev, MV_GLOBALREG(VTU_SID), i);
+               sw16(dev, MV_GLOBALREG(VTU_FID), 0);
                sw16(dev, MV_GLOBALREG(VTU_DATA1), v1);
                sw16(dev, MV_GLOBALREG(VTU_DATA2), v2);
+               sw16(dev, MV_GLOBALREG(VTU_DATA3), 0);
 
                sw16(dev, MV_GLOBALREG(VTU_OP),
                                MV_VTUOP_INPROGRESS | MV_VTUOP_LOAD);
@@ -514,8 +537,6 @@ static int mvsw61xx_update_state(struct switch_dev *dev)
        if (!state->registered)
                return -EINVAL;
 
-       mvsw61xx_vtu_program(dev);
-
        /*
         * Set 802.1q-only mode if vlan_enabled is true.
         *
@@ -568,6 +589,8 @@ static int mvsw61xx_update_state(struct switch_dev *dev)
                sw16(dev, MV_PORTREG(CONTROL2, i), reg);
        }
 
+       mvsw61xx_vtu_program(dev);
+
        return 0;
 }
 
@@ -615,6 +638,7 @@ static int mvsw61xx_reset(struct switch_dev *dev)
                state->vlans[i].mask = 0;
                state->vlans[i].vid = 0;
                state->vlans[i].port_mode = 0;
+               state->vlans[i].port_sstate = 0;
        }
 
        state->vlan_enabled = 0;
index 8bd6f9a9049efadeaf7283b2a0ef97b92d236661..61e134ce91cb29076aac9baf73e6b86e27731502 100644 (file)
@@ -249,6 +249,7 @@ struct mvsw61xx_state {
                u16 mask;
                u16 vid;
                u32 port_mode;
+               u32 port_sstate;
        } vlans[MV_VLANS];
 
        char buf[128];