From owner-svn-src-head@freebsd.org Tue Jun 13 00:42:24 2017 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 96E6BD87B6A; Tue, 13 Jun 2017 00:42:24 +0000 (UTC) (envelope-from loos@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::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 57AE41AAB; Tue, 13 Jun 2017 00:42:24 +0000 (UTC) (envelope-from loos@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id v5D0gN2G082963; Tue, 13 Jun 2017 00:42:23 GMT (envelope-from loos@FreeBSD.org) Received: (from loos@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v5D0gN5d082962; Tue, 13 Jun 2017 00:42:23 GMT (envelope-from loos@FreeBSD.org) Message-Id: <201706130042.v5D0gN5d082962@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: loos set sender to loos@FreeBSD.org using -f From: Luiz Otavio O Souza Date: Tue, 13 Jun 2017 00:42:23 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r319886 - head/sys/dev/etherswitch/e6000sw X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 13 Jun 2017 00:42:24 -0000 Author: loos Date: Tue Jun 13 00:42:23 2017 New Revision: 319886 URL: https://svnweb.freebsd.org/changeset/base/319886 Log: Add the initial support for the Marvell 88E6141 and 88E6341 switches. Right now the driver only supports port VLANs, so make sure etherswitch_getinfo() return the proper switch capabilities. Handle the cases where not all ports are in use (that will also require etherswitch cooperation). Sponsored by: Rubicon Communications, LLC (Netgate) Modified: head/sys/dev/etherswitch/e6000sw/e6000sw.c Modified: head/sys/dev/etherswitch/e6000sw/e6000sw.c ============================================================================== --- head/sys/dev/etherswitch/e6000sw/e6000sw.c Tue Jun 13 00:31:16 2017 (r319885) +++ head/sys/dev/etherswitch/e6000sw/e6000sw.c Tue Jun 13 00:42:23 2017 (r319886) @@ -73,6 +73,8 @@ typedef struct e6000sw_softc { uint32_t cpuports_mask; uint32_t fixed_mask; + uint32_t ports_mask; + int phy_base; int sw_addr; int num_ports; boolean_t multi_chip; @@ -85,6 +87,7 @@ typedef struct e6000sw_softc { static etherswitch_info_t etherswitch_info = { .es_nports = 0, .es_nvlangroups = E6000SW_NUM_VGROUPS, + .es_vlan_caps = ETHERSWITCH_VLAN_PORT, .es_name = "Marvell 6000 series switch" }; @@ -95,6 +98,7 @@ static int e6000sw_detach(device_t); static int e6000sw_readphy(device_t, int, int); static int e6000sw_writephy(device_t, int, int, int); static etherswitch_info_t* e6000sw_getinfo(device_t); +static int e6000sw_getconf(device_t, etherswitch_conf_t *); static void e6000sw_lock(device_t); static void e6000sw_unlock(device_t); static int e6000sw_getport(device_t, etherswitch_port_t *); @@ -123,6 +127,7 @@ static int e6000sw_set_pvid(e6000sw_softc_t *, int, in 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_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 *, unsigned int); @@ -142,6 +147,7 @@ static device_method_t e6000sw_methods[] = { /* etherswitch interface */ DEVMETHOD(etherswitch_getinfo, e6000sw_getinfo), + DEVMETHOD(etherswitch_getconf, e6000sw_getconf), DEVMETHOD(etherswitch_lock, e6000sw_lock), DEVMETHOD(etherswitch_unlock, e6000sw_unlock), DEVMETHOD(etherswitch_getport, e6000sw_getport), @@ -202,7 +208,6 @@ e6000sw_probe(device_t dev) return (ENXIO); sc = device_get_softc(dev); - bzero(sc, sizeof(e6000sw_softc_t)); sc->dev = dev; sc->node = switch_node; @@ -219,14 +224,27 @@ e6000sw_probe(device_t dev) E6000SW_UNLOCK(sc); switch (id & 0xfff0) { + case 0x3400: + description = "Marvell 88E6141"; + sc->phy_base = 0x10; + sc->num_ports = 6; + break; + case 0x3410: + description = "Marvell 88E6341"; + sc->phy_base = 0x10; + sc->num_ports = 6; + break; case 0x3520: description = "Marvell 88E6352"; + sc->num_ports = 7; break; case 0x1720: description = "Marvell 88E6172"; + sc->num_ports = 7; break; case 0x1760: description = "Marvell 88E6176"; + sc->num_ports = 7; break; default: sx_destroy(&sc->sx); @@ -240,17 +258,17 @@ e6000sw_probe(device_t dev) } static int -e6000sw_parse_child_fdt(device_t dev, 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, + uint32_t *fixed_mask, uint32_t *cpu_mask, int *pport, int *pvlangroup) { + boolean_t fixed_link; char portlabel[100]; uint32_t port, vlangroup; - boolean_t fixed_link; if (fixed_mask == NULL || cpu_mask == NULL || pport == NULL) return (ENXIO); - OF_getprop(child, "label", (void *)portlabel, 100); + OF_getprop(child, "label", (void *)portlabel, sizeof(portlabel)); OF_getencprop(child, "reg", (void *)&port, sizeof(port)); if (OF_getencprop(child, "vlangroup", (void *)&vlangroup, @@ -262,22 +280,21 @@ e6000sw_parse_child_fdt(device_t dev, phandle_t child, *pvlangroup = -1; } - if (port >= E6000SW_MAX_PORTS) + if (port >= sc->num_ports) return (ENXIO); *pport = port; if (strncmp(portlabel, "cpu", 3) == 0) { - device_printf(dev, "CPU port at %d\n", port); + device_printf(sc->dev, "CPU port at %d\n", port); *cpu_mask |= (1 << port); - return (0); } fixed_link = OF_child(child); if (fixed_link) { *fixed_mask |= (1 << port); - device_printf(dev, "fixed port at %d\n", port); + device_printf(sc->dev, "fixed port at %d\n", port); } else { - device_printf(dev, "PHY at port %d\n", port); + device_printf(sc->dev, "PHY at port %d\n", port); } return (0); @@ -314,7 +331,7 @@ e6000sw_attach_miibus(e6000sw_softc_t *sc, int port) err = mii_attach(sc->dev, &sc->miibus[port], sc->ifp[port], e6000sw_ifmedia_upd, e6000sw_ifmedia_sts, BMSR_DEFCAPMASK, - port, MII_OFFSET_ANY, 0); + port + sc->phy_base, MII_OFFSET_ANY, 0); if (err != 0) return (err); @@ -343,7 +360,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(dev, child, &sc->fixed_mask, + err = e6000sw_parse_child_fdt(sc, child, &sc->fixed_mask, &sc->cpuports_mask, &port, &vlangroup); if (err != 0) { device_printf(sc->dev, "failed to parse DTS\n"); @@ -353,7 +370,8 @@ e6000sw_attach(device_t dev) if (vlangroup != -1) member_ports[vlangroup] |= (1 << port); - sc->num_ports++; + /* Port is in use. */ + sc->ports_mask |= (1 << port); err = e6000sw_init_interface(sc, port); if (err != 0) { @@ -529,6 +547,17 @@ e6000sw_getinfo(device_t dev) return (ðerswitch_info); } +static int +e6000sw_getconf(device_t dev __unused, etherswitch_conf_t *conf) +{ + + /* Return the VLAN mode. */ + conf->cmd = ETHERSWITCH_CONF_VLAN_MODE; + conf->vlan_mode = ETHERSWITCH_VLAN_PORT; + + return (0); +} + static void e6000sw_lock(device_t dev) { @@ -563,6 +592,8 @@ e6000sw_getport(device_t dev, etherswitch_port_t *p) if (p->es_port >= sc->num_ports || p->es_port < 0) return (EINVAL); + if (!e6000sw_is_portenabled(sc, p->es_port)) + return (0); err = 0; E6000SW_LOCK(sc); @@ -605,12 +636,15 @@ e6000sw_setport(device_t dev, etherswitch_port_t *p) if (p->es_port >= sc->num_ports || p->es_port < 0) return (EINVAL); + if (!e6000sw_is_portenabled(sc, p->es_port)) + return (0); err = 0; 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)) { + if (!e6000sw_is_cpuport(sc, p->es_port) && + !e6000sw_is_fixedport(sc, p->es_port)) { mii = e6000sw_miiforphy(sc, p->es_port); err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr, &mii->mii_media, SIOCSIFMEDIA); @@ -780,8 +814,7 @@ e6000sw_setvgroup(device_t dev, etherswitch_vlangroup_ 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[vg->es_vlangroup] & (1 << port)) || - (vg->es_untagged_ports & (1 << 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, @@ -805,7 +838,8 @@ e6000sw_getvgroup(device_t dev, etherswitch_vlangroup_ return (EINVAL); vg->es_untagged_ports = vg->es_member_ports = sc->members[vg->es_vlangroup]; - vg->es_vid = ETHERSWITCH_VID_VALID; + if (vg->es_untagged_ports != 0) + vg->es_vid = ETHERSWITCH_VID_VALID; return (0); } @@ -936,6 +970,13 @@ e6000sw_is_phyport(e6000sw_softc_t *sc, int port) return ((phy_mask & (1 << port)) ? true : false); } +static __inline bool +e6000sw_is_portenabled(e6000sw_softc_t *sc, int port) +{ + + return ((sc->ports_mask & (1 << port)) ? true : false); +} + static __inline int e6000sw_set_pvid(e6000sw_softc_t *sc, int port, int pvid) { @@ -1010,7 +1051,8 @@ e6000sw_tick (void *arg) E6000SW_LOCK(sc); for (port = 0; port < sc->num_ports; port++) { /* Tick only on PHY ports */ - if (!e6000sw_is_phyport(sc, port)) + if (!e6000sw_is_portenabled(sc, port) || + !e6000sw_is_phyport(sc, port)) continue; mii = e6000sw_miiforphy(sc, port); @@ -1090,6 +1132,8 @@ e6000sw_port_vlan_conf(e6000sw_softc_t *sc) /* Set port priority */ for (port = 0; port < sc->num_ports; port++) { + if (!e6000sw_is_portenabled(sc, port)) + continue; ret = e6000sw_readreg(sc, REG_PORT(port), PORT_VID); ret &= ~PORT_VID_PRIORITY_MASK; e6000sw_writereg(sc, REG_PORT(port), PORT_VID, ret); @@ -1097,6 +1141,8 @@ e6000sw_port_vlan_conf(e6000sw_softc_t *sc) /* Set VID map */ for (port = 0; port < sc->num_ports; port++) { + if (!e6000sw_is_portenabled(sc, port)) + continue; ret = e6000sw_readreg(sc, REG_PORT(port), PORT_VID); ret &= ~PORT_VID_DEF_VID_MASK; ret |= (port + 1); @@ -1105,6 +1151,8 @@ e6000sw_port_vlan_conf(e6000sw_softc_t *sc) /* Enable all ports */ for (port = 0; port < sc->num_ports; port++) { + 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));