Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 27 Jul 2017 02:38:53 +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: r321602 - head/sys/dev/etherswitch/e6000sw
Message-ID:  <201707270238.v6R2crwW023015@repo.freebsd.org>

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



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