Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 8 Mar 2015 21:59:03 +0000 (UTC)
From:      Adrian Chadd <adrian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r279790 - head/sys/dev/etherswitch/arswitch
Message-ID:  <201503082159.t28Lx3MT076594@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: adrian
Date: Sun Mar  8 21:59:03 2015
New Revision: 279790
URL: https://svnweb.freebsd.org/changeset/base/279790

Log:
  Add per-port vlan support for the AR8327.
  
  All the per-port support is really doing is applying a port visibility
  mask to each of the switchports.  Everything still look like a single
  portgroup (vlan id 1), but the per-port visibility mask is modified.
  
  Whilst I'm here, also add some initial dot1q support - the pvid stuff
  is doing the right thing, but it's not useful without the rest of
  the VLAN table programming.
  
  It's enough for me to be able to use the LAN/WAN port distinction
  on the AP135, where there isn't (for now!) a dedicated PHY for the
  "WAN" port.
  
  Tested:
  
  * AP135, QCA9558 SoC + AR8327 switch

Modified:
  head/sys/dev/etherswitch/arswitch/arswitch.c
  head/sys/dev/etherswitch/arswitch/arswitch_8327.c
  head/sys/dev/etherswitch/arswitch/arswitch_vlans.c
  head/sys/dev/etherswitch/arswitch/arswitch_vlans.h
  head/sys/dev/etherswitch/arswitch/arswitchreg.h
  head/sys/dev/etherswitch/arswitch/arswitchvar.h

Modified: head/sys/dev/etherswitch/arswitch/arswitch.c
==============================================================================
--- head/sys/dev/etherswitch/arswitch/arswitch.c	Sun Mar  8 21:51:37 2015	(r279789)
+++ head/sys/dev/etherswitch/arswitch/arswitch.c	Sun Mar  8 21:59:03 2015	(r279790)
@@ -303,14 +303,24 @@ arswitch_attach(device_t dev)
 	sc->hal.arswitch_port_vlan_setup = ar8xxx_port_vlan_setup;
 	sc->hal.arswitch_port_vlan_get = ar8xxx_port_vlan_get;
 	sc->hal.arswitch_vlan_init_hw = ar8xxx_reset_vlans;
+
 	sc->hal.arswitch_vlan_getvgroup = ar8xxx_getvgroup;
 	sc->hal.arswitch_vlan_setvgroup = ar8xxx_setvgroup;
+
 	sc->hal.arswitch_vlan_get_pvid = ar8xxx_get_pvid;
 	sc->hal.arswitch_vlan_set_pvid = ar8xxx_set_pvid;
+
+	sc->hal.arswitch_get_dot1q_vlan = ar8xxx_get_dot1q_vlan;
+	sc->hal.arswitch_set_dot1q_vlan = ar8xxx_set_dot1q_vlan;
+	sc->hal.arswitch_get_port_vlan = ar8xxx_get_port_vlan;
+	sc->hal.arswitch_set_port_vlan = ar8xxx_set_port_vlan;
+
 	sc->hal.arswitch_atu_flush = ar8xxx_atu_flush;
+
 	sc->hal.arswitch_phy_read = arswitch_readphy_internal;
 	sc->hal.arswitch_phy_write = arswitch_writephy_internal;
 
+
 	/*
 	 * Attach switch related functions
 	 */
@@ -627,6 +637,15 @@ ar8xxx_port_vlan_get(struct arswitch_sof
 }
 
 static int
