From owner-svn-src-all@FreeBSD.ORG Sun Mar 8 21:59:05 2015 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 958B826F; Sun, 8 Mar 2015 21:59:05 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 75DE0CE8; Sun, 8 Mar 2015 21:59:05 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t28Lx58f076605; Sun, 8 Mar 2015 21:59:05 GMT (envelope-from adrian@FreeBSD.org) Received: (from adrian@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t28Lx3MT076594; Sun, 8 Mar 2015 21:59:03 GMT (envelope-from adrian@FreeBSD.org) Message-Id: <201503082159.t28Lx3MT076594@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: adrian set sender to adrian@FreeBSD.org using -f From: Adrian Chadd Date: Sun, 8 Mar 2015 21:59:03 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r279790 - head/sys/dev/etherswitch/arswitch X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 08 Mar 2015 21:59:05 -0000 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);