Author: loos
Date: Thu Jul 27 02:38:53 2017
New Revision: 321602
URL: https://svnweb.freebsd.org/changeset/base/321602

Log:
  Fix the port vlan support in e6000 based switches.
  
  Reduce the use of local copies of switch register data.
  
  The switch now works with the upstream dsa node (i.e. the upstream DTS).
  
  Tested on:    ClearFog Pro (88E6176), SG-3100 (88E6141)
  Sponsored by: Rubicon Communications, LLC (Netgate)

Modified:
  head/sys/dev/etherswitch/e6000sw/e6000sw.c
  head/sys/dev/etherswitch/e6000sw/e6000swreg.h

Modified: head/sys/dev/etherswitch/e6000sw/e6000sw.c
==============================================================================
--- head/sys/dev/etherswitch/e6000sw/e6000sw.c  Thu Jul 27 00:30:13 2017        
(r321601)
+++ head/sys/dev/etherswitch/e6000sw/e6000sw.c  Thu Jul 27 02:38:53 2017        
(r321602)
@@ -72,6 +72,7 @@ typedef struct e6000sw_softc {
        struct proc             *kproc;
 
        uint32_t                swid;
+       uint32_t                vlan_mode;
        uint32_t                cpuports_mask;
        uint32_t                fixed_mask;
        uint32_t                fixed25_mask;
@@ -80,15 +81,11 @@ typedef struct e6000sw_softc {
        int                     sw_addr;
        int                     num_ports;
        boolean_t               multi_chip;
-
-       int                     vid[E6000SW_NUM_VGROUPS];
-       int                     members[E6000SW_NUM_VGROUPS];
-       int                     vgroup[E6000SW_MAX_PORTS];
 } e6000sw_softc_t;
 
 static etherswitch_info_t etherswitch_info = {
        .es_nports =            0,
-       .es_nvlangroups =       E6000SW_NUM_VGROUPS,
+       .es_nvlangroups =       0,
        .es_vlan_caps =         ETHERSWITCH_VLAN_PORT,
        .es_name =              "Marvell 6000 series switch"
 };
@@ -263,15 +260,14 @@ e6000sw_probe(device_t dev)
 }
 
 static int
