changeset 337:3c0fed8eac60

Update bcm5325 driver for Port Based VLAN setup
author ray@terran.dlink.ua
date Fri, 03 Feb 2012 17:31:23 +0200
parents 7142a751aca2
children 7dbf1516e36b
files head/sys/dev/switch/bcm5325_switch.c head/sys/dev/switch/bcm5325_switchreg.h head/sys/dev/switch/bcm5325_switchvar.h
diffstat 3 files changed, 246 insertions(+), 55 deletions(-) [+]
line wrap: on
line diff
--- a/head/sys/dev/switch/bcm5325_switch.c	Fri Feb 03 17:30:35 2012 +0200
+++ b/head/sys/dev/switch/bcm5325_switch.c	Fri Feb 03 17:31:23 2012 +0200
@@ -73,6 +73,15 @@
 static int	bcm5325_read(struct bcm5325_switch_softc *sc, uint32_t reg,
 		    uint64_t *val);
 
+static int	bcm5325_vlan_write(struct bcm5325_switch_softc *sc, uint16_t vid,
+		    uint32_t tports, uint32_t uports);
+static int	bcm5325_vlan_read(struct bcm5325_switch_softc *sc, uint16_t vid,
+		    uint32_t *tports, uint32_t *uports);
+static int	bcm5395_vlan_write(struct bcm5325_switch_softc *sc, uint16_t vid,
+		    uint32_t tports, uint32_t uports);
+static int	bcm5395_vlan_read(struct bcm5325_switch_softc *sc, uint16_t vid,
+		    uint32_t *tports, uint32_t *uports);
+
 #define	PSPHY_WRITE(_sc, _reg, _val)			\
 	    MII_SW_WRITE4((_sc), ((PSEUDOPHY_ADDR << 8) | (_reg)), (_val))
 #define	PSPHY_READ(_sc, _reg)				\
@@ -203,7 +212,7 @@
 	struct bcm5325_switch_softc *sc;
 	uint64_t reg;
 	uint64_t reg32;
-	int i;
+//	int i;
 
 	sc = device_get_softc(dev);
 	sc->parent = device_get_parent(dev);
@@ -213,13 +222,18 @@
 
 	reg = 0;
 	READ(sc, SWITCH_DEVICEID, &reg);
-	reg32 = reg & 0xffff;
+	reg32 = reg & 0xfffff;
 	if (reg32) {
+#if 1
+		/* At least BCM53115 return 0x53115 if query in 32bit mode */
+		sc->devid = reg32;
+#else
 		/* XXX: maybe wrong, based on known chips */
 		if (reg32 < 0x100)
 			sc->devid = reg32 + 0x5300;
 		else
 			sc->devid = reg32 + 0x50000;
+#endif
 	}
 
 	resource_int_value(device_get_name(dev), device_get_unit(dev),
@@ -227,33 +241,47 @@
 	device_printf(dev, "\t%switch model is BCM%x\n",
 	    ((resource_int_value(device_get_name(dev), device_get_unit(dev),
 	    "devid", &sc->devid))?"S":"Hinted s"), sc->devid);
-#ifdef notyet
-	switch (sc->devid) {
-	case 0x5365:
-		sc->mode = 0;
-		break;
-	case 0x5356:
-		sc->mode = 0;
-		break;
-	case 0x53115:
-		sc->mode = 0;
-		break;
-	case 0x5325:
-	case 0x5352:
-	case 0x5354:
-	default:
-		sc->mode = 0;
-		break;
-	}
-#endif
+
 	sc->caps = malloc(sizeof(struct switch_capability), M_DEVBUF,
 	    M_WAITOK | M_ZERO);
 
 	if (!sc->caps)
 		return (ENXIO);
 
-	sc->caps->ports = sc->ports = 6;
-	sc->vlans = 16;
+	switch (sc->devid) {
+	case 0x5395:
+	case 0x53115:
+	case 0x53118:
+		sc->vlan_write = &bcm5395_vlan_write;
+		sc->vlan_read = &bcm5395_vlan_read;
+		sc->vlans = 4096;
+		break;
+	case 0x5325:
+	case 0x5352:
+	case 0x5354:
+	default:
+		sc->vlan_write = &bcm5325_vlan_write;
+		sc->vlan_read = &bcm5325_vlan_read;
+		sc->vlans = 16;
+		break;
+	}
+
+	switch (sc->devid) {
+	case 0x53118:
+	case 0x53115:	/* 53118 w/o ports 6-7 */
+		sc->caps->ports = sc->ports = 9;
+		break;
+	case 0x5325:
+	case 0x5352:
+	case 0x5354:
+	case 0x5395:
+		sc->caps->ports = sc->ports = 6;
+		break;
+	default:
+		/* XXX: trick, last digit of id + 1 MII port */
+		sc->caps->ports = sc->ports = (sc->devid % 0xf) + 1;
+		break;
+	}
 	sc->sc_dev = dev;
 
 #define S_C(x) SWITCH_CAPS_ ## x
@@ -311,16 +339,16 @@
 
 	/*
 	 * XXX: Avoid default configuration, bootloader must set it or we
-	 * load user defined
+	 * must load user defined
 	 */
 	/* set_vid(swdev, Idx, VID) */
-	set_vid(dev, 0, 1);
+	//set_vid(dev, 0, 1);
 
 	/* All ports are members of VLAN0 (VID1) */
-	set_vlan_ports(dev, 0, 0x01ff);
+	//set_vlan_ports(dev, 0, 0x01ff);
 	/* Other VLANs have no members */
-	for (i = 1; i < 9; i++)
-		set_vlan_ports(dev, i, 0x00);
+	//for (i = 1; i < 9; i++)
+	//	set_vlan_ports(dev, i, 0x00);
 
 	return (0);
 }
