From owner-svn-src-all@FreeBSD.ORG Wed May 8 20:58:42 2013 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id B4CA46E4; Wed, 8 May 2013 20:58:42 +0000 (UTC) (envelope-from adrian@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id A6168CE3; Wed, 8 May 2013 20:58:42 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.6/8.14.6) with ESMTP id r48Kwg8u080822; Wed, 8 May 2013 20:58:42 GMT (envelope-from adrian@svn.freebsd.org) Received: (from adrian@localhost) by svn.freebsd.org (8.14.6/8.14.5/Submit) id r48KwfTI080812; Wed, 8 May 2013 20:58:41 GMT (envelope-from adrian@svn.freebsd.org) Message-Id: <201305082058.r48KwfTI080812@svn.freebsd.org> From: Adrian Chadd Date: Wed, 8 May 2013 20:58:41 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r250386 - in head/sys: conf dev/etherswitch/ip17x 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.14 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: Wed, 08 May 2013 20:58:42 -0000 Author: adrian Date: Wed May 8 20:58:41 2013 New Revision: 250386 URL: http://svnweb.freebsd.org/changeset/base/250386 Log: Bring in a basic ethernet switch driver for the IP17x series of switches. These are notably found on some AR71xx based Mikrotik boards. Submitted by: Luiz Otavio O Souza Reviewed by: ray Added: head/sys/dev/etherswitch/ip17x/ head/sys/dev/etherswitch/ip17x/ip175c.c (contents, props changed) head/sys/dev/etherswitch/ip17x/ip175c.h (contents, props changed) head/sys/dev/etherswitch/ip17x/ip175d.c (contents, props changed) head/sys/dev/etherswitch/ip17x/ip175d.h (contents, props changed) head/sys/dev/etherswitch/ip17x/ip17x.c (contents, props changed) head/sys/dev/etherswitch/ip17x/ip17x_phy.c (contents, props changed) head/sys/dev/etherswitch/ip17x/ip17x_phy.h (contents, props changed) head/sys/dev/etherswitch/ip17x/ip17x_reg.h (contents, props changed) head/sys/dev/etherswitch/ip17x/ip17x_var.h (contents, props changed) head/sys/dev/etherswitch/ip17x/ip17x_vlans.c (contents, props changed) head/sys/dev/etherswitch/ip17x/ip17x_vlans.h (contents, props changed) Modified: head/sys/conf/files Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Wed May 8 20:57:37 2013 (r250385) +++ head/sys/conf/files Wed May 8 20:58:41 2013 (r250386) @@ -1331,6 +1331,11 @@ dev/etherswitch/arswitch/arswitch_8316.c dev/etherswitch/arswitch/arswitch_7240.c optional arswitch dev/etherswitch/etherswitch.c optional etherswitch dev/etherswitch/etherswitch_if.m optional etherswitch +dev/etherswitch/ip17x/ip17x.c optional ip17x +dev/etherswitch/ip17x/ip175c.c optional ip17x +dev/etherswitch/ip17x/ip175d.c optional ip17x +dev/etherswitch/ip17x/ip17x_phy.c optional ip17x +dev/etherswitch/ip17x/ip17x_vlans.c optional ip17x dev/etherswitch/mdio_if.m optional miiproxy dev/etherswitch/mdio.c optional miiproxy dev/etherswitch/miiproxy.c optional miiproxy Added: head/sys/dev/etherswitch/ip17x/ip175c.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/etherswitch/ip17x/ip175c.c Wed May 8 20:58:41 2013 (r250386) @@ -0,0 +1,249 @@ +/*- + * Copyright (c) 2013 Luiz Otavio O Souza. + * Copyright (c) 2011-2012 Stefan Bethke. + * Copyright (c) 2012 Adrian Chadd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include + +/* + * IP175C specific functions. + */ + +/* + * Reset the switch. + */ +static int +ip175c_reset(struct ip17x_softc *sc) +{ + uint32_t data; + + /* Reset all the switch settings. */ + if (ip17x_writephy(sc->sc_dev, IP175C_RESET_PHY, IP175C_RESET_REG, + 0x175c)) + return (-1); + DELAY(2); + + /* Force IP175C mode. */ + data = ip17x_readphy(sc->sc_dev, IP175C_MODE_PHY, IP175C_MODE_REG); + if (data == 0x175a) { + if (ip17x_writephy(sc->sc_dev, IP175C_MODE_PHY, IP175C_MODE_REG, + 0x175c)) + return (-1); + } + + return (0); +} + +static int +ip175c_port_vlan_setup(struct ip17x_softc *sc) +{ + struct ip17x_vlan *v; + uint32_t ports[IP175X_NUM_PORTS], reg[IP175X_NUM_PORTS/2]; + int i, err, phy; + + KASSERT(sc->cpuport == 5, ("cpuport != 5 not supported for IP175C")); + KASSERT(sc->numports == 6, ("numports != 6 not supported for IP175C")); + + /* Build the port access masks. */ + memset(ports, 0, sizeof(ports)); + for (i = 0; i < sc->info.es_nports; i++) { + phy = sc->portphy[i]; + v = &sc->vlan[i]; + ports[phy] = v->ports; + } + + /* Move the cpuport bit to its correct place. */ + for (i = 0; i < sc->numports; i++) { + if (ports[i] & (1 << sc->cpuport)) { + ports[i] |= (1 << 7); + ports[i] &= ~(1 << sc->cpuport); + } + } + + /* And now build the switch register data. */ + memset(reg, 0, sizeof(reg)); + for (i = 0; i < (sc->numports / 2); i++) + reg[i] = ports[i * 2] << 8 | ports[i * 2 + 1]; + + /* Update the switch resgisters. */ + err = ip17x_writephy(sc->sc_dev, 29, 19, reg[0]); + if (err == 0) + err = ip17x_writephy(sc->sc_dev, 29, 20, reg[1]); + if (err == 0) + err = ip17x_updatephy(sc->sc_dev, 29, 21, 0xff00, reg[2]); + if (err == 0) + err = ip17x_updatephy(sc->sc_dev, 30, 18, 0x00ff, reg[2]); + return (err); +} + +static int +ip175c_dot1q_vlan_setup(struct ip17x_softc *sc) +{ + struct ip17x_vlan *v; + uint32_t data; + uint32_t vlans[IP17X_MAX_VLANS]; + int i, j; + + KASSERT(sc->cpuport == 5, ("cpuport != 5 not supported for IP175C")); + KASSERT(sc->numports == 6, ("numports != 6 not supported for IP175C")); + + /* Add and strip VLAN tags. */ + data = (sc->addtag & ~(1 << IP175X_CPU_PORT)) << 11; + data |= (sc->striptag & ~(1 << IP175X_CPU_PORT)) << 6; + if (sc->addtag & (1 << IP175X_CPU_PORT)) + data |= (1 << 1); + if (sc->striptag & (1 << IP175X_CPU_PORT)) + data |= (1 << 0); + if (ip17x_writephy(sc->sc_dev, 29, 23, data)) + return (-1); + + /* Set the VID_IDX_SEL to 0. */ + if (ip17x_updatephy(sc->sc_dev, 30, 9, 0x70, 0)) + return (-1); + + /* Calculate the port masks. */ + memset(vlans, 0, sizeof(vlans)); + for (i = 0; i < IP17X_MAX_VLANS; i++) { + v = &sc->vlan[i]; + if (v->vlanid == 0) + continue; + vlans[v->vlanid] = v->ports; + } + + for (j = 0, i = 1; i <= IP17X_MAX_VLANS / 2; i++) { + data = vlans[j++] & 0x3f; + data |= (vlans[j++] & 0x3f) << 8; + if (ip17x_writephy(sc->sc_dev, 30, i, data)) + return (-1); + } + + /* Port default VLAN ID. */ + for (i = 0; i < sc->numports; i++) { + if (i == IP175X_CPU_PORT) { + if (ip17x_writephy(sc->sc_dev, 29, 30, sc->pvid[i])) + return (-1); + } else { + if (ip17x_writephy(sc->sc_dev, 29, 24 + i, sc->pvid[i])) + return (-1); + } + } + + return (0); +} + +/* + * Set the Switch configuration. + */ +static int +ip175c_hw_setup(struct ip17x_softc *sc) +{ + + switch (sc->vlan_mode) { + case ETHERSWITCH_VLAN_PORT: + return (ip175c_port_vlan_setup(sc)); + break; + case ETHERSWITCH_VLAN_DOT1Q: + return (ip175c_dot1q_vlan_setup(sc)); + break; + } + return (-1); +} + +/* + * Set the switch VLAN mode. + */ +static int +ip175c_set_vlan_mode(struct ip17x_softc *sc, uint32_t mode) +{ + + switch (mode) { + case ETHERSWITCH_VLAN_DOT1Q: + /* Enable VLAN tag processing. */ + ip17x_updatephy(sc->sc_dev, 30, 9, 0x80, 0x80); + sc->vlan_mode = mode; + break; + case ETHERSWITCH_VLAN_PORT: + default: + /* Disable VLAN tag processing. */ + ip17x_updatephy(sc->sc_dev, 30, 9, 0x80, 0); + sc->vlan_mode = ETHERSWITCH_VLAN_PORT; + break; + }; + + /* Reset vlans. */ + ip17x_reset_vlans(sc, sc->vlan_mode); + + /* Update switch configuration. */ + ip175c_hw_setup(sc); + + return (0); +} + +/* + * Get the switch VLAN mode. + */ +static int +ip175c_get_vlan_mode(struct ip17x_softc *sc) +{ + + return (sc->vlan_mode); +} + +void +ip175c_attach(struct ip17x_softc *sc) +{ + + sc->hal.ip17x_reset = ip175c_reset; + sc->hal.ip17x_hw_setup = ip175c_hw_setup; + sc->hal.ip17x_get_vlan_mode = ip175c_get_vlan_mode; + sc->hal.ip17x_set_vlan_mode = ip175c_set_vlan_mode; + + /* Defaults for IP175C. */ + sc->cpuport = IP175X_CPU_PORT; + sc->numports = IP175X_NUM_PORTS; + sc->info.es_vlan_caps = ETHERSWITCH_VLAN_PORT | ETHERSWITCH_VLAN_DOT1Q; + + device_printf(sc->sc_dev, "type: IP175C\n"); +} Added: head/sys/dev/etherswitch/ip17x/ip175c.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/etherswitch/ip17x/ip175c.h Wed May 8 20:58:41 2013 (r250386) @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2013 Luiz Otavio O Souza. + * Copyright (c) 2011-2012 Stefan Bethke. + * Copyright (c) 2012 Adrian Chadd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef __IP175C_H__ +#define __IP175C_H__ + +#define IP175C_MODE_PHY 29 +#define IP175C_MODE_REG 31 +#define IP175C_RESET_PHY 30 +#define IP175C_RESET_REG 0 + +#define IP175C_LAST_VLAN 15 + +void ip175c_attach(struct ip17x_softc *sc); + +#endif /* __IP175C_H__ */ Added: head/sys/dev/etherswitch/ip17x/ip175d.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/etherswitch/ip17x/ip175d.c Wed May 8 20:58:41 2013 (r250386) @@ -0,0 +1,219 @@ +/*- + * Copyright (c) 2013 Luiz Otavio O Souza. + * Copyright (c) 2011-2012 Stefan Bethke. + * Copyright (c) 2012 Adrian Chadd. + * Copyright (C) 2008 Patrick Horn. + * Copyright (C) 2008, 2010 Martin Mares. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include + +/* + * IP175D specific functions. + */ + +/* + * Reset the switch to default state. + */ +static int +ip175d_reset(struct ip17x_softc *sc) +{ + + /* Reset all the switch settings. */ + ip17x_writephy(sc->sc_dev, IP175D_RESET_PHY, IP175D_RESET_REG, 0x175d); + DELAY(2); + + /* Disable the special tagging mode. */ + ip17x_updatephy(sc->sc_dev, 21, 22, 0x3, 0x0); + + /* Set 802.1q protocol type. */ + ip17x_writephy(sc->sc_dev, 22, 3, 0x8100); + + return (0); +} + +/* + * Set the Switch configuration. + */ +static int +ip175d_hw_setup(struct ip17x_softc *sc) +{ + struct ip17x_vlan *v; + uint32_t ports[IP17X_MAX_VLANS]; + uint32_t addtag[IP17X_MAX_VLANS]; + uint32_t striptag[IP17X_MAX_VLANS]; + uint32_t vlan_mask; + int i, j; + + vlan_mask = 0; + for (i = 0; i < IP17X_MAX_VLANS; i++) { + + ports[i] = 0; + addtag[i] = 0; + striptag[i] = 0; + + v = &sc->vlan[i]; + if (v->vlanid == 0 || sc->vlan_mode == 0) { + /* Vlangroup disabled. Reset the filter. */ + ip17x_writephy(sc->sc_dev, 22, 14 + i, i + 1); + ports[i] = 0x3f; + continue; + } + + vlan_mask |= (1 << i); + ports[i] = v->ports; + + /* Setup the filter, write the VLAN id. */ + ip17x_writephy(sc->sc_dev, 22, 14 + i, v->vlanid); + + for (j = 0; j < MII_NPHY; j++) { + if ((ports[i] & (1 << j)) == 0) + continue; + if (sc->addtag & (1 << j)) + addtag[i] |= (1 << j); + if (sc->striptag & (1 << j)) + striptag[i] |= (1 << j); + } + } + + /* Write the port masks, tag adds and removals. */ + for (i = 0; i < IP17X_MAX_VLANS / 2; i++) { + ip17x_writephy(sc->sc_dev, 23, i, + ports[2 * i] | (ports[2 * i + 1] << 8)); + ip17x_writephy(sc->sc_dev, 23, i + 8, + addtag[2 * i] | (addtag[2 * i + 1] << 8)); + ip17x_writephy(sc->sc_dev, 23, i + 16, + striptag[2 * i] | (striptag[2 * i + 1] << 8)); + } + + /* Write the in use vlan mask. */ + ip17x_writephy(sc->sc_dev, 22, 10, vlan_mask); + + /* Write the PVID of each port. */ + for (i = 0; i < sc->numports; i++) + ip17x_writephy(sc->sc_dev, 22, 4 + i, sc->pvid[i]); + + return (0); +} + +/* + * Set the switch VLAN mode. + */ +static int +ip175d_set_vlan_mode(struct ip17x_softc *sc, uint32_t mode) +{ + + switch (mode) { + case ETHERSWITCH_VLAN_DOT1Q: + /* + * VLAN classification rules: tag-based VLANs, + * use VID to classify, drop packets that cannot + * be classified. + */ + ip17x_updatephy(sc->sc_dev, 22, 0, 0x3fff, 0x003f); + sc->vlan_mode = mode; + break; + case ETHERSWITCH_VLAN_PORT: + sc->vlan_mode = mode; + /* fallthrough */ + default: + /* + * VLAN classification rules: everything off & + * clear table. + */ + ip17x_updatephy(sc->sc_dev, 22, 0, 0xbfff, 0x8000); + sc->vlan_mode = 0; + break; + }; + + if (sc->vlan_mode != 0) { + /* + * Ingress rules: CFI=1 dropped, null VID is untagged, VID=1 passed, + * VID=0xfff discarded, admin both tagged and untagged, ingress + * filters enabled. + */ + ip17x_updatephy(sc->sc_dev, 22, 1, 0x0fff, 0x0c3f); + + /* Egress rules: IGMP processing off, keep VLAN header off. */ + ip17x_updatephy(sc->sc_dev, 22, 2, 0x0fff, 0x0000); + } else { + ip17x_updatephy(sc->sc_dev, 22, 1, 0x0fff, 0x043f); + ip17x_updatephy(sc->sc_dev, 22, 2, 0x0fff, 0x0020); + } + + /* Reset vlans. */ + ip17x_reset_vlans(sc, sc->vlan_mode); + + /* Update switch configuration. */ + ip175d_hw_setup(sc); + + return (0); +} + +/* + * Get the switch VLAN mode. + */ +static int +ip175d_get_vlan_mode(struct ip17x_softc *sc) +{ + + return (sc->vlan_mode); +} + +void +ip175d_attach(struct ip17x_softc *sc) +{ + + sc->hal.ip17x_reset = ip175d_reset; + sc->hal.ip17x_hw_setup = ip175d_hw_setup; + sc->hal.ip17x_get_vlan_mode = ip175d_get_vlan_mode; + sc->hal.ip17x_set_vlan_mode = ip175d_set_vlan_mode; + + /* Defaults for IP175C. */ + sc->cpuport = IP175X_CPU_PORT; + sc->numports = IP175X_NUM_PORTS; + sc->info.es_vlan_caps = ETHERSWITCH_VLAN_DOT1Q; + + device_printf(sc->sc_dev, "type: IP175D\n"); +} Added: head/sys/dev/etherswitch/ip17x/ip175d.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/etherswitch/ip17x/ip175d.h Wed May 8 20:58:41 2013 (r250386) @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2013 Luiz Otavio O Souza. + * Copyright (c) 2011-2012 Stefan Bethke. + * Copyright (c) 2012 Adrian Chadd. + * Copyright (C) 2008 Patrick Horn. + * Copyright (C) 2008, 2010 Martin Mares. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef __IP175D_H__ +#define __IP175D_H__ + +#define IP175D_ID_PHY 20 +#define IP175D_ID_REG 0 +#define IP175D_RESET_PHY 20 +#define IP175D_RESET_REG 2 + +void ip175d_attach(struct ip17x_softc *sc); + +#endif /* __IP175D_H__ */ Added: head/sys/dev/etherswitch/ip17x/ip17x.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/etherswitch/ip17x/ip17x.c Wed May 8 20:58:41 2013 (r250386) @@ -0,0 +1,614 @@ +/*- + * Copyright (c) 2013 Luiz Otavio O Souza. + * Copyright (c) 2011-2012 Stefan Bethke. + * Copyright (c) 2012 Adrian Chadd. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "mdio_if.h" +#include "miibus_if.h" +#include "etherswitch_if.h" + +MALLOC_DECLARE(M_IP17X); +MALLOC_DEFINE(M_IP17X, "ip17x", "ip17x data structures"); + +static void ip17x_tick(void *); +static int ip17x_ifmedia_upd(struct ifnet *); +static void ip17x_ifmedia_sts(struct ifnet *, struct ifmediareq *); + +static int +ip17x_probe(device_t dev) +{ + struct ip17x_softc *sc; + uint32_t oui, model, phy_id1, phy_id2; + + sc = device_get_softc(dev); + + /* Read ID from PHY 0. */ + phy_id1 = MDIO_READREG(device_get_parent(dev), 0, MII_PHYIDR1); + phy_id2 = MDIO_READREG(device_get_parent(dev), 0, MII_PHYIDR2); + + oui = MII_OUI(phy_id1, phy_id2), + model = MII_MODEL(phy_id2); + /* We only care about IC+ devices. */ + if (oui != IP17X_OUI) { + device_printf(dev, + "Unsupported IC+ switch. Unknown OUI: %#x\n", oui); + return (ENXIO); + } + + switch (model) { + case IP17X_IP175A: + sc->sc_switchtype = IP17X_SWITCH_IP175A; + break; + case IP17X_IP175C: + sc->sc_switchtype = IP17X_SWITCH_IP175C; + break; + default: + device_printf(dev, "Unsupported IC+ switch model: %#x\n", + model); + return (ENXIO); + } + + /* IP175D has a specific ID register. */ + model = MDIO_READREG(device_get_parent(dev), IP175D_ID_PHY, + IP175D_ID_REG); + if (model == 0x175d) + sc->sc_switchtype = IP17X_SWITCH_IP175D; + else { + /* IP178 has more PHYs. Try it. */ + model = MDIO_READREG(device_get_parent(dev), 5, MII_PHYIDR1); + if (phy_id1 == model) + sc->sc_switchtype = IP17X_SWITCH_IP178C; + } + + device_set_desc_copy(dev, "IC+ IP17x switch driver"); + return (BUS_PROBE_DEFAULT); +} + +static int +ip17x_attach_phys(struct ip17x_softc *sc) +{ + int err, phy, port; + char name[IFNAMSIZ]; + + port = err = 0; + + /* PHYs need an interface, so we generate a dummy one */ + snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->sc_dev)); + for (phy = 0; phy < MII_NPHY; phy++) { + if (((1 << phy) & sc->phymask) == 0) + continue; + sc->phyport[phy] = port; + sc->portphy[port] = phy; + sc->ifp[port] = if_alloc(IFT_ETHER); + sc->ifp[port]->if_softc = sc; + sc->ifp[port]->if_flags |= IFF_UP | IFF_BROADCAST | + IFF_DRV_RUNNING | IFF_SIMPLEX; + sc->ifname[port] = malloc(strlen(name)+1, M_IP17X, M_WAITOK); + bcopy(name, sc->ifname[port], strlen(name)+1); + if_initname(sc->ifp[port], sc->ifname[port], port); + sc->miibus[port] = malloc(sizeof(device_t), M_IP17X, + M_WAITOK | M_ZERO); + err = mii_attach(sc->sc_dev, sc->miibus[port], sc->ifp[port], + ip17x_ifmedia_upd, ip17x_ifmedia_sts, \ + BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0); + DPRINTF(sc->sc_dev, "%s attached to pseudo interface %s\n", + device_get_nameunit(*sc->miibus[port]), + sc->ifp[port]->if_xname); + if (err != 0) { + device_printf(sc->sc_dev, + "attaching PHY %d failed\n", + phy); + break; + } + sc->info.es_nports = port + 1; + if (++port >= sc->numports) + break; + } + return (err); +} + +static int +ip17x_attach(device_t dev) +{ + struct ip17x_softc *sc; + int err; + + sc = device_get_softc(dev); + + sc->sc_dev = dev; + mtx_init(&sc->sc_mtx, "ip17x", NULL, MTX_DEF); + strlcpy(sc->info.es_name, device_get_desc(dev), + sizeof(sc->info.es_name)); + + /* XXX Defaults */ + sc->phymask = 0x0f; + sc->media = 100; + + (void) resource_int_value(device_get_name(dev), device_get_unit(dev), + "phymask", &sc->phymask); + + /* Number of vlans supported by the switch. */ + sc->info.es_nvlangroups = IP17X_MAX_VLANS; + + /* Attach the switch related functions. */ + if (IP17X_IS_SWITCH(sc, IP175C)) + ip175c_attach(sc); + else if (IP17X_IS_SWITCH(sc, IP175D)) + ip175d_attach(sc); + else + /* We don't have support to all the models yet :-/ */ + return (ENXIO); + + /* Always attach the cpu port. */ + sc->phymask |= (1 << sc->cpuport); + + sc->ifp = malloc(sizeof(struct ifnet *) * sc->numports, M_IP17X, + M_WAITOK | M_ZERO); + sc->pvid = malloc(sizeof(uint32_t) * sc->numports, M_IP17X, + M_WAITOK | M_ZERO); + sc->ifname = malloc(sizeof(char *) * sc->numports, M_IP17X, + M_WAITOK | M_ZERO); + sc->miibus = malloc(sizeof(device_t *) * sc->numports, M_IP17X, + M_WAITOK | M_ZERO); + sc->portphy = malloc(sizeof(int) * sc->numports, M_IP17X, + M_WAITOK | M_ZERO); + + /* Initialize the switch. */ + sc->hal.ip17x_reset(sc); + + /* + * Attach the PHYs and complete the bus enumeration. + */ + err = ip17x_attach_phys(sc); + if (err != 0) + return (err); + + /* + * Set the switch to port based vlans or disabled (if not supported + * on this model). + */ + sc->hal.ip17x_set_vlan_mode(sc, ETHERSWITCH_VLAN_PORT); + + bus_generic_probe(dev); + bus_enumerate_hinted_children(dev); + err = bus_generic_attach(dev); + if (err != 0) + return (err); + + callout_init(&sc->callout_tick, 0); + + ip17x_tick(sc); + + return (0); +} + +static int +ip17x_detach(device_t dev) +{ + struct ip17x_softc *sc; + int i, port; + + sc = device_get_softc(dev); + callout_drain(&sc->callout_tick); + + for (i=0; i < MII_NPHY; i++) { + if (((1 << i) & sc->phymask) == 0) + continue; + port = sc->phyport[i]; + if (sc->miibus[port] != NULL) + device_delete_child(dev, (*sc->miibus[port])); + if (sc->ifp[port] != NULL) + if_free(sc->ifp[port]); + free(sc->ifname[port], M_IP17X); + free(sc->miibus[port], M_IP17X); + } + + free(sc->portphy, M_IP17X); + free(sc->miibus, M_IP17X); + free(sc->ifname, M_IP17X); + free(sc->pvid, M_IP17X); + free(sc->ifp, M_IP17X); + + /* Reset the switch. */ + sc->hal.ip17x_reset(sc); + + bus_generic_detach(dev); + mtx_destroy(&sc->sc_mtx); + + return (0); +} + +static inline struct mii_data * +ip17x_miiforport(struct ip17x_softc *sc, int port) +{ + + if (port < 0 || port > sc->numports) + return (NULL); + return (device_get_softc(*sc->miibus[port])); +} + +static inline struct ifnet * +ip17x_ifpforport(struct ip17x_softc *sc, int port) +{ + + if (port < 0 || port > sc->numports) + return (NULL); + return (sc->ifp[port]); +} + +/* + * Poll the status for all PHYs. + */ +static void +ip17x_miipollstat(struct ip17x_softc *sc) +{ + struct mii_softc *miisc; + struct mii_data *mii; + int i, port; + + IP17X_LOCK_ASSERT(sc, MA_NOTOWNED); + + for (i = 0; i < MII_NPHY; i++) { + if (((1 << i) & sc->phymask) == 0) + continue; + port = sc->phyport[i]; + if ((*sc->miibus[port]) == NULL) + continue; + mii = device_get_softc(*sc->miibus[port]); + LIST_FOREACH(miisc, &mii->mii_phys, mii_list) { + if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) != + miisc->mii_inst) + continue; + ukphy_status(miisc); + mii_phy_update(miisc, MII_POLLSTAT); + } + } +} + +static void +ip17x_tick(void *arg) +{ + struct ip17x_softc *sc; + + sc = arg; + ip17x_miipollstat(sc); + callout_reset(&sc->callout_tick, hz, ip17x_tick, sc); +} + +static void +ip17x_lock(device_t dev) +{ + struct ip17x_softc *sc; + + sc = device_get_softc(dev); + IP17X_LOCK_ASSERT(sc, MA_NOTOWNED); + IP17X_LOCK(sc); +} + +static void +ip17x_unlock(device_t dev) +{ + struct ip17x_softc *sc; + + sc = device_get_softc(dev); + IP17X_LOCK_ASSERT(sc, MA_OWNED); + IP17X_UNLOCK(sc); +} + +static etherswitch_info_t * +ip17x_getinfo(device_t dev) +{ + struct ip17x_softc *sc; + + sc = device_get_softc(dev); + return (&sc->info); +} + +static int +ip17x_getport(device_t dev, etherswitch_port_t *p) +{ + struct ip17x_softc *sc; + struct ifmediareq *ifmr; + struct mii_data *mii; + int err, phy; + + sc = device_get_softc(dev); + if (p->es_port < 0 || p->es_port >= sc->numports) + return (ENXIO); + + phy = sc->portphy[p->es_port]; + + /* Retrieve the PVID. */ + p->es_pvid = sc->pvid[phy]; + + /* Port flags. */ + if (sc->addtag & (1 << phy)) + p->es_flags |= ETHERSWITCH_PORT_ADDTAG; + if (sc->striptag & (1 << phy)) + p->es_flags |= ETHERSWITCH_PORT_STRIPTAG; + + ifmr = &p->es_ifmr; + + /* No media settings ? */ + if (p->es_ifmr.ifm_count == 0) + return (0); + + mii = ip17x_miiforport(sc, p->es_port); + if (mii == NULL) + return (ENXIO); + if (phy == sc->cpuport) { + /* fill in fixed values for CPU port */ + p->es_flags |= ETHERSWITCH_PORT_CPU; + ifmr->ifm_count = 0; + if (sc->media == 100) + ifmr->ifm_current = ifmr->ifm_active = + IFM_ETHER | IFM_100_TX | IFM_FDX; + else + ifmr->ifm_current = ifmr->ifm_active = + IFM_ETHER | IFM_1000_T | IFM_FDX; + ifmr->ifm_mask = 0; + ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID; + } else { + err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr, + &mii->mii_media, SIOCGIFMEDIA); + if (err) + return (err); + } + return (0); +} + +static int +ip17x_setport(device_t dev, etherswitch_port_t *p) +{ *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***