Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 13 Jun 2017 00:42:23 +0000 (UTC)
From:      Luiz Otavio O Souza <loos@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r319886 - head/sys/dev/etherswitch/e6000sw
Message-ID:  <201706130042.v5D0gN5d082962@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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));



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201706130042.v5D0gN5d082962>