+arswitch_is_cpuport(struct arswitch_softc *sc, int port)
+{
+
+	return ((port == AR8X16_PORT_CPU) ||
+	    ((AR8X16_IS_SWITCH(sc, AR8327) &&
+	      port == AR8327_PORT_GMAC6)));
+}
+
+static int
 arswitch_getport(device_t dev, etherswitch_port_t *p)
 {
 	struct arswitch_softc *sc;
@@ -635,7 +654,8 @@ arswitch_getport(device_t dev, etherswit
 	int err;
 
 	sc = device_get_softc(dev);
-	if (p->es_port < 0 || p->es_port > sc->numphys)
+	/* XXX +1 is for AR8327; should make this configurable! */
+	if (p->es_port < 0 || p->es_port > sc->info.es_nports)
 		return (ENXIO);
 
 	err = sc->hal.arswitch_port_vlan_get(sc, p);
@@ -643,7 +663,7 @@ arswitch_getport(device_t dev, etherswit
 		return (err);
 
 	mii = arswitch_miiforport(sc, p->es_port);
-	if (p->es_port == AR8X16_PORT_CPU) {
+	if (arswitch_is_cpuport(sc, p->es_port)) {
 		/* fill in fixed values for CPU port */
 		/* XXX is this valid in all cases? */
 		p->es_flags |= ETHERSWITCH_PORT_CPU;
@@ -712,7 +732,7 @@ arswitch_setport(device_t dev, etherswit
 	struct ifnet *ifp;
 
 	sc = device_get_softc(dev);
-	if (p->es_port < 0 || p->es_port > sc->numphys)
+	if (p->es_port < 0 || p->es_port > sc->info.es_nports)
 		return (ENXIO);
 
 	/* Port flags. */
@@ -723,7 +743,7 @@ arswitch_setport(device_t dev, etherswit
 	}
 
 	/* Do not allow media changes on CPU port. */
-	if (p->es_port == AR8X16_PORT_CPU)
+	if (arswitch_is_cpuport(sc, p->es_port))
 		return (0);
 
 	mii = arswitch_miiforport(sc, p->es_port);

Modified: head/sys/dev/etherswitch/arswitch/arswitch_8327.c
==============================================================================
--- head/sys/dev/etherswitch/arswitch/arswitch_8327.c	Sun Mar  8 21:51:37 2015	(r279789)
+++ head/sys/dev/etherswitch/arswitch/arswitch_8327.c	Sun Mar  8 21:59:03 2015	(r279790)
@@ -655,7 +655,8 @@ ar8327_hw_global_setup(struct arswitch_s
 	arswitch_writereg(sc->sc_dev, AR8327_REG_EEE_CTRL, t);
 
 	/* Set the right number of ports */
-	sc->info.es_nports = 6;
+	/* GMAC0 (CPU), GMAC1..5 (PHYs), GMAC6 (CPU) */
+	sc->info.es_nports = 7;
 
 	return (0);
 }
@@ -712,8 +713,20 @@ static int
 ar8327_port_vlan_setup(struct arswitch_softc *sc, etherswitch_port_t *p)
 {
 
-	/* XXX stub for now */
-//	device_printf(sc->sc_dev, "%s: called\n", __func__);
+	/* Check: ADDTAG/STRIPTAG - exclusive */
+
+	ARSWITCH_LOCK(sc);
+
+	/* Set the PVID. */
+	if (p->es_pvid != 0)
+		sc->hal.arswitch_vlan_set_pvid(sc, p->es_port, p->es_pvid);
+
+	/*
+	 * DOUBLE_TAG
+	 * VLAN_MODE_ADD
+	 * VLAN_MODE_STRIP
+	 */
+	ARSWITCH_UNLOCK(sc);
 	return (0);
 }
 
@@ -723,8 +736,20 @@ ar8327_port_vlan_setup(struct arswitch_s
 static int
 ar8327_port_vlan_get(struct arswitch_softc *sc, etherswitch_port_t *p)
 {
-	/* XXX stub for now */
-//	device_printf(sc->sc_dev, "%s: called\n", __func__);
+
+	ARSWITCH_LOCK(sc);
+
+	/* Retrieve the PVID */
+	sc->hal.arswitch_vlan_get_pvid(sc, p->es_port, &p->es_pvid);
+
+	/* Retrieve the current port configuration */
+	/*
+	 * DOUBLE_TAG
+	 * VLAN_MODE_ADD
+	 * VLAN_MODE_STRIP
+	 */
+
+	ARSWITCH_UNLOCK(sc);
 	return (0);
 }
 
@@ -764,7 +789,10 @@ ar8327_reset_vlans(struct arswitch_softc
 
 	for (i = 0; i < AR8327_NUM_PORTS; i++) {
 
-		/* set pvid = 1; there's only one vlangroup */
+		if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT)
+			sc->vid[i] = i | ETHERSWITCH_VID_VALID;
+
+		/* set pvid = 1; there's only one vlangroup to start with */
 		t = 1 << AR8327_PORT_VLAN0_DEF_SVID_S;
 		t |= 1 << AR8327_PORT_VLAN0_DEF_CVID_S;
 		arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_VLAN0(i), t);
@@ -802,44 +830,90 @@ ar8327_reset_vlans(struct arswitch_softc
 }
 
 static int
+ar8327_vlan_get_port(struct arswitch_softc *sc, uint32_t *ports, int vid)
+{
+	int port;
+	uint32_t reg;
+
+	ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
+
+	/* For port based vlans the vlanid is the same as the port index. */
+	port = vid & ETHERSWITCH_VID_MASK;
+	reg = arswitch_readreg(sc->sc_dev, AR8327_REG_PORT_LOOKUP(port));
+	*ports = reg & 0x7f;
+	return (0);
+}
+
+static int
+ar8327_vlan_set_port(struct arswitch_softc *sc, uint32_t ports, int vid)
+{
+	int err, port;
+
+	ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
+
+	/* For port based vlans the vlanid is the same as the port index. */
+	port = vid & ETHERSWITCH_VID_MASK;
+
+	err = arswitch_modifyreg(sc->sc_dev, AR8327_REG_PORT_LOOKUP(port),
+	    0x7f, /* vlan membership mask */
+	    (ports & 0x7f));
+
+	if (err)
+		return (err);
+	return (0);
+}
+
+static int
 ar8327_vlan_getvgroup(struct arswitch_softc *sc, etherswitch_vlangroup_t *vg)
 {
 
-#if 0
 	/* XXX for now, no dot1q vlans */
 	if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q)
 		return (EINVAL);
 	return (ar8xxx_getvgroup(sc, vg));
-#endif
-	return (0);
 }
 
 static int
 ar8327_vlan_setvgroup(struct arswitch_softc *sc, etherswitch_vlangroup_t *vg)
 {
 
-#if 0
 	/* XXX for now, no dot1q vlans */
 	if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q)
 		return (EINVAL);
 	return (ar8xxx_setvgroup(sc, vg));
-#endif
-	return (0);
 }
 
 static int
 ar8327_get_pvid(struct arswitch_softc *sc, int port, int *pvid)
 {
+	uint32_t reg;
+
+	ARSWITCH_LOCK_ASSERT(sc, MA_OWNED);
+
+	/*
+	 * XXX for now, assuming it's CVID; likely very wrong!
+	 */
+	port = port & ETHERSWITCH_VID_MASK;
+	reg = arswitch_readreg(sc->sc_dev, AR8327_REG_PORT_VLAN0(port));
+	reg = reg >> AR8327_PORT_VLAN0_DEF_CVID_S;
+	reg = reg & 0xfff;
 
-	device_printf(sc->sc_dev, "%s: called\n", __func__);
+	*pvid = reg;
 	return (0);
 }
 
 static int
 ar8327_set_pvid(struct arswitch_softc *sc, int port, int pvid)
 {
+	uint32_t t;
+
+	/* Limit pvid to valid values */
+	pvid &= 0x7f;
+
+	t = pvid << AR8327_PORT_VLAN0_DEF_SVID_S;
+	t |= pvid << AR8327_PORT_VLAN0_DEF_CVID_S;
+	arswitch_writereg(sc->sc_dev, AR8327_REG_PORT_VLAN0(port), t);
 
-	device_printf(sc->sc_dev, "%s: called\n", __func__);
 	return (0);
 }
 
@@ -883,6 +957,9 @@ ar8327_attach(struct arswitch_softc *sc)
 	sc->hal.arswitch_vlan_get_pvid = ar8327_get_pvid;
 	sc->hal.arswitch_vlan_set_pvid = ar8327_set_pvid;
 
+	sc->hal.arswitch_get_port_vlan = ar8327_vlan_get_port;
+	sc->hal.arswitch_set_port_vlan = ar8327_vlan_set_port;
+
 	sc->hal.arswitch_atu_flush = ar8327_atu_flush;
 
 	/*

Modified: head/sys/dev/etherswitch/arswitch/arswitch_vlans.c
==============================================================================
--- head/sys/dev/etherswitch/arswitch/arswitch_vlans.c	Sun Mar  8 21:51:37 2015	(r279789)
+++ head/sys/dev/etherswitch/arswitch/arswitch_vlans.c	Sun Mar  8 21:59:03 2015	(r279790)
@@ -103,8 +103,8 @@ arswitch_purge_dot1q_vlan(struct arswitc
 	return (arswitch_vlan_op(sc, AR8X16_VLAN_OP_PURGE, vid, 0));
 }
 
-static int
-arswitch_get_dot1q_vlan(struct arswitch_softc *sc, uint32_t *ports, int vid)
+int
+ar8xxx_get_dot1q_vlan(struct arswitch_softc *sc, uint32_t *ports, int vid)
 {
 	uint32_t reg;
 	int err;
@@ -124,8 +124,8 @@ arswitch_get_dot1q_vlan(struct arswitch_
 	return (0);
 }
 
-static int
-arswitch_set_dot1q_vlan(struct arswitch_softc *sc, uint32_t ports, int vid)
+int
+ar8xxx_set_dot1q_vlan(struct arswitch_softc *sc, uint32_t ports, int vid)
 {
 	int err;
 
@@ -136,8 +136,8 @@ arswitch_set_dot1q_vlan(struct arswitch_
 	return (0);
 }
 
-static int
-arswitch_get_port_vlan(struct arswitch_softc *sc, uint32_t *ports, int vid)
+int
+ar8xxx_get_port_vlan(struct arswitch_softc *sc, uint32_t *ports, int vid)
 {
 	int port;
 	uint32_t reg;
@@ -151,8 +151,8 @@ arswitch_get_port_vlan(struct arswitch_s
 	return (0);
 }
 
-static int
-arswitch_set_port_vlan(struct arswitch_softc *sc, uint32_t ports, int vid)
+int
+ar8xxx_set_port_vlan(struct arswitch_softc *sc, uint32_t ports, int vid)
 {
 	int err, port;
 
@@ -224,7 +224,7 @@ ar8xxx_reset_vlans(struct arswitch_softc
 		ports = 0;
 		for (i = 0; i <= sc->numphys; i++)
 			ports |= (1 << i);
-		arswitch_set_dot1q_vlan(sc, ports, sc->vid[0]);
+		sc->hal.arswitch_set_dot1q_vlan(sc, ports, sc->vid[0]);
 		sc->vid[0] |= ETHERSWITCH_VID_VALID;
 	} else if (sc->vlan_mode == ETHERSWITCH_VLAN_PORT) {
 		/* Initialize the port based vlans. */
@@ -286,11 +286,11 @@ ar8xxx_getvgroup(struct arswitch_softc *
 	/* Member Ports. */
 	switch (sc->vlan_mode) {
 	case ETHERSWITCH_VLAN_DOT1Q:
-		err = arswitch_get_dot1q_vlan(sc, &vg->es_member_ports,
+		err = sc->hal.arswitch_get_dot1q_vlan(sc, &vg->es_member_ports,
 		    vg->es_vid);
 		break;
 	case ETHERSWITCH_VLAN_PORT:
-		err = arswitch_get_port_vlan(sc, &vg->es_member_ports,
+		err = sc->hal.arswitch_get_port_vlan(sc, &vg->es_member_ports,
 		    vg->es_vid);
 		break;
 	default:
@@ -345,10 +345,10 @@ ar8xxx_setvgroup(struct arswitch_softc *
 	/* Member Ports. */
 	switch (sc->vlan_mode) {
 	case ETHERSWITCH_VLAN_DOT1Q:
-		err = arswitch_set_dot1q_vlan(sc, vg->es_member_ports, vid);
+		err = sc->hal.arswitch_set_dot1q_vlan(sc, vg->es_member_ports, vid);
 		break;
 	case ETHERSWITCH_VLAN_PORT:
-		err = arswitch_set_port_vlan(sc, vg->es_member_ports, vid);
+		err = sc->hal.arswitch_set_port_vlan(sc, vg->es_member_ports, vid);
 		break;
 	default:
 		err = -1;

Modified: head/sys/dev/etherswitch/arswitch/arswitch_vlans.h
==============================================================================
--- head/sys/dev/etherswitch/arswitch/arswitch_vlans.h	Sun Mar  8 21:51:37 2015	(r279789)
+++ head/sys/dev/etherswitch/arswitch/arswitch_vlans.h	Sun Mar  8 21:59:03 2015	(r279790)
@@ -35,4 +35,9 @@ int ar8xxx_setvgroup(struct arswitch_sof
 int ar8xxx_get_pvid(struct arswitch_softc *, int, int *);
 int ar8xxx_set_pvid(struct arswitch_softc *, int, int);
 
+int ar8xxx_get_dot1q_vlan(struct arswitch_softc *sc, uint32_t *ports, int vid);
+int ar8xxx_set_dot1q_vlan(struct arswitch_softc *sc, uint32_t ports, int vid);
+int ar8xxx_get_port_vlan(struct arswitch_softc *sc, uint32_t *ports, int vid);
+int ar8xxx_set_port_vlan(struct arswitch_softc *sc, uint32_t ports, int vid);
+
 #endif	/* __ARSWITCH_VLANS_H__ */

Modified: head/sys/dev/etherswitch/arswitch/arswitchreg.h
==============================================================================
--- head/sys/dev/etherswitch/arswitch/arswitchreg.h	Sun Mar  8 21:51:37 2015	(r279789)
+++ head/sys/dev/etherswitch/arswitch/arswitchreg.h	Sun Mar  8 21:59:03 2015	(r279790)
@@ -370,6 +370,9 @@
 #define	AR8327_NUM_PHYS			5
 #define	AR8327_PORTS_ALL		0x7f
 
+#define	AR8327_PORT_GMAC0		0
+#define	AR8327_PORT_GMAC6		6
+
 #define	AR8327_REG_MASK			0x000
 
 #define	AR8327_REG_PAD0_MODE		0x004

Modified: head/sys/dev/etherswitch/arswitch/arswitchvar.h
==============================================================================
--- head/sys/dev/etherswitch/arswitch/arswitchvar.h	Sun Mar  8 21:51:37 2015	(r279789)
+++ head/sys/dev/etherswitch/arswitch/arswitchvar.h	Sun Mar  8 21:59:03 2015	(r279790)
@@ -99,6 +99,15 @@ struct arswitch_softc {
 		int (* arswitch_vlan_set_pvid) (struct arswitch_softc *, int,
 		    int);
 
+		int (* arswitch_get_dot1q_vlan) (struct arswitch_softc *,
+		    uint32_t *ports, int vid);
+		int (* arswitch_set_dot1q_vlan) (struct arswitch_softc *sc,
+		    uint32_t ports, int vid);
+		int (* arswitch_get_port_vlan) (struct arswitch_softc *sc,
+		    uint32_t *ports, int vid);
+		int (* arswitch_set_port_vlan) (struct arswitch_softc *sc,
+		    uint32_t ports, int vid);
+
 		/* PHY functions */
 		int (* arswitch_phy_read) (device_t, int, int);
 		int (* arswitch_phy_write) (device_t, int, int, int);



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