Author: loos
Date: Tue Jun 13 00:42:23 2017
New Revision: 319886
URL: https://svnweb.freebsd.org/changeset/base/319886

Log:
  Add the initial support for the Marvell 88E6141 and 88E6341 switches.
  
  Right now the driver only supports port VLANs, so make sure
  etherswitch_getinfo() return the proper switch capabilities.
  
  Handle the cases where not all ports are in use (that will also require
  etherswitch cooperation).
  
  Sponsored by: Rubicon Communications, LLC (Netgate)

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

Modified: head/sys/dev/etherswitch/e6000sw/e6000sw.c
==============================================================================
--- head/sys/dev/etherswitch/e6000sw/e6000sw.c  Tue Jun 13 00:31:16 2017        
(r319885)
+++ head/sys/dev/etherswitch/e6000sw/e6000sw.c  Tue Jun 13 00:42:23 2017        
(r319886)
@@ -73,6 +73,8 @@ typedef struct e6000sw_softc {
 
        uint32_t                cpuports_mask;
        uint32_t                fixed_mask;
+       uint32_t                ports_mask;
+       int                     phy_base;
        int                     sw_addr;
        int                     num_ports;
        boolean_t               multi_chip;
@@ -85,6 +87,7 @@ typedef struct e6000sw_softc {
 static etherswitch_info_t etherswitch_info = {
        .es_nports =            0,
        .es_nvlangroups =       E6000SW_NUM_VGROUPS,
+       .es_vlan_caps =         ETHERSWITCH_VLAN_PORT,
        .es_name =              "Marvell 6000 series switch"
 };
 
@@ -95,6 +98,7 @@ static int e6000sw_detach(device_t);
 static int e6000sw_readphy(device_t, int, int);
 static int e6000sw_writephy(device_t, int, int, int);
 static etherswitch_info_t* e6000sw_getinfo(device_t);
+static int e6000sw_getconf(device_t, etherswitch_conf_t *);
 static void e6000sw_lock(device_t);
 static void e6000sw_unlock(device_t);
 static int e6000sw_getport(device_t, etherswitch_port_t *);
@@ -123,6 +127,7 @@ static int e6000sw_set_pvid(e6000sw_softc_t *, int, in
 static __inline bool e6000sw_is_cpuport(e6000sw_softc_t *, int);
 static __inline bool e6000sw_is_fixedport(e6000sw_softc_t *, int);
 static __inline bool e6000sw_is_phyport(e6000sw_softc_t *, int);
+static __inline bool e6000sw_is_portenabled(e6000sw_softc_t *, int);
 static __inline struct mii_data *e6000sw_miiforphy(e6000sw_softc_t *,
     unsigned int);
 
@@ -142,6 +147,7 @@ static device_method_t e6000sw_methods[] = {
 
        /* etherswitch interface */
        DEVMETHOD(etherswitch_getinfo,          e6000sw_getinfo),
+       DEVMETHOD(etherswitch_getconf,          e6000sw_getconf),
        DEVMETHOD(etherswitch_lock,             e6000sw_lock),
        DEVMETHOD(etherswitch_unlock,           e6000sw_unlock),
        DEVMETHOD(etherswitch_getport,          e6000sw_getport),
@@ -202,7 +208,6 @@ e6000sw_probe(device_t dev)
                return (ENXIO);
 
        sc = device_get_softc(dev);
-       bzero(sc, sizeof(e6000sw_softc_t));
        sc->dev = dev;
        sc->node = switch_node;
 
@@ -219,14 +224,27 @@ e6000sw_probe(device_t dev)
        E6000SW_UNLOCK(sc);
 
        switch (id & 0xfff0) {
+       case 0x3400:
+               description = "Marvell 88E6141";
+               sc->phy_base = 0x10;
+               sc->num_ports = 6;
+               break;
+       case 0x3410:
+               description = "Marvell 88E6341";
+               sc->phy_base = 0x10;
+               sc->num_ports = 6;
+               break;
        case 0x3520:
                description = "Marvell 88E6352";
+               sc->num_ports = 7;
                break;
        case 0x1720:
                description = "Marvell 88E6172";
+               sc->num_ports = 7;
                break;
        case 0x1760:
                description = "Marvell 88E6176";
+               sc->num_ports = 7;
                break;
        default:
                sx_destroy(&sc->sx);
@@ -240,17 +258,17 @@ e6000sw_probe(device_t dev)
 }
 
 static int
-e6000sw_parse_child_fdt(device_t dev, phandle_t child, uint32_t *fixed_mask,
-    uint32_t *cpu_mask, int *pport, int *pvlangroup)
+e6000sw_parse_child_fdt(e6000sw_softc_t *sc, phandle_t child,
+    uint32_t *fixed_mask, uint32_t *cpu_mask, int *pport, int *pvlangroup)
 {
+       boolean_t fixed_link;
        char portlabel[100];
        uint32_t port, vlangroup;
-       boolean_t fixed_link;
 
        if (fixed_mask == NULL || cpu_mask == NULL || pport == NULL)
                return (ENXIO);
 
-       OF_getprop(child, "label", (void *)portlabel, 100);
+       OF_getprop(child, "label", (void *)portlabel, sizeof(portlabel));
        OF_getencprop(child, "reg", (void *)&port, sizeof(port));
 
        if (OF_getencprop(child, "vlangroup", (void *)&vlangroup,
@@ -262,22 +280,21 @@ e6000sw_parse_child_fdt(device_t dev, phandle_t child,
                *pvlangroup = -1;
        }
 
-       if (port >= E6000SW_MAX_PORTS)
+       if (port >= sc->num_ports)
                return (ENXIO);
        *pport = port;
 
        if (strncmp(portlabel, "cpu", 3) == 0) {
-               device_printf(dev, "CPU port at %d\n", port);
+               device_printf(sc->dev, "CPU port at %d\n", port);
                *cpu_mask |= (1 << port);
-               return (0);
        }
 
        fixed_link = OF_child(child);
        if (fixed_link) {
                *fixed_mask |= (1 << port);
-               device_printf(dev, "fixed port at %d\n", port);
+               device_printf(sc->dev, "fixed port at %d\n", port);
        } else {
-               device_printf(dev, "PHY at port %d\n", port);
+               device_printf(sc->dev, "PHY at port %d\n", port);
        }
 
        return (0);
@@ -314,7 +331,7 @@ e6000sw_attach_miibus(e6000sw_softc_t *sc, int port)
 
        err = mii_attach(sc->dev, &sc->miibus[port], sc->ifp[port],
            e6000sw_ifmedia_upd, e6000sw_ifmedia_sts, BMSR_DEFCAPMASK,
-           port, MII_OFFSET_ANY, 0);
+           port + sc->phy_base, MII_OFFSET_ANY, 0);
        if (err != 0)
                return (err);
 
@@ -343,7 +360,7 @@ e6000sw_attach(device_t dev)
        bzero(member_ports, sizeof(member_ports));
 
        for (child = OF_child(sc->node); child != 0; child = OF_peer(child)) {
-               err = e6000sw_parse_child_fdt(dev, child, &sc->fixed_mask,
+               err = e6000sw_parse_child_fdt(sc, child, &sc->fixed_mask,
                    &sc->cpuports_mask, &port, &vlangroup);
                if (err != 0) {
                        device_printf(sc->dev, "failed to parse DTS\n");
@@ -353,7 +370,8 @@ e6000sw_attach(device_t dev)
                if (vlangroup != -1)
                        member_ports[vlangroup] |= (1 << port);
 
-               sc->num_ports++;
+               /* Port is in use. */
+               sc->ports_mask |= (1 << port);
 
                err = e6000sw_init_interface(sc, port);
                if (err != 0) {
@@ -529,6 +547,17 @@ e6000sw_getinfo(device_t dev)
        return (&etherswitch_info);
 }
 
+static int
+e6000sw_getconf(device_t dev __unused, etherswitch_conf_t *conf)
+{
+
+       /* Return the VLAN mode. */
+       conf->cmd = ETHERSWITCH_CONF_VLAN_MODE;
+       conf->vlan_mode = ETHERSWITCH_VLAN_PORT;
+
+       return (0);
+}
+
 static void
 e6000sw_lock(device_t dev)
 {
@@ -563,6 +592,8 @@ e6000sw_getport(device_t dev, etherswitch_port_t *p)
 
        if (p->es_port >= sc->num_ports || p->es_port < 0)
                return (EINVAL);
+       if (!e6000sw_is_portenabled(sc, p->es_port))
+               return (0);
 
        err = 0;
        E6000SW_LOCK(sc);
@@ -605,12 +636,15 @@ e6000sw_setport(device_t dev, etherswitch_port_t *p)
 
        if (p->es_port >= sc->num_ports || p->es_port < 0)
                return (EINVAL);
+       if (!e6000sw_is_portenabled(sc, p->es_port))
+               return (0);
 
        err = 0;
        E6000SW_LOCK(sc);
        if (p->es_pvid != 0)
                e6000sw_set_pvid(sc, p->es_port, p->es_pvid);
-       if (!e6000sw_is_cpuport(sc, p->es_port)) {
+       if (!e6000sw_is_cpuport(sc, p->es_port)  &&
+           !e6000sw_is_fixedport(sc, p->es_port)) {
                mii = e6000sw_miiforphy(sc, p->es_port);
                err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr, &mii->mii_media,
                    SIOCSIFMEDIA);
@@ -780,8 +814,7 @@ e6000sw_setvgroup(device_t dev, etherswitch_vlangroup_
        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[vg->es_vlangroup] & (1 << port)) ||
-                   (vg->es_untagged_ports & (1 << 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,
@@ -805,7 +838,8 @@ e6000sw_getvgroup(device_t dev, etherswitch_vlangroup_
                return (EINVAL);
        vg->es_untagged_ports = vg->es_member_ports =
            sc->members[vg->es_vlangroup];
-       vg->es_vid = ETHERSWITCH_VID_VALID;
+       if (vg->es_untagged_ports != 0)
+               vg->es_vid = ETHERSWITCH_VID_VALID;
 
        return (0);
 }
@@ -936,6 +970,13 @@ e6000sw_is_phyport(e6000sw_softc_t *sc, int port)
        return ((phy_mask & (1 << port)) ? true : false);
 }
 
+static __inline bool
+e6000sw_is_portenabled(e6000sw_softc_t *sc, int port)
+{
+
+       return ((sc->ports_mask & (1 << port)) ? true : false);
+}
+
 static __inline int
 e6000sw_set_pvid(e6000sw_softc_t *sc, int port, int pvid)
 {
@@ -1010,7 +1051,8 @@ e6000sw_tick (void *arg)
                E6000SW_LOCK(sc);
                for (port = 0; port < sc->num_ports; port++) {
                        /* Tick only on PHY ports */
-                       if (!e6000sw_is_phyport(sc, port))
+                       if (!e6000sw_is_portenabled(sc, port) ||
+                           !e6000sw_is_phyport(sc, port))
                                continue;
 
                        mii = e6000sw_miiforphy(sc, port);
@@ -1090,6 +1132,8 @@ e6000sw_port_vlan_conf(e6000sw_softc_t *sc)
 
        /* Set port priority */
        for (port = 0; port < sc->num_ports; port++) {
+               if (!e6000sw_is_portenabled(sc, port))
+                       continue;
                ret = e6000sw_readreg(sc, REG_PORT(port), PORT_VID);
                ret &= ~PORT_VID_PRIORITY_MASK;
                e6000sw_writereg(sc, REG_PORT(port), PORT_VID, ret);
@@ -1097,6 +1141,8 @@ e6000sw_port_vlan_conf(e6000sw_softc_t *sc)
 
        /* Set VID map */
        for (port = 0; port < sc->num_ports; port++) {
+               if (!e6000sw_is_portenabled(sc, port))
+                       continue;
                ret = e6000sw_readreg(sc, REG_PORT(port), PORT_VID);
                ret &= ~PORT_VID_DEF_VID_MASK;
                ret |= (port + 1);
@@ -1105,6 +1151,8 @@ e6000sw_port_vlan_conf(e6000sw_softc_t *sc)
 
        /* Enable all ports */
        for (port = 0; port < sc->num_ports; port++) {
+               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));
_______________________________________________
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