@@ -541,7 +569,7 @@
 
 static int
 bcm5325_vlan_write(struct bcm5325_switch_softc *sc, uint16_t vid,
-		   uint8_t tports, uint8_t uports)
+		   uint32_t tports, uint32_t uports)
 {
 	uint64_t reg;
 	int error = 0;
@@ -561,7 +589,7 @@
 
 static int
 bcm5325_vlan_read(struct bcm5325_switch_softc *sc, uint16_t vid,
-		  uint8_t *tports, uint8_t *uports)
+		  uint32_t *tports, uint32_t *uports)
 {
 	uint64_t reg;
 	int error = 0;
@@ -586,6 +614,69 @@
 	return (error);
 }
 
+static int
+bcm5395_vlan_write(struct bcm5325_switch_softc *sc, uint16_t vid,
+		   uint32_t tports, uint32_t uports)
+{
+	int error = 0;
+
+	error = WRITE(sc, VLAN_TABLE_ENTRY_5395,
+	    (uports << VLAN_RW_UNTAG_SHIFT_5395) | tports);
+	if (error)
+		return (error);
+	error = WRITE(sc, VLAN_TABLE_INDX_5395, vid);
+	if (error)
+		return (error);
+	error = WRITE(sc, VLAN_TABLE_ACCESS_5395, VLAN_TABLE_ACCESS_5395_RUN);
+	if (error)
+		return (error);
+
+	return (error);
+}
+
+static int
+bcm5395_vlan_read(struct bcm5325_switch_softc *sc, uint16_t vid,
+		  uint32_t *tports, uint32_t *uports)
+{
+	uint64_t reg, mask;
+	int error = 0;
+
+	error = WRITE(sc, VLAN_TABLE_INDX_5395, vid);
+	if (error)
+		return (error);
+	error = WRITE(sc, VLAN_TABLE_ACCESS_5395,
+	    VLAN_TABLE_ACCESS_5395_RUN |VLAN_TABLE_ACCESS_5395_READ);
+	if (error)
+		return (error);
+
+	error = READ(sc, VLAN_TABLE_ENTRY_5395, &reg);
+	if (error)
+		return (error);
+
+	mask = (1 << VLAN_RW_UNTAG_SHIFT_5395) - 1;
+	if (tports != NULL)
+		*tports = reg & mask;
+	if (uports != NULL)
+		*uports = (reg >> VLAN_RW_UNTAG_SHIFT_5395) & mask;
+
+	return (error);
+}
+
+static inline int
+bcmXXXX_vlan_write(struct bcm5325_switch_softc *sc, uint16_t vid,
+		   uint32_t tports, uint32_t uports)
+{
+
+	return (sc->vlan_write(sc, vid, tports, uports));
+}
+
+static inline int
+bcmXXXX_vlan_read(struct bcm5325_switch_softc *sc, uint16_t vid,
+		  uint32_t *tports, uint32_t *uports)
+{
+
+	return (sc->vlan_read(sc, vid, tports, uports));
+}
 /*
  * set_vid(dev, idx, vid)
  * Define a VLAN, since BCM5325 family use only lower 4-8 bits of VID -
@@ -611,10 +702,10 @@
 			      sc->base_vlan);
 	}
 
-	error = bcm5325_vlan_read(sc, vid, NULL, NULL);
+	error = bcmXXXX_vlan_read(sc, vid, NULL, NULL);
 	if (error == ENOENT) {
 		/* Create empty valid VLAN port set */