-e6000sw_parse_child_fdt(e6000sw_softc_t *sc, phandle_t child, int *pport,
-    int *pvlangroup)
+e6000sw_parse_child_fdt(e6000sw_softc_t *sc, phandle_t child, int *pport)
 {
        char *name, *portlabel;
        int speed;
        phandle_t fixed_link;
-       uint32_t port, vlangroup;
+       uint32_t port;
 
-       if (pport == NULL || pvlangroup == NULL)
+       if (pport == NULL)
                return (ENXIO);
 
        if (OF_getencprop(child, "reg", (void *)&port, sizeof(port)) < 0)
@@ -280,15 +276,6 @@ e6000sw_parse_child_fdt(e6000sw_softc_t *sc, phandle_t
                return (ENXIO);
        *pport = port;
 
-       if (OF_getencprop(child, "vlangroup", (void *)&vlangroup,
-           sizeof(vlangroup)) > 0) {
-               if (vlangroup >= E6000SW_NUM_VGROUPS)
-                       return (ENXIO);
-               *pvlangroup = vlangroup;
-       } else {
-               *pvlangroup = -1;
-       }
-
        if (OF_getprop_alloc(child, "label", 1, (void **)&portlabel) > 0) {
                if (strncmp(portlabel, "cpu", 3) == 0) {
                        device_printf(sc->dev, "CPU port at %d\n", port);
@@ -364,11 +351,9 @@ e6000sw_attach_miibus(e6000sw_softc_t *sc, int port)
 static int
 e6000sw_attach(device_t dev)
 {
-       etherswitch_vlangroup_t vg;
        e6000sw_softc_t *sc;
        phandle_t child;
-       int err, port, vlangroup;
-       int member_ports[E6000SW_NUM_VGROUPS];
+       int err, port;
        uint32_t reg;
 
        err = 0;
@@ -383,18 +368,14 @@ e6000sw_attach(device_t dev)
 
        E6000SW_LOCK(sc);
        e6000sw_setup(dev, sc);
-       bzero(member_ports, sizeof(member_ports));
 
        for (child = OF_child(sc->node); child != 0; child = OF_peer(child)) {
-               err = e6000sw_parse_child_fdt(sc, child, &port, &vlangroup);
+               err = e6000sw_parse_child_fdt(sc, child, &port);
                if (err != 0) {
                        device_printf(sc->dev, "failed to parse DTS\n");
                        goto out_fail;
                }
 
-               if (vlangroup != -1)
-                       member_ports[vlangroup] |= (1 << port);
-
                /* Port is in use. */
                sc->ports_mask |= (1 << port);
 
@@ -440,21 +421,9 @@ e6000sw_attach(device_t dev)
        }
 
        etherswitch_info.es_nports = sc->num_ports;
-       for (port = 0; port < sc->num_ports; port++)
-               sc->vgroup[port] = E6000SW_PORT_NO_VGROUP;
 
-       /* Set VLAN configuration */
+       /* Default to port vlan. */
        e6000sw_port_vlan_conf(sc);
-
-       /* Set vlangroups */
-       for (vlangroup = 0; vlangroup < E6000SW_NUM_VGROUPS; vlangroup++)
-               if (member_ports[vlangroup] != 0) {
-                       vg.es_vlangroup = vg.es_vid = vlangroup;
-                       vg.es_member_ports = vg.es_untagged_ports =
-                           member_ports[vlangroup];
-                       e6000sw_setvgroup(dev, &vg);
-               }
-
        E6000SW_UNLOCK(sc);
 
        bus_generic_probe(dev);
@@ -597,12 +566,14 @@ e6000sw_getinfo(device_t dev)
 }
 
 static int
-e6000sw_getconf(device_t dev __unused, etherswitch_conf_t *conf)
+e6000sw_getconf(device_t dev, etherswitch_conf_t *conf)
 {
+       struct e6000sw_softc *sc;
 
        /* Return the VLAN mode. */
+       sc = device_get_softc(dev);
        conf->cmd = ETHERSWITCH_CONF_VLAN_MODE;
-       conf->vlan_mode = ETHERSWITCH_VLAN_PORT;
+       conf->vlan_mode = sc->vlan_mode;
 
        return (0);
 }
@@ -808,67 +779,79 @@ e6000sw_getvgroup_wrapper(device_t dev, etherswitch_vl
 }
 
 static __inline void
-e6000sw_flush_port(e6000sw_softc_t *sc, int port)
+e6000sw_port_vlan_assign(e6000sw_softc_t *sc, int port, uint32_t fid,
+    uint32_t members)
 {
        uint32_t reg;
 
        reg = e6000sw_readreg(sc, REG_PORT(port), PORT_VLAN_MAP);
        reg &= ~PORT_VLAN_MAP_TABLE_MASK;
        reg &= ~PORT_VLAN_MAP_FID_MASK;
+       reg |= members & PORT_VLAN_MAP_TABLE_MASK & ~(1 << port);
+       reg |= (fid << PORT_VLAN_MAP_FID) & PORT_VLAN_MAP_FID_MASK;
        e6000sw_writereg(sc, REG_PORT(port), PORT_VLAN_MAP, reg);
-       if (sc->vgroup[port] != E6000SW_PORT_NO_VGROUP) {
-               /*
-                * If port belonged somewhere, owner-group
-                * should have its entry removed.
-                */
-               sc->members[sc->vgroup[port]] &= ~(1 << port);
-               sc->vgroup[port] = E6000SW_PORT_NO_VGROUP;
-       }
+       reg = e6000sw_readreg(sc, REG_PORT(port), PORT_CONTROL_1);
+       reg &= ~PORT_CONTROL_1_FID_MASK;
+       reg |= (fid >> 4) & PORT_CONTROL_1_FID_MASK;
+       e6000sw_writereg(sc, REG_PORT(port), PORT_CONTROL_1, reg);
 }
 
-static __inline void
-e6000sw_port_assign_vgroup(e6000sw_softc_t *sc, int port, int fid, int vgroup,
-    int members)
+static int
+e6000sw_set_port_vlan(e6000sw_softc_t *sc, etherswitch_vlangroup_t *vg)
 {
-       uint32_t reg;
+       uint32_t port;
 
-       reg = e6000sw_readreg(sc, REG_PORT(port), PORT_VLAN_MAP);
-       reg &= ~PORT_VLAN_MAP_TABLE_MASK;
-       reg &= ~PORT_VLAN_MAP_FID_MASK;
-       reg |= members & ~(1 << port);
-       reg |= (fid << PORT_VLAN_MAP_FID) & PORT_VLAN_MAP_FID_MASK;
-       e6000sw_writereg(sc, REG_PORT(port), PORT_VLAN_MAP, reg);
-       sc->vgroup[port] = vgroup;
+       port = vg->es_vlangroup;
+       if (port > sc->num_ports)
+               return (EINVAL);
+
+       if (vg->es_member_ports != vg->es_untagged_ports) {
+               device_printf(sc->dev, "Tagged ports not supported.\n");
+               return (EINVAL);
+       }
+
+       e6000sw_port_vlan_assign(sc, port, port + 1, vg->es_untagged_ports);
+       vg->es_vid = port | ETHERSWITCH_VID_VALID;
+
+       return (0);
 }
 
 static int
 e6000sw_setvgroup(device_t dev, etherswitch_vlangroup_t *vg)
 {
        e6000sw_softc_t *sc;
-       int port, fid;
 
        sc = device_get_softc(dev);
        E6000SW_LOCK_ASSERT(sc, SA_XLOCKED);
 
-       if (vg->es_vlangroup >= E6000SW_NUM_VGROUPS)
+       if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT)
+               return (e6000sw_set_port_vlan(sc, vg));
+
+       return (EINVAL);
+}
+
+static int
+e6000sw_get_port_vlan(e6000sw_softc_t *sc, etherswitch_vlangroup_t *vg)
+{
+       uint32_t port, reg;
+
+       port = vg->es_vlangroup;
+       if (port > sc->num_ports)
                return (EINVAL);
-       if (vg->es_member_ports != vg->es_untagged_ports) {
-               device_printf(dev, "Tagged ports not supported.\n");
-               return (EINVAL);
-       }
 
-       vg->es_untagged_ports &= PORT_VLAN_MAP_TABLE_MASK;
-       fid = vg->es_vlangroup + 1;
-       for (port = 0; port < sc->num_ports; port++) {
-               if ((sc->members[sc->vgroup[port]] & (1 << port)))
-                       e6000sw_flush_port(sc, port);
-               if (vg->es_untagged_ports & (1 << port))
-                       e6000sw_port_assign_vgroup(sc, port, fid,
-                           vg->es_vlangroup, vg->es_untagged_ports);
+       if (!e6000sw_is_portenabled(sc, port)) {
+               vg->es_vid = port;
+               return (0);
        }
-       sc->vid[vg->es_vlangroup] = vg->es_vid;
-       sc->members[vg->es_vlangroup] = vg->es_untagged_ports;
 
+       reg = e6000sw_readreg(sc, REG_PORT(port), PORT_VLAN_MAP);
+       vg->es_untagged_ports = vg->es_member_ports =
+           reg & PORT_VLAN_MAP_TABLE_MASK;
+       vg->es_vid = port | ETHERSWITCH_VID_VALID;
+       vg->es_fid = (reg & PORT_VLAN_MAP_FID_MASK) >> PORT_VLAN_MAP_FID;
+       reg = e6000sw_readreg(sc, REG_PORT(port), PORT_CONTROL_1);
+       vg->es_fid |= (reg & PORT_CONTROL_1_FID_MASK) << 4;
+
        return (0);
 }
 
@@ -880,14 +863,10 @@ e6000sw_getvgroup(device_t dev, etherswitch_vlangroup_
        sc = device_get_softc(dev);
        E6000SW_LOCK_ASSERT(sc, SA_XLOCKED);
 
-       if (vg->es_vlangroup >= E6000SW_NUM_VGROUPS)
-               return (EINVAL);
-       vg->es_untagged_ports = vg->es_member_ports =
-           sc->members[vg->es_vlangroup];
-       if (vg->es_untagged_ports != 0)
-               vg->es_vid = ETHERSWITCH_VID_VALID;
+       if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT)
+               return (e6000sw_get_port_vlan(sc, vg));
 
-       return (0);
+       return (EINVAL);
 }
 
 static __inline struct mii_data*
@@ -1172,10 +1151,9 @@ e6000sw_setup(device_t dev, e6000sw_softc_t *sc)
 static void
 e6000sw_port_vlan_conf(e6000sw_softc_t *sc)
 {
-       int port, ret;
-       device_t dev;
+       int i, port, ret;
+       uint32_t members;
 
-       dev = sc->dev;
        /* Disable all ports */
        for (port = 0; port < sc->num_ports; port++) {
                ret = e6000sw_readreg(sc, REG_PORT(port), PORT_CONTROL);
@@ -1207,8 +1185,23 @@ e6000sw_port_vlan_conf(e6000sw_softc_t *sc)
                if (!e6000sw_is_portenabled(sc, port))
                        continue;
                ret = e6000sw_readreg(sc, REG_PORT(port), PORT_CONTROL);
-               e6000sw_writereg(sc, REG_PORT(port), PORT_CONTROL, (ret |
-                   PORT_CONTROL_ENABLE));
+               e6000sw_writereg(sc, REG_PORT(port), PORT_CONTROL,
+                   (ret | PORT_CONTROL_ENABLE));
+       }
+
+       /* Set VLAN mode. */
+       sc->vlan_mode = ETHERSWITCH_VLAN_PORT;
+       etherswitch_info.es_nvlangroups = sc->num_ports;
+       for (port = 0; port < sc->num_ports; port++) {
+               members = 0;
+               if (e6000sw_is_portenabled(sc, port)) {
+                       for (i = 0; i < sc->num_ports; i++) {
+                               if (i == port || !e6000sw_is_portenabled(sc, i))
+                                       continue;
+                               members |= (1 << i);
+                       }
+               }
+               e6000sw_port_vlan_assign(sc, port, port + 1, members);
        }
 }
 

Modified: head/sys/dev/etherswitch/e6000sw/e6000swreg.h
==============================================================================
--- head/sys/dev/etherswitch/e6000sw/e6000swreg.h       Thu Jul 27 00:30:13 
2017        (r321601)
+++ head/sys/dev/etherswitch/e6000sw/e6000swreg.h       Thu Jul 27 02:38:53 
2017        (r321602)
@@ -87,6 +87,7 @@ struct atu_opt {
 #define SWITCH_ID                      0x3
 #define PORT_CONTROL                   0x4
 #define PORT_CONTROL_1                 0x5
+#define        PORT_CONTROL_1_FID_MASK         0xf
 #define PORT_VLAN_MAP                  0x6
 #define PORT_VID                       0x7
 #define PORT_ASSOCIATION_VECTOR                0xb
@@ -104,6 +105,7 @@ struct atu_opt {
 #define PORT_VLAN_MAP_TABLE_MASK       0x7f
 #define PORT_VLAN_MAP_FID              12
 #define PORT_VLAN_MAP_FID_MASK         0xf000
+
 /*
  * Switch Global Register 1 accessed via REG_GLOBAL_ADDR
  */
@@ -201,9 +203,7 @@ struct atu_opt {
 #define SCR_AND_MISC_DATA_CFG_MASK     0xf0
 
 #define E6000SW_NUM_PHY_REGS           29
-#define E6000SW_NUM_VGROUPS            8
-#define E6000SW_MAX_PORTS              10
-#define E6000SW_PORT_NO_VGROUP         -1
+#define        E6000SW_MAX_PORTS               8
 #define E6000SW_DEFAULT_AGETIME                20
 #define E6000SW_RETRIES                        100
 #define E6000SW_SMI_TIMEOUT            16
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to