svn commit: r320157 - head/sys/dev/etherswitch/e6000sw

Luiz Otavio O Souza loos at FreeBSD.org
Tue Jun 20 18:11:25 UTC 2017


Author: loos
Date: Tue Jun 20 18:11:23 2017
New Revision: 320157
URL: https://svnweb.freebsd.org/changeset/base/320157

Log:
  Add support to 2.5G uplink for the MV88E6141 and MV88E6341 switches.
  
  Force the switch port settings for fixed media types.
  
  Tested with:	88E6176, 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	Tue Jun 20 17:39:24 2017	(r320156)
+++ head/sys/dev/etherswitch/e6000sw/e6000sw.c	Tue Jun 20 18:11:23 2017	(r320157)
@@ -71,8 +71,10 @@ typedef struct e6000sw_softc {
 	device_t		miibus[E6000SW_MAX_PORTS];
 	struct proc		*kproc;
 
+	uint32_t		swid;
 	uint32_t		cpuports_mask;
 	uint32_t		fixed_mask;
+	uint32_t		fixed25_mask;
 	uint32_t		ports_mask;
 	int			phy_base;
 	int			sw_addr;
@@ -126,6 +128,7 @@ static int e6000sw_get_pvid(e6000sw_softc_t *, int, in
 static int e6000sw_set_pvid(e6000sw_softc_t *, int, int);
 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_fixed25port(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 *,
@@ -198,7 +201,6 @@ e6000sw_probe(device_t dev)
 	e6000sw_softc_t *sc;
 	const char *description;
 	phandle_t dsa_node, switch_node;
-	uint32_t id;
 
 	dsa_node = fdt_find_compatible(OF_finddevice("/"),
 	    "marvell,dsa", 0);
@@ -223,35 +225,35 @@ e6000sw_probe(device_t dev)
 	 */
 	sx_init(&sc->sx, "e6000sw_tmp");
 	E6000SW_LOCK(sc);
-	id = e6000sw_readreg(sc, REG_PORT(0), SWITCH_ID);
+	sc->swid = e6000sw_readreg(sc, REG_PORT(0), SWITCH_ID) & 0xfff0;
 	E6000SW_UNLOCK(sc);
 	sx_destroy(&sc->sx);
 
-	switch (id & 0xfff0) {
-	case 0x3400:
+	switch (sc->swid) {
+	case MV88E6141:
 		description = "Marvell 88E6141";
 		sc->phy_base = 0x10;
 		sc->num_ports = 6;
 		break;
-	case 0x3410:
+	case MV88E6341:
 		description = "Marvell 88E6341";
 		sc->phy_base = 0x10;
 		sc->num_ports = 6;
 		break;
-	case 0x3520:
+	case MV88E6352:
 		description = "Marvell 88E6352";
 		sc->num_ports = 7;
 		break;
-	case 0x1720:
+	case MV88E6172:
 		description = "Marvell 88E6172";
 		sc->num_ports = 7;
 		break;
-	case 0x1760:
+	case MV88E6176:
 		description = "Marvell 88E6176";
 		sc->num_ports = 7;
 		break;
 	default:
-		device_printf(dev, "Unrecognized device, id 0x%x.\n", id);
+		device_printf(dev, "Unrecognized device, id 0x%x.\n", sc->swid);
 		return (ENXIO);
 	}
 
@@ -261,18 +263,22 @@ e6000sw_probe(device_t dev)
 }
 
 static int
-e6000sw_parse_child_fdt(e6000sw_softc_t *sc, 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, int *pport,
+    int *pvlangroup)
 {
-	boolean_t fixed_link;
-	char portlabel[100];
+	char *name, *portlabel;
+	int speed;
+	phandle_t fixed_link;
 	uint32_t port, vlangroup;
 
-	if (fixed_mask == NULL || cpu_mask == NULL || pport == NULL)
+	if (pport == NULL || pvlangroup == NULL)
 		return (ENXIO);
 
-	OF_getprop(child, "label", (void *)portlabel, sizeof(portlabel));
-	OF_getencprop(child, "reg", (void *)&port, sizeof(port));
+	if (OF_getencprop(child, "reg", (void *)&port, sizeof(port)) < 0)
+		return (ENXIO);
+	if (port >= sc->num_ports)
+		return (ENXIO);
+	*pport = port;
 
 	if (OF_getencprop(child, "vlangroup", (void *)&vlangroup,
 	    sizeof(vlangroup)) > 0) {
@@ -283,22 +289,36 @@ e6000sw_parse_child_fdt(e6000sw_softc_t *sc, phandle_t
 		*pvlangroup = -1;
 	}
 
-	if (port >= sc->num_ports)
-		return (ENXIO);
-	*pport = port;
-
-	if (strncmp(portlabel, "cpu", 3) == 0) {
-		device_printf(sc->dev, "CPU port at %d\n", port);
-		*cpu_mask |= (1 << port);
+	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);
+			sc->cpuports_mask |= (1 << port);
+			sc->fixed_mask |= (1 << port);
+		}
+		free(portlabel, M_OFWPROP);
 	}
 
 	fixed_link = OF_child(child);
-	if (fixed_link) {
-		*fixed_mask |= (1 << port);
+	if (fixed_link != 0 &&
+	    OF_getprop_alloc(fixed_link, "name", 1, (void **)&name) > 0) {
+		if (strncmp(name, "fixed-link", 10) == 0) {
+			/* Assume defaults: 1g - full-duplex. */
+			sc->fixed_mask |= (1 << port);
+			if (OF_getencprop(fixed_link, "speed", &speed,
+			     sizeof(speed)) > 0) {
+				if (speed == 2500 &&
+				    (MVSWITCH(sc, MV88E6141) ||
+				     MVSWITCH(sc, MV88E6341))) {
+					sc->fixed25_mask |= (1 << port);
+				}
+			}
+		}
+		free(name, M_OFWPROP);
+	}
+	if ((sc->fixed_mask & (1 << port)) != 0)
 		device_printf(sc->dev, "fixed port at %d\n", port);
-	} else {
+	else
 		device_printf(sc->dev, "PHY at port %d\n", port);
-	}
 
 	return (0);
 }
@@ -344,11 +364,12 @@ 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];
-	etherswitch_vlangroup_t vg;
+	uint32_t reg;
 
 	err = 0;
 	sc = device_get_softc(dev);
@@ -365,8 +386,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(sc, child, &sc->fixed_mask,
-		    &sc->cpuports_mask, &port, &vlangroup);
+		err = e6000sw_parse_child_fdt(sc, child, &port, &vlangroup);
 		if (err != 0) {
 			device_printf(sc->dev, "failed to parse DTS\n");
 			goto out_fail;
@@ -384,6 +404,30 @@ e6000sw_attach(device_t dev)
 			goto out_fail;
 		}
 
+		if (e6000sw_is_fixedport(sc, port)) {
+			/* Link must be down to change speed force value. */
+			reg = e6000sw_readreg(sc, REG_PORT(port), PSC_CONTROL);
+			reg &= ~PSC_CONTROL_LINK_UP;
+			reg |= PSC_CONTROL_FORCED_LINK;
+			e6000sw_writereg(sc, REG_PORT(port), PSC_CONTROL, reg);
+
+			/*
+			 * Force speed, full-duplex, EEE off and flow-control
+			 * on.
+			 */
+			if (e6000sw_is_fixed25port(sc, port))
+				reg = PSC_CONTROL_SPD2500;
+			else
+				reg = PSC_CONTROL_SPD1000;
+			reg |= PSC_CONTROL_FORCED_DPX | PSC_CONTROL_FULLDPX |
+			    PSC_CONTROL_FORCED_LINK | PSC_CONTROL_LINK_UP |
+			    PSC_CONTROL_FORCED_FC | PSC_CONTROL_FC_ON |
+			    PSC_CONTROL_FORCED_SPD;
+			if (MVSWITCH(sc, MV88E6141) || MVSWITCH(sc, MV88E6341))
+			    reg |= PSC_CONTROL_FORCED_EEE;
+			e6000sw_writereg(sc, REG_PORT(port), PSC_CONTROL, reg);
+		}
+
 		/* Don't attach miibus at CPU/fixed ports */
 		if (!e6000sw_is_phyport(sc, port))
 			continue;
@@ -604,21 +648,19 @@ e6000sw_getport(device_t dev, etherswitch_port_t *p)
 	E6000SW_LOCK(sc);
 	e6000sw_get_pvid(sc, p->es_port, &p->es_pvid);
 
-	if (e6000sw_is_cpuport(sc, p->es_port)) {
-		p->es_flags |= ETHERSWITCH_PORT_CPU;
+	if (e6000sw_is_fixedport(sc, p->es_port)) {
+		if (e6000sw_is_cpuport(sc, p->es_port))
+			p->es_flags |= ETHERSWITCH_PORT_CPU;
 		ifmr = &p->es_ifmr;
 		ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
 		ifmr->ifm_count = 0;
-		ifmr->ifm_current = ifmr->ifm_active =
-		    IFM_ETHER | IFM_1000_T | IFM_FDX;
+		if (e6000sw_is_fixed25port(sc, p->es_port))
+			ifmr->ifm_active = IFM_2500_T;
+		else
+			ifmr->ifm_active = IFM_1000_T;
+		ifmr->ifm_active |= IFM_ETHER | IFM_FDX;
+		ifmr->ifm_current = ifmr->ifm_active;
 		ifmr->ifm_mask = 0;
-	} else if (e6000sw_is_fixedport(sc, p->es_port)) {
-		ifmr = &p->es_ifmr;
-		ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
-		ifmr->ifm_count = 0;
-		ifmr->ifm_current = ifmr->ifm_active =
-		    IFM_ETHER | IFM_1000_T | IFM_FDX;
-		ifmr->ifm_mask = 0;
 	} else {
 		mii = e6000sw_miiforphy(sc, p->es_port);
 		err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr,
@@ -648,8 +690,7 @@ e6000sw_setport(device_t dev, etherswitch_port_t *p)
 	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)  &&
-	    !e6000sw_is_fixedport(sc, p->es_port)) {
+	if (e6000sw_is_phyport(sc, p->es_port)) {
 		mii = e6000sw_miiforphy(sc, p->es_port);
 		err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr, &mii->mii_media,
 		    SIOCSIFMEDIA);
@@ -964,6 +1005,13 @@ e6000sw_is_fixedport(e6000sw_softc_t *sc, int port)
 {
 
 	return ((sc->fixed_mask & (1 << port)) ? true : false);
+}
+
+static __inline bool
+e6000sw_is_fixed25port(e6000sw_softc_t *sc, int port)
+{
+
+	return ((sc->fixed25_mask & (1 << port)) ? true : false);
 }
 
 static __inline bool

Modified: head/sys/dev/etherswitch/e6000sw/e6000swreg.h
==============================================================================
--- head/sys/dev/etherswitch/e6000sw/e6000swreg.h	Tue Jun 20 17:39:24 2017	(r320156)
+++ head/sys/dev/etherswitch/e6000sw/e6000swreg.h	Tue Jun 20 18:11:23 2017	(r320157)
@@ -42,6 +42,15 @@ struct atu_opt {
  * Definitions for the Marvell 88E6000 series Ethernet Switch.
  */
 
+/* Switch IDs. */
+#define	MV88E6141	0x3400
+#define	MV88E6341	0x3410
+#define	MV88E6352	0x3520
+#define	MV88E6172	0x1720
+#define	MV88E6176	0x1760
+
+#define	MVSWITCH(_sc, id)	((_sc)->swid == (id))
+
 /*
  * Switch Registers
  */
@@ -64,6 +73,17 @@ struct atu_opt {
 #define	PORT_STATUS_PHY_DETECT_MASK	(1 << 12)
 
 #define PSC_CONTROL			0x1
+#define	PSC_CONTROL_FORCED_SPD		(1 << 13)
+#define	PSC_CONTROL_EEE_ON		(1 << 9)
+#define	PSC_CONTROL_FORCED_EEE		(1 << 8)
+#define	PSC_CONTROL_FC_ON		(1 << 7)
+#define	PSC_CONTROL_FORCED_FC		(1 << 6)
+#define	PSC_CONTROL_LINK_UP		(1 << 5)
+#define	PSC_CONTROL_FORCED_LINK		(1 << 4)
+#define	PSC_CONTROL_FULLDPX		(1 << 3)
+#define	PSC_CONTROL_FORCED_DPX		(1 << 2)
+#define	PSC_CONTROL_SPD2500		0x3
+#define	PSC_CONTROL_SPD1000		0x2
 #define SWITCH_ID			0x3
 #define PORT_CONTROL			0x4
 #define PORT_CONTROL_1			0x5


More information about the svn-src-all mailing list