-		bcm5325_vlan_write(sc, vid, 0, 0);
+		bcmXXXX_vlan_write(sc, vid, 0, 0);
 		return (0);
 	}
 
@@ -638,7 +729,7 @@
 set_vlan_ports(device_t dev, int idx, uint32_t memb)
 {
 	struct bcm5325_switch_softc *sc = device_get_softc(dev);
-	uint8_t umemb;
+	uint32_t umemb;
 	int error = 0;
 
 	printf("%s: idx=%d, memb=%08x\n", __func__, idx, memb);
@@ -648,8 +739,8 @@
 	if (memb & ~((1 << sc->ports) - 1))
 		return (EINVAL);
 
-	bcm5325_vlan_read(sc, idx /* must be vid */, NULL, &umemb);
-	error = bcm5325_vlan_write(sc, idx /* must be vid */, memb, umemb);
+	bcmXXXX_vlan_read(sc, idx /* must be vid */, NULL, &umemb);
+	error = bcmXXXX_vlan_write(sc, idx /* must be vid */, memb, umemb);
 
 	return (error);
 }
@@ -658,13 +749,13 @@
 get_vlan_ports(device_t dev, int idx, uint32_t *memb)
 {
 	struct bcm5325_switch_softc *sc = device_get_softc(dev);
-	uint8_t reg;
+	uint32_t reg;
 	int error;
 
 	if (idx > (sc->vlans - 1))
 		return (EINVAL);
 
-	error = bcm5325_vlan_read(sc, idx /* must be vid */, &reg, NULL);
+	error = bcmXXXX_vlan_read(sc, idx /* must be vid */, &reg, NULL);
 	printf("%s: error=%d idx=%d, memb=%08x\n", __func__, error, idx, reg);
 	if (error == ENOENT) {
 		*memb = 0;
@@ -681,7 +772,7 @@
 set_vlan_untagged_ports(device_t dev, int idx, uint32_t umemb)
 {
 	struct bcm5325_switch_softc *sc = device_get_softc(dev);
-	uint8_t memb;
+	uint32_t memb;
 	int error = 0;
 
 	printf("%s: idx=%d, memb=%08x\n", __func__, idx, umemb);
@@ -691,8 +782,8 @@
 	if (memb & ~((1 << sc->ports) - 1))
 		return (EINVAL);
 
-	bcm5325_vlan_read(sc, idx /* must be vid */, &memb, NULL);
-	error = bcm5325_vlan_write(sc, idx /* must be vid */, memb | umemb,
+	bcmXXXX_vlan_read(sc, idx /* must be vid */, &memb, NULL);
+	error = bcmXXXX_vlan_write(sc, idx /* must be vid */, memb | umemb,
 	    umemb);
 
 	return (error);
@@ -702,13 +793,13 @@
 get_vlan_untagged_ports(device_t dev, int idx, uint32_t *memb)
 {
 	struct bcm5325_switch_softc *sc = device_get_softc(dev);
-	uint8_t reg;
+	uint32_t reg;
 	int error;
 
 	if (idx > (sc->vlans - 1))
 		return (EINVAL);
 
-	error = bcm5325_vlan_read(sc, idx /* must be vid */, NULL, &reg);
+	error = bcmXXXX_vlan_read(sc, idx /* must be vid */, NULL, &reg);
 	printf("%s: error=%d idx=%d, memb=%08x\n", __func__, error, idx, reg);
 	if (error == ENOENT) {
 		*memb = 0;
@@ -721,6 +812,94 @@
 	return (0);
 }
 
+static int
+pbvlan_setports(device_t dev, int port,	uint32_t allowed)
+{
+	struct bcm5325_switch_softc *sc;
+	int error;
+
+	sc = device_get_softc(dev);
+
+	if (port > (sc->ports - 1))
+		return (EINVAL);
+
+	error = WRITE(sc, PBVLAN_ALLOWED_PORTS(port), allowed);
+	if (error)
+		return (error);
+
+	return (0);
+}
+
+static int
+pbvlan_getports(device_t dev, int port,	uint32_t *allowed)
+{
+	struct bcm5325_switch_softc *sc;
+	uint64_t reg;
+	int error;
+
+	sc = device_get_softc(dev);
+
+	if (port > (sc->ports - 1))
+		return (EINVAL);
+
+	error = READ(sc, PBVLAN_ALLOWED_PORTS(port), &reg);
+	if (error)
+		return (error);
+
+	*allowed = (uint32_t)reg;
+	return (0);
+}
+
+static int
+reset_subsys(device_t dev, int subsys)
+{
+	struct bcm5325_switch_softc *sc;
+	int error, port;
+
+	sc = device_get_softc(dev);
+	error = 0;
+	switch (subsys & SWITCH_RESETSUB_MASK) {
+	case SWITCH_RESETSUB_SWITCH:
+//		error = WRITE(sc, SWITCH_RESET, 0x90);
+		/* XXX: Hope it will reset any switch */
+		error = WRITE(sc, SWITCH_RESET, 0xffff);
+		if (error)
+			return (error);
+
+		pause("eswrst", hz/100);
+
+		error = WRITE(sc, SWITCH_RESET, 0x00);
+		if (error)
+			return (error);
+		break;
+	case SWITCH_RESETSUB_PORT:
+		if ((subsys & SWITCH_RESETSUB_PORT_MASK) ==
+		    SWITCH_RESETSUB_ALLPORTS) {
+			/* Reset all PHYs */
+#ifdef notyet
+			for (port = 0; port < sc->ports; port ++)
+				reset_port(sc, port);
+#endif
+		} else {
+			/* Reset syngle PHY */
+			port = (subsys & SWITCH_RESETSUB_PORT_MASK) >>
+			    SWITCH_RESETSUB_PORT_SHIFT;
+#ifdef notyet
+			reset_port(sc, port);
+#endif
+		}
+		break;
+	case SWITCH_RESETSUB_VLANS:
+		/* TODO */
+		break;
+	case SWITCH_RESETSUB_QOS:
+		/* TODO */
+		break;
+	}
+
+	return (error);
+}
+
 static device_method_t bcm5325_switch_methods[] = {
 	DEVMETHOD(device_probe,		bcm5325_switch_probe),
 	DEVMETHOD(device_attach,	bcm5325_switch_attach),
@@ -730,6 +909,7 @@
 	DEVMETHOD(switch_get_caps,	get_caps),
 	DEVMETHOD(switch_set_reg,	set_reg),
 	DEVMETHOD(switch_get_reg,	get_reg),
+	DEVMETHOD(switch_reset_subsys,	reset_subsys),
 
 	/* MAC address table */
 	DEVMETHOD(switch_find_mac,	find_mac_addr),
@@ -747,6 +927,10 @@
 	DEVMETHOD(switch_set_vlanutports,	set_vlan_untagged_ports),
 	DEVMETHOD(switch_get_vlanutports,	get_vlan_untagged_ports),
 
+	/* Port based VLAN */
+	DEVMETHOD(switch_pbvlan_getports,	pbvlan_getports),
+	DEVMETHOD(switch_pbvlan_setports,	pbvlan_setports),
+
 	{0, 0},
 };
 
--- a/head/sys/dev/switch/bcm5325_switchreg.h	Fri Feb 03 17:30:35 2012 +0200
+++ b/head/sys/dev/switch/bcm5325_switchreg.h	Fri Feb 03 17:31:23 2012 +0200
@@ -97,6 +97,7 @@
 #define 	SWITCH_MODE_MANAGED		0x01
 
 #define PORTMII_STATUS_OVERRIDE		(S1 | PAGE(0x00) | 0x0e)
+#define 	PORTMII_STATUS_FORCE_1000M	0x80	/* it is force? */
 #define 	PORTMII_STATUS_REVERSE_MII	0x10
 #define 	PORTMII_STATUS_PAUSE_CAPABLE	0x08
 #define 	PORTMII_STATUS_FORCE_100M	0x04
@@ -178,7 +179,7 @@
 #define	IGMP_CPU_FWD_CTL		(S1 | PAGE(0x02) | 0x26)
 #define	IGMP_REPLACE_DA			(S6 | PAGE(0x02) | 0x27)
 
-#define	SWITCH_DEVICEID			(S2 | PAGE(0x02) | 0x30)
+#define	SWITCH_DEVICEID			(S4 | PAGE(0x02) | 0x30)
 
 #define	MIB_AUTOCAST_PORT	(S2 | PAGE(0x03) | 0x00)
 #define	MIB_AUTOCAST_HDR_PNTR	(S2 | PAGE(0x03) | 0x02)
@@ -265,7 +266,6 @@
 #define	QUEUE4_CTL_3		(S2 | PAGE(0x0A) | 0x86)
 #define	QUEUE4_CTL_4		(S2 | PAGE(0x0A) | 0x88)
 
-
 /* Standard MII
 PRT = PAGE10 + port
 Page PRT, Address 00h-01h	Switch Port Control Register
@@ -360,14 +360,8 @@
 #define	DIFFSERV_DSCP_PRIORITYH	(S8 | PAGE(0x30) | 0x38)
 #define		DSCP_TO_QUEUE(_d, _q)	((_q) << (((_d) & 0x3f) * 2))
 
-/* BCM5395/5397/5398/53115 */
-#define	ROBO_VTBL_ACCESS	0x60 /* VLAN table access: 8bit */
-#define	ROBO_VTBL_INDX		0x61 /* VLAN table address index: 16bit */
-#define	ROBO_VTBL_ENTRY		0x63 /* VLAN table entry: 32bit */
-#define	ROBO_VTBL_ACCESS_5395	0x80 /* VLAN table access: 8bit */
-#define	ROBO_VTBL_INDX_5395	0x81 /* VLAN table address index: 16bit */
-#define	ROBO_VTBL_ENTRY_5395	0x83 /* VLAN table entry: 32bit */
-
+/* PAGE31, Port Based VLAN */
+#define	PBVLAN_ALLOWED_PORTS(_p)	(S2 | PAGE(0x31) | ((_p) * 2))
 
 #define	VLAN_GLOBAL_CTL0		(S1 | PAGE(0x34) | 0x00)
 #define		VLAN_GLOBAL_CTL0_1Q_ENABLE	0x80
@@ -399,12 +393,22 @@
 #define VLAN_ID_MAX5350 			15
 #define VLAN_ID_MAX5395				4094
 
+#define	VLAN_TABLE_ACCESS_5350	(S1 | PAGE(0x05) | 0x60)
+#define	VLAN_TABLE_INDX_5350	(S2 | PAGE(0x05) | 0x61)
+#define	VLAN_TABLE_ENTRY_5350	(S4 | PAGE(0x05) | 0x63)
+/* BCM5395/5397/5398/53115/53118 */
+#define	VLAN_TABLE_ACCESS_5395	(S1 | PAGE(0x05) | 0x80)
+#define		VLAN_TABLE_ACCESS_5395_RUN	0x80
+#define		VLAN_TABLE_ACCESS_5395_READ	0x01
+#define	VLAN_TABLE_INDX_5395	(S1 | PAGE(0x05) | 0x81)
+#define	VLAN_TABLE_ENTRY_5395	(S4 | PAGE(0x05) | 0x83)
 
 /* XXX: Valid for BCM535x */
 #define	VLAN_WRITE			(S4 | PAGE(0x34) | 0x08)
 #define		VLAN_RW_VALID_5350		0x00100000
 #define		VLAN_RW_VALID_5380 		0x04000000
 #define		VLAN_RW_VALID 			0x4000
+#define		VLAN_RW_UNTAG_SHIFT_5395	9
 #define		VLAN_RW_UNTAG_SHIFT_5380	13
 #define		VLAN_RW_UNTAG_SHIFT_5350	6
 #define		VLAN_RW_UNTAG_SHIFT		7
@@ -421,7 +425,6 @@
 #define	VLAN_PRIORITY_REMAP		(S3 | PAGE(0x34) | 0x20)
 #define		VLAN_PRIORITY_REMAP_OLD_NEW(_o, _n)	((_n) << ((_o) * 3))
 
-
 #define	PORT_SUPPRESSION_CTL		(S1 | PAGE(0x35) | (0x00 + (_p)))
 #define		PORT_SUPPRESSION_CTL_HAS_DROPS	0x80
 #define		PORT_SUPPRESSION_CTL_PASS_MCAST	0x40
--- a/head/sys/dev/switch/bcm5325_switchvar.h	Fri Feb 03 17:30:35 2012 +0200
+++ b/head/sys/dev/switch/bcm5325_switchvar.h	Fri Feb 03 17:31:23 2012 +0200
@@ -32,7 +32,7 @@
 struct bcm5325_switch_softc {
 	device_t		sc_dev;
 	device_t		parent;
-	device_t		new_mii;
+	device_t		new_mii; /* Unused */
 	int 			ports;
 	int 			vlans;
 	uint16_t		base_vlan;
@@ -40,8 +40,12 @@
 	int			page_reg;
 	int			page_phy;
 	int			devid;
-	int			mode;
+	int			mode; /* Unused */
 	uint32_t		sc_mii_mode;
+	int (*vlan_write)	(struct bcm5325_switch_softc *, uint16_t,
+	    uint32_t, uint32_t);
+	int (*vlan_read)	(struct bcm5325_switch_softc *, uint16_t,
+	    uint32_t *, uint32_t *);
 };
 
 #define MII_SW_READ4(_sc, _reg) \