1a043e8c7SAdrian Chadd /*- 2*718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*718cf2ccSPedro F. Giffuni * 4a043e8c7SAdrian Chadd * Copyright (c) 2011-2012 Stefan Bethke. 5a043e8c7SAdrian Chadd * Copyright (c) 2012 Adrian Chadd. 6a043e8c7SAdrian Chadd * All rights reserved. 7a043e8c7SAdrian Chadd * 8a043e8c7SAdrian Chadd * Redistribution and use in source and binary forms, with or without 9a043e8c7SAdrian Chadd * modification, are permitted provided that the following conditions 10a043e8c7SAdrian Chadd * are met: 11a043e8c7SAdrian Chadd * 1. Redistributions of source code must retain the above copyright 12a043e8c7SAdrian Chadd * notice, this list of conditions and the following disclaimer. 13a043e8c7SAdrian Chadd * 2. Redistributions in binary form must reproduce the above copyright 14a043e8c7SAdrian Chadd * notice, this list of conditions and the following disclaimer in the 15a043e8c7SAdrian Chadd * documentation and/or other materials provided with the distribution. 16a043e8c7SAdrian Chadd * 17a043e8c7SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18a043e8c7SAdrian Chadd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19a043e8c7SAdrian Chadd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20a043e8c7SAdrian Chadd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21a043e8c7SAdrian Chadd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22a043e8c7SAdrian Chadd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23a043e8c7SAdrian Chadd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24a043e8c7SAdrian Chadd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25a043e8c7SAdrian Chadd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26a043e8c7SAdrian Chadd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27a043e8c7SAdrian Chadd * SUCH DAMAGE. 28a043e8c7SAdrian Chadd * 29a043e8c7SAdrian Chadd * $FreeBSD$ 30a043e8c7SAdrian Chadd */ 31a043e8c7SAdrian Chadd 32a043e8c7SAdrian Chadd #include <sys/param.h> 33a043e8c7SAdrian Chadd #include <sys/bus.h> 34a043e8c7SAdrian Chadd #include <sys/errno.h> 35a043e8c7SAdrian Chadd #include <sys/kernel.h> 36104dc214SGleb Smirnoff #include <sys/malloc.h> 37a043e8c7SAdrian Chadd #include <sys/module.h> 38a043e8c7SAdrian Chadd #include <sys/socket.h> 39a043e8c7SAdrian Chadd #include <sys/sockio.h> 40a043e8c7SAdrian Chadd #include <sys/sysctl.h> 41a043e8c7SAdrian Chadd #include <sys/systm.h> 42a043e8c7SAdrian Chadd 43a043e8c7SAdrian Chadd #include <net/if.h> 44104dc214SGleb Smirnoff #include <net/if_var.h> 45a043e8c7SAdrian Chadd #include <net/if_arp.h> 46a043e8c7SAdrian Chadd #include <net/ethernet.h> 47a043e8c7SAdrian Chadd #include <net/if_dl.h> 48a043e8c7SAdrian Chadd #include <net/if_media.h> 49a043e8c7SAdrian Chadd #include <net/if_types.h> 50a043e8c7SAdrian Chadd 51a043e8c7SAdrian Chadd #include <machine/bus.h> 52efce3748SRui Paulo #include <dev/iicbus/iic.h> 53a043e8c7SAdrian Chadd #include <dev/iicbus/iiconf.h> 54a043e8c7SAdrian Chadd #include <dev/iicbus/iicbus.h> 55a043e8c7SAdrian Chadd #include <dev/mii/mii.h> 56a043e8c7SAdrian Chadd #include <dev/mii/miivar.h> 5771e8eac4SAdrian Chadd #include <dev/mdio/mdio.h> 58a043e8c7SAdrian Chadd 59a043e8c7SAdrian Chadd #include <dev/etherswitch/etherswitch.h> 60a043e8c7SAdrian Chadd 61a043e8c7SAdrian Chadd #include <dev/etherswitch/arswitch/arswitchreg.h> 62a043e8c7SAdrian Chadd #include <dev/etherswitch/arswitch/arswitchvar.h> 63a043e8c7SAdrian Chadd #include <dev/etherswitch/arswitch/arswitch_reg.h> 64a043e8c7SAdrian Chadd #include <dev/etherswitch/arswitch/arswitch_phy.h> 65b9f07b86SLuiz Otavio O Souza #include <dev/etherswitch/arswitch/arswitch_vlans.h> 66a043e8c7SAdrian Chadd 6727a2ecaaSAdrian Chadd #include <dev/etherswitch/arswitch/arswitch_7240.h> 68a043e8c7SAdrian Chadd #include <dev/etherswitch/arswitch/arswitch_8216.h> 69a043e8c7SAdrian Chadd #include <dev/etherswitch/arswitch/arswitch_8226.h> 70a043e8c7SAdrian Chadd #include <dev/etherswitch/arswitch/arswitch_8316.h> 71482d268dSAdrian Chadd #include <dev/etherswitch/arswitch/arswitch_8327.h> 72b2152161SAdrian Chadd #include <dev/etherswitch/arswitch/arswitch_9340.h> 73a043e8c7SAdrian Chadd 74a043e8c7SAdrian Chadd #include "mdio_if.h" 75a043e8c7SAdrian Chadd #include "miibus_if.h" 76a043e8c7SAdrian Chadd #include "etherswitch_if.h" 77a043e8c7SAdrian Chadd 78c94dc808SAdrian Chadd /* Map ETHERSWITCH_PORT_LED_* to Atheros pattern codes */ 79c94dc808SAdrian Chadd static int led_pattern_table[] = { 80c94dc808SAdrian Chadd [ETHERSWITCH_PORT_LED_DEFAULT] = 0x3, 81c94dc808SAdrian Chadd [ETHERSWITCH_PORT_LED_ON] = 0x2, 82c94dc808SAdrian Chadd [ETHERSWITCH_PORT_LED_OFF] = 0x0, 83c94dc808SAdrian Chadd [ETHERSWITCH_PORT_LED_BLINK] = 0x1 84c94dc808SAdrian Chadd }; 85c94dc808SAdrian Chadd 86a043e8c7SAdrian Chadd static inline int arswitch_portforphy(int phy); 87a043e8c7SAdrian Chadd static void arswitch_tick(void *arg); 88a043e8c7SAdrian Chadd static int arswitch_ifmedia_upd(struct ifnet *); 89a043e8c7SAdrian Chadd static void arswitch_ifmedia_sts(struct ifnet *, struct ifmediareq *); 90a9ad4222SAdrian Chadd static int ar8xxx_port_vlan_setup(struct arswitch_softc *sc, 91a9ad4222SAdrian Chadd etherswitch_port_t *p); 92a9ad4222SAdrian Chadd static int ar8xxx_port_vlan_get(struct arswitch_softc *sc, 93a9ad4222SAdrian Chadd etherswitch_port_t *p); 94c94dc808SAdrian Chadd static int arswitch_setled(struct arswitch_softc *sc, int phy, int led, 95c94dc808SAdrian Chadd int style); 96a043e8c7SAdrian Chadd 97a043e8c7SAdrian Chadd static int 98a043e8c7SAdrian Chadd arswitch_probe(device_t dev) 99a043e8c7SAdrian Chadd { 100a043e8c7SAdrian Chadd struct arswitch_softc *sc; 101a043e8c7SAdrian Chadd uint32_t id; 102a043e8c7SAdrian Chadd char *chipname, desc[256]; 103a043e8c7SAdrian Chadd 104a043e8c7SAdrian Chadd sc = device_get_softc(dev); 105a043e8c7SAdrian Chadd bzero(sc, sizeof(*sc)); 106a043e8c7SAdrian Chadd sc->page = -1; 10727a2ecaaSAdrian Chadd 10827a2ecaaSAdrian Chadd /* AR7240 probe */ 10927a2ecaaSAdrian Chadd if (ar7240_probe(dev) == 0) { 11027a2ecaaSAdrian Chadd chipname = "AR7240"; 11127a2ecaaSAdrian Chadd sc->sc_switchtype = AR8X16_SWITCH_AR7240; 112b2152161SAdrian Chadd sc->is_internal_switch = 1; 113b2152161SAdrian Chadd id = 0; 114b2152161SAdrian Chadd goto done; 115b2152161SAdrian Chadd } 116b2152161SAdrian Chadd 117b2152161SAdrian Chadd /* AR9340 probe */ 118b2152161SAdrian Chadd if (ar9340_probe(dev) == 0) { 119b2152161SAdrian Chadd chipname = "AR9340"; 120b2152161SAdrian Chadd sc->sc_switchtype = AR8X16_SWITCH_AR9340; 121b2152161SAdrian Chadd sc->is_internal_switch = 1; 122daa4deacSAleksandr Rybalko id = 0; 12327a2ecaaSAdrian Chadd goto done; 12427a2ecaaSAdrian Chadd } 12527a2ecaaSAdrian Chadd 12627a2ecaaSAdrian Chadd /* AR8xxx probe */ 127a043e8c7SAdrian Chadd id = arswitch_readreg(dev, AR8X16_REG_MASK_CTRL); 128dd843f87SAdrian Chadd sc->chip_rev = (id & AR8X16_MASK_CTRL_REV_MASK); 129dd843f87SAdrian Chadd sc->chip_ver = (id & AR8X16_MASK_CTRL_VER_MASK) > AR8X16_MASK_CTRL_VER_SHIFT; 130b2152161SAdrian Chadd switch (id & (AR8X16_MASK_CTRL_VER_MASK | AR8X16_MASK_CTRL_REV_MASK)) { 131b2152161SAdrian Chadd case 0x0101: 132a043e8c7SAdrian Chadd chipname = "AR8216"; 133a043e8c7SAdrian Chadd sc->sc_switchtype = AR8X16_SWITCH_AR8216; 134a043e8c7SAdrian Chadd break; 135b2152161SAdrian Chadd case 0x0201: 136a043e8c7SAdrian Chadd chipname = "AR8226"; 137a043e8c7SAdrian Chadd sc->sc_switchtype = AR8X16_SWITCH_AR8226; 138a043e8c7SAdrian Chadd break; 139b2152161SAdrian Chadd /* 0x0301 - AR8236 */ 140b2152161SAdrian Chadd case 0x1000: 141b2152161SAdrian Chadd case 0x1001: 142a043e8c7SAdrian Chadd chipname = "AR8316"; 143a043e8c7SAdrian Chadd sc->sc_switchtype = AR8X16_SWITCH_AR8316; 144a043e8c7SAdrian Chadd break; 1450e67bf94SAdrian Chadd case 0x1202: 1469682e347SAdrian Chadd case 0x1204: 1470e67bf94SAdrian Chadd chipname = "AR8327"; 1480e67bf94SAdrian Chadd sc->sc_switchtype = AR8X16_SWITCH_AR8327; 1490e67bf94SAdrian Chadd sc->mii_lo_first = 1; 1500e67bf94SAdrian Chadd break; 151a043e8c7SAdrian Chadd default: 152a043e8c7SAdrian Chadd chipname = NULL; 153a043e8c7SAdrian Chadd } 15427a2ecaaSAdrian Chadd 15527a2ecaaSAdrian Chadd done: 156b2152161SAdrian Chadd 1571b334c8bSAdrian Chadd DPRINTF(sc, ARSWITCH_DBG_ANY, "chipname=%s, id=%08x\n", chipname, id); 158a043e8c7SAdrian Chadd if (chipname != NULL) { 159a043e8c7SAdrian Chadd snprintf(desc, sizeof(desc), 16078549b94SAdrian Chadd "Atheros %s Ethernet Switch (ver %d rev %d)", 16178549b94SAdrian Chadd chipname, 16278549b94SAdrian Chadd sc->chip_ver, 16378549b94SAdrian Chadd sc->chip_rev); 164a043e8c7SAdrian Chadd device_set_desc_copy(dev, desc); 165a043e8c7SAdrian Chadd return (BUS_PROBE_DEFAULT); 166a043e8c7SAdrian Chadd } 167a043e8c7SAdrian Chadd return (ENXIO); 168a043e8c7SAdrian Chadd } 169a043e8c7SAdrian Chadd 170a043e8c7SAdrian Chadd static int 171a043e8c7SAdrian Chadd arswitch_attach_phys(struct arswitch_softc *sc) 172a043e8c7SAdrian Chadd { 173a043e8c7SAdrian Chadd int phy, err = 0; 174a043e8c7SAdrian Chadd char name[IFNAMSIZ]; 175a043e8c7SAdrian Chadd 176a043e8c7SAdrian Chadd /* PHYs need an interface, so we generate a dummy one */ 177a043e8c7SAdrian Chadd snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->sc_dev)); 178a043e8c7SAdrian Chadd for (phy = 0; phy < sc->numphys; phy++) { 179a043e8c7SAdrian Chadd sc->ifp[phy] = if_alloc(IFT_ETHER); 180a043e8c7SAdrian Chadd sc->ifp[phy]->if_softc = sc; 181a043e8c7SAdrian Chadd sc->ifp[phy]->if_flags |= IFF_UP | IFF_BROADCAST | 182a043e8c7SAdrian Chadd IFF_DRV_RUNNING | IFF_SIMPLEX; 183a043e8c7SAdrian Chadd sc->ifname[phy] = malloc(strlen(name)+1, M_DEVBUF, M_WAITOK); 184a043e8c7SAdrian Chadd bcopy(name, sc->ifname[phy], strlen(name)+1); 185a043e8c7SAdrian Chadd if_initname(sc->ifp[phy], sc->ifname[phy], 186a043e8c7SAdrian Chadd arswitch_portforphy(phy)); 187a043e8c7SAdrian Chadd err = mii_attach(sc->sc_dev, &sc->miibus[phy], sc->ifp[phy], 188a043e8c7SAdrian Chadd arswitch_ifmedia_upd, arswitch_ifmedia_sts, \ 189a043e8c7SAdrian Chadd BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0); 19078549b94SAdrian Chadd #if 0 191a043e8c7SAdrian Chadd DPRINTF(sc->sc_dev, "%s attached to pseudo interface %s\n", 192a043e8c7SAdrian Chadd device_get_nameunit(sc->miibus[phy]), 193a043e8c7SAdrian Chadd sc->ifp[phy]->if_xname); 19478549b94SAdrian Chadd #endif 195a043e8c7SAdrian Chadd if (err != 0) { 196a043e8c7SAdrian Chadd device_printf(sc->sc_dev, 197a043e8c7SAdrian Chadd "attaching PHY %d failed\n", 198a043e8c7SAdrian Chadd phy); 199a043e8c7SAdrian Chadd return (err); 200a043e8c7SAdrian Chadd } 201a043e8c7SAdrian Chadd 202c94dc808SAdrian Chadd if (AR8X16_IS_SWITCH(sc, AR8327)) { 203c94dc808SAdrian Chadd int led; 204c94dc808SAdrian Chadd char ledname[IFNAMSIZ+4]; 205c94dc808SAdrian Chadd 206c94dc808SAdrian Chadd for (led = 0; led < 3; led++) { 207c94dc808SAdrian Chadd sprintf(ledname, "%s%dled%d", name, 208c94dc808SAdrian Chadd arswitch_portforphy(phy), led+1); 209c94dc808SAdrian Chadd sc->dev_led[phy][led].sc = sc; 210c94dc808SAdrian Chadd sc->dev_led[phy][led].phy = phy; 211c94dc808SAdrian Chadd sc->dev_led[phy][led].lednum = led; 212c94dc808SAdrian Chadd } 213c94dc808SAdrian Chadd } 214c94dc808SAdrian Chadd } 215c94dc808SAdrian Chadd return (0); 216c94dc808SAdrian Chadd } 217c94dc808SAdrian Chadd 218a043e8c7SAdrian Chadd static int 219b9f07b86SLuiz Otavio O Souza arswitch_reset(device_t dev) 220b9f07b86SLuiz Otavio O Souza { 221b9f07b86SLuiz Otavio O Souza 222b9f07b86SLuiz Otavio O Souza arswitch_writereg(dev, AR8X16_REG_MASK_CTRL, 223b9f07b86SLuiz Otavio O Souza AR8X16_MASK_CTRL_SOFT_RESET); 224b9f07b86SLuiz Otavio O Souza DELAY(1000); 225b9f07b86SLuiz Otavio O Souza if (arswitch_readreg(dev, AR8X16_REG_MASK_CTRL) & 226b9f07b86SLuiz Otavio O Souza AR8X16_MASK_CTRL_SOFT_RESET) { 227b9f07b86SLuiz Otavio O Souza device_printf(dev, "unable to reset switch\n"); 228b9f07b86SLuiz Otavio O Souza return (-1); 229b9f07b86SLuiz Otavio O Souza } 230b9f07b86SLuiz Otavio O Souza return (0); 231b9f07b86SLuiz Otavio O Souza } 232b9f07b86SLuiz Otavio O Souza 233b9f07b86SLuiz Otavio O Souza static int 234b9f07b86SLuiz Otavio O Souza arswitch_set_vlan_mode(struct arswitch_softc *sc, uint32_t mode) 235b9f07b86SLuiz Otavio O Souza { 236b9f07b86SLuiz Otavio O Souza 237b9f07b86SLuiz Otavio O Souza /* Check for invalid modes. */ 238b9f07b86SLuiz Otavio O Souza if ((mode & sc->info.es_vlan_caps) != mode) 239b9f07b86SLuiz Otavio O Souza return (EINVAL); 240b9f07b86SLuiz Otavio O Souza 241b9f07b86SLuiz Otavio O Souza switch (mode) { 242b9f07b86SLuiz Otavio O Souza case ETHERSWITCH_VLAN_DOT1Q: 243b9f07b86SLuiz Otavio O Souza sc->vlan_mode = ETHERSWITCH_VLAN_DOT1Q; 244b9f07b86SLuiz Otavio O Souza break; 245b9f07b86SLuiz Otavio O Souza case ETHERSWITCH_VLAN_PORT: 246b9f07b86SLuiz Otavio O Souza sc->vlan_mode = ETHERSWITCH_VLAN_PORT; 247b9f07b86SLuiz Otavio O Souza break; 248b9f07b86SLuiz Otavio O Souza default: 249b9f07b86SLuiz Otavio O Souza sc->vlan_mode = 0; 25074b8d63dSPedro F. Giffuni } 251b9f07b86SLuiz Otavio O Souza 252b9f07b86SLuiz Otavio O Souza /* Reset VLANs. */ 2536dcbabd7SAdrian Chadd sc->hal.arswitch_vlan_init_hw(sc); 254b9f07b86SLuiz Otavio O Souza 255b9f07b86SLuiz Otavio O Souza return (0); 256b9f07b86SLuiz Otavio O Souza } 257b9f07b86SLuiz Otavio O Souza 258b9f07b86SLuiz Otavio O Souza static void 259a9ad4222SAdrian Chadd ar8xxx_port_init(struct arswitch_softc *sc, int port) 260b9f07b86SLuiz Otavio O Souza { 261b9f07b86SLuiz Otavio O Souza 262b9f07b86SLuiz Otavio O Souza /* Port0 - CPU */ 263df892897SAdrian Chadd if (port == AR8X16_PORT_CPU) { 264b9f07b86SLuiz Otavio O Souza arswitch_writereg(sc->sc_dev, AR8X16_REG_PORT_STS(0), 265b9f07b86SLuiz Otavio O Souza (AR8X16_IS_SWITCH(sc, AR8216) ? 266b9f07b86SLuiz Otavio O Souza AR8X16_PORT_STS_SPEED_100 : AR8X16_PORT_STS_SPEED_1000) | 267b9f07b86SLuiz Otavio O Souza (AR8X16_IS_SWITCH(sc, AR8216) ? 0 : AR8X16_PORT_STS_RXFLOW) | 268b9f07b86SLuiz Otavio O Souza (AR8X16_IS_SWITCH(sc, AR8216) ? 0 : AR8X16_PORT_STS_TXFLOW) | 269b9f07b86SLuiz Otavio O Souza AR8X16_PORT_STS_RXMAC | 270b9f07b86SLuiz Otavio O Souza AR8X16_PORT_STS_TXMAC | 271b9f07b86SLuiz Otavio O Souza AR8X16_PORT_STS_DUPLEX); 272b9f07b86SLuiz Otavio O Souza arswitch_writereg(sc->sc_dev, AR8X16_REG_PORT_CTRL(0), 273b9f07b86SLuiz Otavio O Souza arswitch_readreg(sc->sc_dev, AR8X16_REG_PORT_CTRL(0)) & 274b9f07b86SLuiz Otavio O Souza ~AR8X16_PORT_CTRL_HEADER); 275df892897SAdrian Chadd } else { 276b9f07b86SLuiz Otavio O Souza /* Set ports to auto negotiation. */ 277b9f07b86SLuiz Otavio O Souza arswitch_writereg(sc->sc_dev, AR8X16_REG_PORT_STS(port), 278b9f07b86SLuiz Otavio O Souza AR8X16_PORT_STS_LINK_AUTO); 279b9f07b86SLuiz Otavio O Souza arswitch_writereg(sc->sc_dev, AR8X16_REG_PORT_CTRL(port), 280b9f07b86SLuiz Otavio O Souza arswitch_readreg(sc->sc_dev, AR8X16_REG_PORT_CTRL(port)) & 281b9f07b86SLuiz Otavio O Souza ~AR8X16_PORT_CTRL_HEADER); 282b9f07b86SLuiz Otavio O Souza } 283b9f07b86SLuiz Otavio O Souza } 284b9f07b86SLuiz Otavio O Souza 285b9f07b86SLuiz Otavio O Souza static int 2864ff2f60dSAdrian Chadd ar8xxx_atu_flush(struct arswitch_softc *sc) 2874ff2f60dSAdrian Chadd { 2884ff2f60dSAdrian Chadd int ret; 2894ff2f60dSAdrian Chadd 2904ff2f60dSAdrian Chadd ret = arswitch_waitreg(sc->sc_dev, 2914ff2f60dSAdrian Chadd AR8216_REG_ATU, 2924ff2f60dSAdrian Chadd AR8216_ATU_ACTIVE, 2934ff2f60dSAdrian Chadd 0, 2944ff2f60dSAdrian Chadd 1000); 2954ff2f60dSAdrian Chadd 2964ff2f60dSAdrian Chadd if (ret) 2974ff2f60dSAdrian Chadd device_printf(sc->sc_dev, "%s: waitreg failed\n", __func__); 2984ff2f60dSAdrian Chadd 2994ff2f60dSAdrian Chadd if (!ret) 3004ff2f60dSAdrian Chadd arswitch_writereg(sc->sc_dev, 3014ff2f60dSAdrian Chadd AR8216_REG_ATU, 3024ff2f60dSAdrian Chadd AR8216_ATU_OP_FLUSH); 3034ff2f60dSAdrian Chadd 3044ff2f60dSAdrian Chadd return (ret); 3054ff2f60dSAdrian Chadd } 3064ff2f60dSAdrian Chadd 3074ff2f60dSAdrian Chadd static int 308a043e8c7SAdrian Chadd arswitch_attach(device_t dev) 309a043e8c7SAdrian Chadd { 3101b334c8bSAdrian Chadd struct arswitch_softc *sc = device_get_softc(dev); 3111b334c8bSAdrian Chadd struct sysctl_ctx_list *ctx; 3121b334c8bSAdrian Chadd struct sysctl_oid *tree; 313a043e8c7SAdrian Chadd int err = 0; 314df892897SAdrian Chadd int port; 315a043e8c7SAdrian Chadd 316a043e8c7SAdrian Chadd /* sc->sc_switchtype is already decided in arswitch_probe() */ 317a043e8c7SAdrian Chadd sc->sc_dev = dev; 318a043e8c7SAdrian Chadd mtx_init(&sc->sc_mtx, "arswitch", NULL, MTX_DEF); 319a043e8c7SAdrian Chadd sc->page = -1; 320a043e8c7SAdrian Chadd strlcpy(sc->info.es_name, device_get_desc(dev), 321a043e8c7SAdrian Chadd sizeof(sc->info.es_name)); 322a043e8c7SAdrian Chadd 3231b334c8bSAdrian Chadd /* Debugging */ 3241b334c8bSAdrian Chadd ctx = device_get_sysctl_ctx(sc->sc_dev); 3251b334c8bSAdrian Chadd tree = device_get_sysctl_tree(sc->sc_dev); 3261b334c8bSAdrian Chadd SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 3271b334c8bSAdrian Chadd "debug", CTLFLAG_RW, &sc->sc_debug, 0, 3281b334c8bSAdrian Chadd "control debugging printfs"); 3291b334c8bSAdrian Chadd 330ddbc4420SAdrian Chadd /* Default HAL methods */ 331a9ad4222SAdrian Chadd sc->hal.arswitch_port_init = ar8xxx_port_init; 332a9ad4222SAdrian Chadd sc->hal.arswitch_port_vlan_setup = ar8xxx_port_vlan_setup; 333a9ad4222SAdrian Chadd sc->hal.arswitch_port_vlan_get = ar8xxx_port_vlan_get; 3346dcbabd7SAdrian Chadd sc->hal.arswitch_vlan_init_hw = ar8xxx_reset_vlans; 335749cac13SAdrian Chadd 3366dcbabd7SAdrian Chadd sc->hal.arswitch_vlan_getvgroup = ar8xxx_getvgroup; 3376dcbabd7SAdrian Chadd sc->hal.arswitch_vlan_setvgroup = ar8xxx_setvgroup; 338749cac13SAdrian Chadd 3396dcbabd7SAdrian Chadd sc->hal.arswitch_vlan_get_pvid = ar8xxx_get_pvid; 3406dcbabd7SAdrian Chadd sc->hal.arswitch_vlan_set_pvid = ar8xxx_set_pvid; 341749cac13SAdrian Chadd 342749cac13SAdrian Chadd sc->hal.arswitch_get_dot1q_vlan = ar8xxx_get_dot1q_vlan; 343749cac13SAdrian Chadd sc->hal.arswitch_set_dot1q_vlan = ar8xxx_set_dot1q_vlan; 344f35f94f4SAdrian Chadd sc->hal.arswitch_flush_dot1q_vlan = ar8xxx_flush_dot1q_vlan; 345f35f94f4SAdrian Chadd sc->hal.arswitch_purge_dot1q_vlan = ar8xxx_purge_dot1q_vlan; 346749cac13SAdrian Chadd sc->hal.arswitch_get_port_vlan = ar8xxx_get_port_vlan; 347749cac13SAdrian Chadd sc->hal.arswitch_set_port_vlan = ar8xxx_set_port_vlan; 348749cac13SAdrian Chadd 3494ff2f60dSAdrian Chadd sc->hal.arswitch_atu_flush = ar8xxx_atu_flush; 350749cac13SAdrian Chadd 35178549b94SAdrian Chadd sc->hal.arswitch_phy_read = arswitch_readphy_internal; 35278549b94SAdrian Chadd sc->hal.arswitch_phy_write = arswitch_writephy_internal; 353ddbc4420SAdrian Chadd 354749cac13SAdrian Chadd 355a043e8c7SAdrian Chadd /* 356a043e8c7SAdrian Chadd * Attach switch related functions 357a043e8c7SAdrian Chadd */ 35827a2ecaaSAdrian Chadd if (AR8X16_IS_SWITCH(sc, AR7240)) 35927a2ecaaSAdrian Chadd ar7240_attach(sc); 360b2152161SAdrian Chadd else if (AR8X16_IS_SWITCH(sc, AR9340)) 361b2152161SAdrian Chadd ar9340_attach(sc); 36227a2ecaaSAdrian Chadd else if (AR8X16_IS_SWITCH(sc, AR8216)) 363a043e8c7SAdrian Chadd ar8216_attach(sc); 364a043e8c7SAdrian Chadd else if (AR8X16_IS_SWITCH(sc, AR8226)) 365a043e8c7SAdrian Chadd ar8226_attach(sc); 366a043e8c7SAdrian Chadd else if (AR8X16_IS_SWITCH(sc, AR8316)) 367a043e8c7SAdrian Chadd ar8316_attach(sc); 368482d268dSAdrian Chadd else if (AR8X16_IS_SWITCH(sc, AR8327)) 369482d268dSAdrian Chadd ar8327_attach(sc); 37078549b94SAdrian Chadd else { 3711b334c8bSAdrian Chadd DPRINTF(sc, ARSWITCH_DBG_ANY, 3721b334c8bSAdrian Chadd "%s: unknown switch (%d)?\n", __func__, sc->sc_switchtype); 373a043e8c7SAdrian Chadd return (ENXIO); 37478549b94SAdrian Chadd } 375a043e8c7SAdrian Chadd 376b9f07b86SLuiz Otavio O Souza /* Common defaults. */ 377a043e8c7SAdrian Chadd sc->info.es_nports = 5; /* XXX technically 6, but 6th not used */ 378a043e8c7SAdrian Chadd 379a043e8c7SAdrian Chadd /* XXX Defaults for externally connected AR8316 */ 380a043e8c7SAdrian Chadd sc->numphys = 4; 381a043e8c7SAdrian Chadd sc->phy4cpu = 1; 382a043e8c7SAdrian Chadd sc->is_rgmii = 1; 383a043e8c7SAdrian Chadd sc->is_gmii = 0; 384b2152161SAdrian Chadd sc->is_mii = 0; 385a043e8c7SAdrian Chadd 386a043e8c7SAdrian Chadd (void) resource_int_value(device_get_name(dev), device_get_unit(dev), 387a043e8c7SAdrian Chadd "numphys", &sc->numphys); 388a043e8c7SAdrian Chadd (void) resource_int_value(device_get_name(dev), device_get_unit(dev), 389a043e8c7SAdrian Chadd "phy4cpu", &sc->phy4cpu); 390a043e8c7SAdrian Chadd (void) resource_int_value(device_get_name(dev), device_get_unit(dev), 391a043e8c7SAdrian Chadd "is_rgmii", &sc->is_rgmii); 392a043e8c7SAdrian Chadd (void) resource_int_value(device_get_name(dev), device_get_unit(dev), 393a043e8c7SAdrian Chadd "is_gmii", &sc->is_gmii); 394b2152161SAdrian Chadd (void) resource_int_value(device_get_name(dev), device_get_unit(dev), 395b2152161SAdrian Chadd "is_mii", &sc->is_mii); 396a043e8c7SAdrian Chadd 397b9f07b86SLuiz Otavio O Souza if (sc->numphys > AR8X16_NUM_PHYS) 398b9f07b86SLuiz Otavio O Souza sc->numphys = AR8X16_NUM_PHYS; 399a043e8c7SAdrian Chadd 400b9f07b86SLuiz Otavio O Souza /* Reset the switch. */ 40178549b94SAdrian Chadd if (arswitch_reset(dev)) { 4021b334c8bSAdrian Chadd DPRINTF(sc, ARSWITCH_DBG_ANY, 4031b334c8bSAdrian Chadd "%s: arswitch_reset: failed\n", __func__); 404b9f07b86SLuiz Otavio O Souza return (ENXIO); 40578549b94SAdrian Chadd } 406a043e8c7SAdrian Chadd 407b2152161SAdrian Chadd err = sc->hal.arswitch_hw_setup(sc); 4081b334c8bSAdrian Chadd if (err != 0) { 4091b334c8bSAdrian Chadd DPRINTF(sc, ARSWITCH_DBG_ANY, 4101b334c8bSAdrian Chadd "%s: hw_setup: err=%d\n", __func__, err); 411b2152161SAdrian Chadd return (err); 4121b334c8bSAdrian Chadd } 413b2152161SAdrian Chadd 414a043e8c7SAdrian Chadd err = sc->hal.arswitch_hw_global_setup(sc); 4151b334c8bSAdrian Chadd if (err != 0) { 4161b334c8bSAdrian Chadd DPRINTF(sc, ARSWITCH_DBG_ANY, 4171b334c8bSAdrian Chadd "%s: hw_global_setup: err=%d\n", __func__, err); 418a043e8c7SAdrian Chadd return (err); 4191b334c8bSAdrian Chadd } 420a043e8c7SAdrian Chadd 421b9f07b86SLuiz Otavio O Souza /* Initialize the switch ports. */ 422df892897SAdrian Chadd for (port = 0; port <= sc->numphys; port++) { 423ddbc4420SAdrian Chadd sc->hal.arswitch_port_init(sc, port); 424df892897SAdrian Chadd } 425b9f07b86SLuiz Otavio O Souza 426a043e8c7SAdrian Chadd /* 427a043e8c7SAdrian Chadd * Attach the PHYs and complete the bus enumeration. 428a043e8c7SAdrian Chadd */ 429a043e8c7SAdrian Chadd err = arswitch_attach_phys(sc); 4301b334c8bSAdrian Chadd if (err != 0) { 4311b334c8bSAdrian Chadd DPRINTF(sc, ARSWITCH_DBG_ANY, 4321b334c8bSAdrian Chadd "%s: attach_phys: err=%d\n", __func__, err); 433a043e8c7SAdrian Chadd return (err); 4341b334c8bSAdrian Chadd } 435a043e8c7SAdrian Chadd 436b9f07b86SLuiz Otavio O Souza /* Default to ingress filters off. */ 437b9f07b86SLuiz Otavio O Souza err = arswitch_set_vlan_mode(sc, 0); 4381b334c8bSAdrian Chadd if (err != 0) { 4391b334c8bSAdrian Chadd DPRINTF(sc, ARSWITCH_DBG_ANY, 4401b334c8bSAdrian Chadd "%s: set_vlan_mode: err=%d\n", __func__, err); 441b9f07b86SLuiz Otavio O Souza return (err); 4421b334c8bSAdrian Chadd } 443b9f07b86SLuiz Otavio O Souza 444a043e8c7SAdrian Chadd bus_generic_probe(dev); 445a043e8c7SAdrian Chadd bus_enumerate_hinted_children(dev); 446a043e8c7SAdrian Chadd err = bus_generic_attach(dev); 4471b334c8bSAdrian Chadd if (err != 0) { 4481b334c8bSAdrian Chadd DPRINTF(sc, ARSWITCH_DBG_ANY, 4491b334c8bSAdrian Chadd "%s: bus_generic_attach: err=%d\n", __func__, err); 450a043e8c7SAdrian Chadd return (err); 4511b334c8bSAdrian Chadd } 452a043e8c7SAdrian Chadd 453a043e8c7SAdrian Chadd callout_init_mtx(&sc->callout_tick, &sc->sc_mtx, 0); 454454d507aSAleksandr Rybalko 455454d507aSAleksandr Rybalko ARSWITCH_LOCK(sc); 456a043e8c7SAdrian Chadd arswitch_tick(sc); 457454d507aSAleksandr Rybalko ARSWITCH_UNLOCK(sc); 458a043e8c7SAdrian Chadd 459a043e8c7SAdrian Chadd return (err); 460a043e8c7SAdrian Chadd } 461a043e8c7SAdrian Chadd 462a043e8c7SAdrian Chadd static int 463a043e8c7SAdrian Chadd arswitch_detach(device_t dev) 464a043e8c7SAdrian Chadd { 465a043e8c7SAdrian Chadd struct arswitch_softc *sc = device_get_softc(dev); 466a043e8c7SAdrian Chadd int i; 467a043e8c7SAdrian Chadd 468a043e8c7SAdrian Chadd callout_drain(&sc->callout_tick); 469a043e8c7SAdrian Chadd 470a043e8c7SAdrian Chadd for (i=0; i < sc->numphys; i++) { 471a043e8c7SAdrian Chadd if (sc->miibus[i] != NULL) 472a043e8c7SAdrian Chadd device_delete_child(dev, sc->miibus[i]); 473a043e8c7SAdrian Chadd if (sc->ifp[i] != NULL) 474a043e8c7SAdrian Chadd if_free(sc->ifp[i]); 475a043e8c7SAdrian Chadd free(sc->ifname[i], M_DEVBUF); 476a043e8c7SAdrian Chadd } 477a043e8c7SAdrian Chadd 478a043e8c7SAdrian Chadd bus_generic_detach(dev); 479a043e8c7SAdrian Chadd mtx_destroy(&sc->sc_mtx); 480a043e8c7SAdrian Chadd 481a043e8c7SAdrian Chadd return (0); 482a043e8c7SAdrian Chadd } 483a043e8c7SAdrian Chadd 484a043e8c7SAdrian Chadd /* 485a043e8c7SAdrian Chadd * Convert PHY number to port number. PHY0 is connected to port 1, PHY1 to 486a043e8c7SAdrian Chadd * port 2, etc. 487a043e8c7SAdrian Chadd */ 488a043e8c7SAdrian Chadd static inline int 489a043e8c7SAdrian Chadd arswitch_portforphy(int phy) 490a043e8c7SAdrian Chadd { 491a043e8c7SAdrian Chadd return (phy+1); 492a043e8c7SAdrian Chadd } 493a043e8c7SAdrian Chadd 494a043e8c7SAdrian Chadd static inline struct mii_data * 495a043e8c7SAdrian Chadd arswitch_miiforport(struct arswitch_softc *sc, int port) 496a043e8c7SAdrian Chadd { 497a043e8c7SAdrian Chadd int phy = port-1; 498a043e8c7SAdrian Chadd 499a043e8c7SAdrian Chadd if (phy < 0 || phy >= sc->numphys) 500a043e8c7SAdrian Chadd return (NULL); 501a043e8c7SAdrian Chadd return (device_get_softc(sc->miibus[phy])); 502a043e8c7SAdrian Chadd } 503a043e8c7SAdrian Chadd 504a043e8c7SAdrian Chadd static inline struct ifnet * 505a043e8c7SAdrian Chadd arswitch_ifpforport(struct arswitch_softc *sc, int port) 506a043e8c7SAdrian Chadd { 507a043e8c7SAdrian Chadd int phy = port-1; 508a043e8c7SAdrian Chadd 509a043e8c7SAdrian Chadd if (phy < 0 || phy >= sc->numphys) 510a043e8c7SAdrian Chadd return (NULL); 511a043e8c7SAdrian Chadd return (sc->ifp[phy]); 512a043e8c7SAdrian Chadd } 513a043e8c7SAdrian Chadd 514a043e8c7SAdrian Chadd /* 515a043e8c7SAdrian Chadd * Convert port status to ifmedia. 516a043e8c7SAdrian Chadd */ 517a043e8c7SAdrian Chadd static void 518a043e8c7SAdrian Chadd arswitch_update_ifmedia(int portstatus, u_int *media_status, u_int *media_active) 519a043e8c7SAdrian Chadd { 520a043e8c7SAdrian Chadd *media_active = IFM_ETHER; 521a043e8c7SAdrian Chadd *media_status = IFM_AVALID; 522a043e8c7SAdrian Chadd 523a043e8c7SAdrian Chadd if ((portstatus & AR8X16_PORT_STS_LINK_UP) != 0) 524a043e8c7SAdrian Chadd *media_status |= IFM_ACTIVE; 525a043e8c7SAdrian Chadd else { 526a043e8c7SAdrian Chadd *media_active |= IFM_NONE; 527a043e8c7SAdrian Chadd return; 528a043e8c7SAdrian Chadd } 529a043e8c7SAdrian Chadd switch (portstatus & AR8X16_PORT_STS_SPEED_MASK) { 530a043e8c7SAdrian Chadd case AR8X16_PORT_STS_SPEED_10: 531a043e8c7SAdrian Chadd *media_active |= IFM_10_T; 532a043e8c7SAdrian Chadd break; 533a043e8c7SAdrian Chadd case AR8X16_PORT_STS_SPEED_100: 534a043e8c7SAdrian Chadd *media_active |= IFM_100_TX; 535a043e8c7SAdrian Chadd break; 536a043e8c7SAdrian Chadd case AR8X16_PORT_STS_SPEED_1000: 537a043e8c7SAdrian Chadd *media_active |= IFM_1000_T; 538a043e8c7SAdrian Chadd break; 539a043e8c7SAdrian Chadd } 540a043e8c7SAdrian Chadd if ((portstatus & AR8X16_PORT_STS_DUPLEX) == 0) 541a043e8c7SAdrian Chadd *media_active |= IFM_FDX; 542a043e8c7SAdrian Chadd else 543a043e8c7SAdrian Chadd *media_active |= IFM_HDX; 544a043e8c7SAdrian Chadd if ((portstatus & AR8X16_PORT_STS_TXFLOW) != 0) 545a043e8c7SAdrian Chadd *media_active |= IFM_ETH_TXPAUSE; 546a043e8c7SAdrian Chadd if ((portstatus & AR8X16_PORT_STS_RXFLOW) != 0) 547a043e8c7SAdrian Chadd *media_active |= IFM_ETH_RXPAUSE; 548a043e8c7SAdrian Chadd } 549a043e8c7SAdrian Chadd 550a043e8c7SAdrian Chadd /* 551a043e8c7SAdrian Chadd * Poll the status for all PHYs. We're using the switch port status because 552a043e8c7SAdrian Chadd * thats a lot quicker to read than talking to all the PHYs. Care must be 553a043e8c7SAdrian Chadd * taken that the resulting ifmedia_active is identical to what the PHY will 554a043e8c7SAdrian Chadd * compute, or gratuitous link status changes will occur whenever the PHYs 555a043e8c7SAdrian Chadd * update function is called. 556a043e8c7SAdrian Chadd */ 557a043e8c7SAdrian Chadd static void 558a043e8c7SAdrian Chadd arswitch_miipollstat(struct arswitch_softc *sc) 559a043e8c7SAdrian Chadd { 560a043e8c7SAdrian Chadd int i; 561a043e8c7SAdrian Chadd struct mii_data *mii; 562a043e8c7SAdrian Chadd struct mii_softc *miisc; 563a043e8c7SAdrian Chadd int portstatus; 5644ff2f60dSAdrian Chadd int port_flap = 0; 565a043e8c7SAdrian Chadd 566454d507aSAleksandr Rybalko ARSWITCH_LOCK_ASSERT(sc, MA_OWNED); 567454d507aSAleksandr Rybalko 568a043e8c7SAdrian Chadd for (i = 0; i < sc->numphys; i++) { 569a043e8c7SAdrian Chadd if (sc->miibus[i] == NULL) 570a043e8c7SAdrian Chadd continue; 571a043e8c7SAdrian Chadd mii = device_get_softc(sc->miibus[i]); 572ddbc4420SAdrian Chadd /* XXX This would be nice to have abstracted out to be per-chip */ 573ddbc4420SAdrian Chadd /* AR8327/AR8337 has a different register base */ 574ddbc4420SAdrian Chadd if (AR8X16_IS_SWITCH(sc, AR8327)) 575ddbc4420SAdrian Chadd portstatus = arswitch_readreg(sc->sc_dev, 576ddbc4420SAdrian Chadd AR8327_REG_PORT_STATUS(arswitch_portforphy(i))); 577ddbc4420SAdrian Chadd else 578a043e8c7SAdrian Chadd portstatus = arswitch_readreg(sc->sc_dev, 579a043e8c7SAdrian Chadd AR8X16_REG_PORT_STS(arswitch_portforphy(i))); 5801b334c8bSAdrian Chadd #if 1 5811b334c8bSAdrian Chadd DPRINTF(sc, ARSWITCH_DBG_POLL, "p[%d]=0x%08x (%b)\n", 582b2152161SAdrian Chadd i, 583a043e8c7SAdrian Chadd portstatus, 5841b334c8bSAdrian Chadd portstatus, 585a043e8c7SAdrian Chadd "\20\3TXMAC\4RXMAC\5TXFLOW\6RXFLOW\7" 586a043e8c7SAdrian Chadd "DUPLEX\11LINK_UP\12LINK_AUTO\13LINK_PAUSE"); 587a043e8c7SAdrian Chadd #endif 5884ff2f60dSAdrian Chadd /* 5894ff2f60dSAdrian Chadd * If the current status is down, but we have a link 5904ff2f60dSAdrian Chadd * status showing up, we need to do an ATU flush. 5914ff2f60dSAdrian Chadd */ 5924ff2f60dSAdrian Chadd if ((mii->mii_media_status & IFM_ACTIVE) == 0 && 5934ff2f60dSAdrian Chadd (portstatus & AR8X16_PORT_STS_LINK_UP) != 0) { 5944ff2f60dSAdrian Chadd device_printf(sc->sc_dev, "%s: port %d: port -> UP\n", 5954ff2f60dSAdrian Chadd __func__, 5964ff2f60dSAdrian Chadd i); 5974ff2f60dSAdrian Chadd port_flap = 1; 5984ff2f60dSAdrian Chadd } 5994ff2f60dSAdrian Chadd /* 6004ff2f60dSAdrian Chadd * and maybe if a port goes up->down? 6014ff2f60dSAdrian Chadd */ 6024ff2f60dSAdrian Chadd if ((mii->mii_media_status & IFM_ACTIVE) != 0 && 6034ff2f60dSAdrian Chadd (portstatus & AR8X16_PORT_STS_LINK_UP) == 0) { 6044ff2f60dSAdrian Chadd device_printf(sc->sc_dev, "%s: port %d: port -> DOWN\n", 6054ff2f60dSAdrian Chadd __func__, 6064ff2f60dSAdrian Chadd i); 6074ff2f60dSAdrian Chadd port_flap = 1; 6084ff2f60dSAdrian Chadd } 609a043e8c7SAdrian Chadd arswitch_update_ifmedia(portstatus, &mii->mii_media_status, 610a043e8c7SAdrian Chadd &mii->mii_media_active); 611a043e8c7SAdrian Chadd LIST_FOREACH(miisc, &mii->mii_phys, mii_list) { 612a043e8c7SAdrian Chadd if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) != 613a043e8c7SAdrian Chadd miisc->mii_inst) 614a043e8c7SAdrian Chadd continue; 615a043e8c7SAdrian Chadd mii_phy_update(miisc, MII_POLLSTAT); 616a043e8c7SAdrian Chadd } 617a043e8c7SAdrian Chadd } 6184ff2f60dSAdrian Chadd 6194ff2f60dSAdrian Chadd /* If a port went from down->up, flush the ATU */ 6204ff2f60dSAdrian Chadd if (port_flap) 6214ff2f60dSAdrian Chadd sc->hal.arswitch_atu_flush(sc); 622a043e8c7SAdrian Chadd } 623a043e8c7SAdrian Chadd 624a043e8c7SAdrian Chadd static void 625a043e8c7SAdrian Chadd arswitch_tick(void *arg) 626a043e8c7SAdrian Chadd { 627a043e8c7SAdrian Chadd struct arswitch_softc *sc = arg; 628a043e8c7SAdrian Chadd 629a043e8c7SAdrian Chadd arswitch_miipollstat(sc); 630a043e8c7SAdrian Chadd callout_reset(&sc->callout_tick, hz, arswitch_tick, sc); 631a043e8c7SAdrian Chadd } 632a043e8c7SAdrian Chadd 633454d507aSAleksandr Rybalko static void 634454d507aSAleksandr Rybalko arswitch_lock(device_t dev) 635454d507aSAleksandr Rybalko { 636454d507aSAleksandr Rybalko struct arswitch_softc *sc = device_get_softc(dev); 637454d507aSAleksandr Rybalko 638454d507aSAleksandr Rybalko ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED); 639454d507aSAleksandr Rybalko ARSWITCH_LOCK(sc); 640454d507aSAleksandr Rybalko } 641454d507aSAleksandr Rybalko 642454d507aSAleksandr Rybalko static void 643454d507aSAleksandr Rybalko arswitch_unlock(device_t dev) 644454d507aSAleksandr Rybalko { 645454d507aSAleksandr Rybalko struct arswitch_softc *sc = device_get_softc(dev); 646454d507aSAleksandr Rybalko 647454d507aSAleksandr Rybalko ARSWITCH_LOCK_ASSERT(sc, MA_OWNED); 648454d507aSAleksandr Rybalko ARSWITCH_UNLOCK(sc); 649454d507aSAleksandr Rybalko } 650454d507aSAleksandr Rybalko 651a043e8c7SAdrian Chadd static etherswitch_info_t * 652a043e8c7SAdrian Chadd arswitch_getinfo(device_t dev) 653a043e8c7SAdrian Chadd { 654a043e8c7SAdrian Chadd struct arswitch_softc *sc = device_get_softc(dev); 655a043e8c7SAdrian Chadd 656a043e8c7SAdrian Chadd return (&sc->info); 657a043e8c7SAdrian Chadd } 658a043e8c7SAdrian Chadd 659a043e8c7SAdrian Chadd static int 660a9ad4222SAdrian Chadd ar8xxx_port_vlan_get(struct arswitch_softc *sc, etherswitch_port_t *p) 661a043e8c7SAdrian Chadd { 662b9f07b86SLuiz Otavio O Souza uint32_t reg; 663b9f07b86SLuiz Otavio O Souza 664b9f07b86SLuiz Otavio O Souza ARSWITCH_LOCK(sc); 665b9f07b86SLuiz Otavio O Souza 666b9f07b86SLuiz Otavio O Souza /* Retrieve the PVID. */ 6676dcbabd7SAdrian Chadd sc->hal.arswitch_vlan_get_pvid(sc, p->es_port, &p->es_pvid); 668b9f07b86SLuiz Otavio O Souza 669b9f07b86SLuiz Otavio O Souza /* Port flags. */ 670b9f07b86SLuiz Otavio O Souza reg = arswitch_readreg(sc->sc_dev, AR8X16_REG_PORT_CTRL(p->es_port)); 671b9f07b86SLuiz Otavio O Souza if (reg & AR8X16_PORT_CTRL_DOUBLE_TAG) 672b9f07b86SLuiz Otavio O Souza p->es_flags |= ETHERSWITCH_PORT_DOUBLE_TAG; 673b9f07b86SLuiz Otavio O Souza reg >>= AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_SHIFT; 674b9f07b86SLuiz Otavio O Souza if ((reg & 0x3) == AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_ADD) 675b9f07b86SLuiz Otavio O Souza p->es_flags |= ETHERSWITCH_PORT_ADDTAG; 676b9f07b86SLuiz Otavio O Souza if ((reg & 0x3) == AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_STRIP) 677b9f07b86SLuiz Otavio O Souza p->es_flags |= ETHERSWITCH_PORT_STRIPTAG; 678b9f07b86SLuiz Otavio O Souza ARSWITCH_UNLOCK(sc); 679a043e8c7SAdrian Chadd 680a9ad4222SAdrian Chadd return (0); 681a9ad4222SAdrian Chadd } 682a9ad4222SAdrian Chadd 683a9ad4222SAdrian Chadd static int 684749cac13SAdrian Chadd arswitch_is_cpuport(struct arswitch_softc *sc, int port) 685749cac13SAdrian Chadd { 686749cac13SAdrian Chadd 687749cac13SAdrian Chadd return ((port == AR8X16_PORT_CPU) || 688749cac13SAdrian Chadd ((AR8X16_IS_SWITCH(sc, AR8327) && 689749cac13SAdrian Chadd port == AR8327_PORT_GMAC6))); 690749cac13SAdrian Chadd } 691749cac13SAdrian Chadd 692749cac13SAdrian Chadd static int 693a9ad4222SAdrian Chadd arswitch_getport(device_t dev, etherswitch_port_t *p) 694a9ad4222SAdrian Chadd { 695a9ad4222SAdrian Chadd struct arswitch_softc *sc; 696a9ad4222SAdrian Chadd struct mii_data *mii; 697a9ad4222SAdrian Chadd struct ifmediareq *ifmr; 698a9ad4222SAdrian Chadd int err; 699a9ad4222SAdrian Chadd 700a9ad4222SAdrian Chadd sc = device_get_softc(dev); 701749cac13SAdrian Chadd /* XXX +1 is for AR8327; should make this configurable! */ 702749cac13SAdrian Chadd if (p->es_port < 0 || p->es_port > sc->info.es_nports) 703a9ad4222SAdrian Chadd return (ENXIO); 704a9ad4222SAdrian Chadd 705a9ad4222SAdrian Chadd err = sc->hal.arswitch_port_vlan_get(sc, p); 706a9ad4222SAdrian Chadd if (err != 0) 707a9ad4222SAdrian Chadd return (err); 708a9ad4222SAdrian Chadd 709a043e8c7SAdrian Chadd mii = arswitch_miiforport(sc, p->es_port); 710749cac13SAdrian Chadd if (arswitch_is_cpuport(sc, p->es_port)) { 711a043e8c7SAdrian Chadd /* fill in fixed values for CPU port */ 712a9ad4222SAdrian Chadd /* XXX is this valid in all cases? */ 713f47857dcSAdrian Chadd p->es_flags |= ETHERSWITCH_PORT_CPU; 714b9f07b86SLuiz Otavio O Souza ifmr = &p->es_ifmr; 715a043e8c7SAdrian Chadd ifmr->ifm_count = 0; 716a043e8c7SAdrian Chadd ifmr->ifm_current = ifmr->ifm_active = 717a043e8c7SAdrian Chadd IFM_ETHER | IFM_1000_T | IFM_FDX; 718a043e8c7SAdrian Chadd ifmr->ifm_mask = 0; 719a043e8c7SAdrian Chadd ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID; 720a043e8c7SAdrian Chadd } else if (mii != NULL) { 721a043e8c7SAdrian Chadd err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr, 722a043e8c7SAdrian Chadd &mii->mii_media, SIOCGIFMEDIA); 723a043e8c7SAdrian Chadd if (err) 724a043e8c7SAdrian Chadd return (err); 725a043e8c7SAdrian Chadd } else { 726a043e8c7SAdrian Chadd return (ENXIO); 727a043e8c7SAdrian Chadd } 728c94dc808SAdrian Chadd 729c94dc808SAdrian Chadd if (!arswitch_is_cpuport(sc, p->es_port) && 730c94dc808SAdrian Chadd AR8X16_IS_SWITCH(sc, AR8327)) { 731c94dc808SAdrian Chadd int led; 732c94dc808SAdrian Chadd p->es_nleds = 3; 733c94dc808SAdrian Chadd 734c94dc808SAdrian Chadd for (led = 0; led < p->es_nleds; led++) 735c94dc808SAdrian Chadd { 736c94dc808SAdrian Chadd int style; 737c94dc808SAdrian Chadd uint32_t val; 738c94dc808SAdrian Chadd 739c94dc808SAdrian Chadd /* Find the right style enum for our pattern */ 740c94dc808SAdrian Chadd val = arswitch_readreg(dev, 741c94dc808SAdrian Chadd ar8327_led_mapping[p->es_port-1][led].reg); 742c94dc808SAdrian Chadd val = (val>>ar8327_led_mapping[p->es_port-1][led].shift)&0x03; 743c94dc808SAdrian Chadd 744c94dc808SAdrian Chadd for (style = 0; style < ETHERSWITCH_PORT_LED_MAX; style++) 745c94dc808SAdrian Chadd { 746c94dc808SAdrian Chadd if (led_pattern_table[style] == val) break; 747c94dc808SAdrian Chadd } 748c94dc808SAdrian Chadd 749c94dc808SAdrian Chadd /* can't happen */ 750c94dc808SAdrian Chadd if (style == ETHERSWITCH_PORT_LED_MAX) 751c94dc808SAdrian Chadd style = ETHERSWITCH_PORT_LED_DEFAULT; 752c94dc808SAdrian Chadd 753c94dc808SAdrian Chadd p->es_led[led] = style; 754c94dc808SAdrian Chadd } 755c94dc808SAdrian Chadd } else 756c94dc808SAdrian Chadd { 757c94dc808SAdrian Chadd p->es_nleds = 0; 758c94dc808SAdrian Chadd } 759c94dc808SAdrian Chadd 760a043e8c7SAdrian Chadd return (0); 761a043e8c7SAdrian Chadd } 762a043e8c7SAdrian Chadd 763a043e8c7SAdrian Chadd static int 764a9ad4222SAdrian Chadd ar8xxx_port_vlan_setup(struct arswitch_softc *sc, etherswitch_port_t *p) 765a043e8c7SAdrian Chadd { 766b9f07b86SLuiz Otavio O Souza uint32_t reg; 767a9ad4222SAdrian Chadd int err; 768a043e8c7SAdrian Chadd 769b9f07b86SLuiz Otavio O Souza ARSWITCH_LOCK(sc); 770a9ad4222SAdrian Chadd 771b9f07b86SLuiz Otavio O Souza /* Set the PVID. */ 772b9f07b86SLuiz Otavio O Souza if (p->es_pvid != 0) 7736dcbabd7SAdrian Chadd sc->hal.arswitch_vlan_set_pvid(sc, p->es_port, p->es_pvid); 774b9f07b86SLuiz Otavio O Souza 775b9f07b86SLuiz Otavio O Souza /* Mutually exclusive. */ 776b9f07b86SLuiz Otavio O Souza if (p->es_flags & ETHERSWITCH_PORT_ADDTAG && 777b9f07b86SLuiz Otavio O Souza p->es_flags & ETHERSWITCH_PORT_STRIPTAG) { 778b9f07b86SLuiz Otavio O Souza ARSWITCH_UNLOCK(sc); 779b9f07b86SLuiz Otavio O Souza return (EINVAL); 780b9f07b86SLuiz Otavio O Souza } 781b9f07b86SLuiz Otavio O Souza 782b9f07b86SLuiz Otavio O Souza reg = 0; 783b9f07b86SLuiz Otavio O Souza if (p->es_flags & ETHERSWITCH_PORT_DOUBLE_TAG) 784b9f07b86SLuiz Otavio O Souza reg |= AR8X16_PORT_CTRL_DOUBLE_TAG; 785b9f07b86SLuiz Otavio O Souza if (p->es_flags & ETHERSWITCH_PORT_ADDTAG) 786b9f07b86SLuiz Otavio O Souza reg |= AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_ADD << 787b9f07b86SLuiz Otavio O Souza AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_SHIFT; 788b9f07b86SLuiz Otavio O Souza if (p->es_flags & ETHERSWITCH_PORT_STRIPTAG) 789b9f07b86SLuiz Otavio O Souza reg |= AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_STRIP << 790b9f07b86SLuiz Otavio O Souza AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_SHIFT; 791b9f07b86SLuiz Otavio O Souza 792b9f07b86SLuiz Otavio O Souza err = arswitch_modifyreg(sc->sc_dev, 793b9f07b86SLuiz Otavio O Souza AR8X16_REG_PORT_CTRL(p->es_port), 794b9f07b86SLuiz Otavio O Souza 0x3 << AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_SHIFT | 795b9f07b86SLuiz Otavio O Souza AR8X16_PORT_CTRL_DOUBLE_TAG, reg); 796b9f07b86SLuiz Otavio O Souza 797b9f07b86SLuiz Otavio O Souza ARSWITCH_UNLOCK(sc); 798a9ad4222SAdrian Chadd return (err); 799a9ad4222SAdrian Chadd } 800a9ad4222SAdrian Chadd 801a9ad4222SAdrian Chadd static int 802a9ad4222SAdrian Chadd arswitch_setport(device_t dev, etherswitch_port_t *p) 803a9ad4222SAdrian Chadd { 804c94dc808SAdrian Chadd int err, i; 805a9ad4222SAdrian Chadd struct arswitch_softc *sc; 806a9ad4222SAdrian Chadd struct ifmedia *ifm; 807a9ad4222SAdrian Chadd struct mii_data *mii; 808a9ad4222SAdrian Chadd struct ifnet *ifp; 809a9ad4222SAdrian Chadd 810a9ad4222SAdrian Chadd sc = device_get_softc(dev); 811749cac13SAdrian Chadd if (p->es_port < 0 || p->es_port > sc->info.es_nports) 812a9ad4222SAdrian Chadd return (ENXIO); 813a9ad4222SAdrian Chadd 814a9ad4222SAdrian Chadd /* Port flags. */ 815a9ad4222SAdrian Chadd if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) { 816a9ad4222SAdrian Chadd err = sc->hal.arswitch_port_vlan_setup(sc, p); 817b9f07b86SLuiz Otavio O Souza if (err) 818b9f07b86SLuiz Otavio O Souza return (err); 819b9f07b86SLuiz Otavio O Souza } 820b9f07b86SLuiz Otavio O Souza 821c94dc808SAdrian Chadd /* Do not allow media or led changes on CPU port. */ 822749cac13SAdrian Chadd if (arswitch_is_cpuport(sc, p->es_port)) 823b9f07b86SLuiz Otavio O Souza return (0); 824a043e8c7SAdrian Chadd 825c94dc808SAdrian Chadd if (AR8X16_IS_SWITCH(sc, AR8327)) 826c94dc808SAdrian Chadd { 827c94dc808SAdrian Chadd for (i = 0; i < 3; i++) 828c94dc808SAdrian Chadd { 829c94dc808SAdrian Chadd int err; 830c94dc808SAdrian Chadd err = arswitch_setled(sc, p->es_port-1, i, p->es_led[i]); 831c94dc808SAdrian Chadd if (err) 832c94dc808SAdrian Chadd return (err); 833c94dc808SAdrian Chadd } 834c94dc808SAdrian Chadd } 835c94dc808SAdrian Chadd 836a043e8c7SAdrian Chadd mii = arswitch_miiforport(sc, p->es_port); 837a043e8c7SAdrian Chadd if (mii == NULL) 838a043e8c7SAdrian Chadd return (ENXIO); 839a043e8c7SAdrian Chadd 840a043e8c7SAdrian Chadd ifp = arswitch_ifpforport(sc, p->es_port); 841a043e8c7SAdrian Chadd 842a043e8c7SAdrian Chadd ifm = &mii->mii_media; 843b9f07b86SLuiz Otavio O Souza return (ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA)); 844a043e8c7SAdrian Chadd } 845a043e8c7SAdrian Chadd 846c94dc808SAdrian Chadd static int 847c94dc808SAdrian Chadd arswitch_setled(struct arswitch_softc *sc, int phy, int led, int style) 848c94dc808SAdrian Chadd { 849c94dc808SAdrian Chadd int shift; 8506d011946SKristof Provost int err; 851c94dc808SAdrian Chadd 852c94dc808SAdrian Chadd if (phy < 0 || phy > sc->numphys) 853c94dc808SAdrian Chadd return EINVAL; 854c94dc808SAdrian Chadd 855c94dc808SAdrian Chadd if (style < 0 || style > ETHERSWITCH_PORT_LED_MAX) 856c94dc808SAdrian Chadd return (EINVAL); 857c94dc808SAdrian Chadd 8586d011946SKristof Provost ARSWITCH_LOCK(sc); 8596d011946SKristof Provost 860c94dc808SAdrian Chadd shift = ar8327_led_mapping[phy][led].shift; 8616d011946SKristof Provost err = (arswitch_modifyreg(sc->sc_dev, 862c94dc808SAdrian Chadd ar8327_led_mapping[phy][led].reg, 863c94dc808SAdrian Chadd 0x03 << shift, led_pattern_table[style] << shift)); 8646d011946SKristof Provost ARSWITCH_UNLOCK(sc); 8656d011946SKristof Provost 8666d011946SKristof Provost return (err); 867c94dc808SAdrian Chadd } 868c94dc808SAdrian Chadd 869a043e8c7SAdrian Chadd static void 870a043e8c7SAdrian Chadd arswitch_statchg(device_t dev) 871a043e8c7SAdrian Chadd { 8721b334c8bSAdrian Chadd struct arswitch_softc *sc = device_get_softc(dev); 873a043e8c7SAdrian Chadd 8741b334c8bSAdrian Chadd DPRINTF(sc, ARSWITCH_DBG_POLL, "%s\n", __func__); 875a043e8c7SAdrian Chadd } 876a043e8c7SAdrian Chadd 877a043e8c7SAdrian Chadd static int 878a043e8c7SAdrian Chadd arswitch_ifmedia_upd(struct ifnet *ifp) 879a043e8c7SAdrian Chadd { 880a043e8c7SAdrian Chadd struct arswitch_softc *sc = ifp->if_softc; 881a043e8c7SAdrian Chadd struct mii_data *mii = arswitch_miiforport(sc, ifp->if_dunit); 882a043e8c7SAdrian Chadd 883a043e8c7SAdrian Chadd if (mii == NULL) 884a043e8c7SAdrian Chadd return (ENXIO); 885a043e8c7SAdrian Chadd mii_mediachg(mii); 886a043e8c7SAdrian Chadd return (0); 887a043e8c7SAdrian Chadd } 888a043e8c7SAdrian Chadd 889a043e8c7SAdrian Chadd static void 890a043e8c7SAdrian Chadd arswitch_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 891a043e8c7SAdrian Chadd { 892a043e8c7SAdrian Chadd struct arswitch_softc *sc = ifp->if_softc; 893a043e8c7SAdrian Chadd struct mii_data *mii = arswitch_miiforport(sc, ifp->if_dunit); 894a043e8c7SAdrian Chadd 8951b334c8bSAdrian Chadd DPRINTF(sc, ARSWITCH_DBG_POLL, "%s\n", __func__); 896a043e8c7SAdrian Chadd 897a043e8c7SAdrian Chadd if (mii == NULL) 898a043e8c7SAdrian Chadd return; 899a043e8c7SAdrian Chadd mii_pollstat(mii); 900a043e8c7SAdrian Chadd ifmr->ifm_active = mii->mii_media_active; 901a043e8c7SAdrian Chadd ifmr->ifm_status = mii->mii_media_status; 902a043e8c7SAdrian Chadd } 903a043e8c7SAdrian Chadd 904b9f07b86SLuiz Otavio O Souza static int 905b9f07b86SLuiz Otavio O Souza arswitch_getconf(device_t dev, etherswitch_conf_t *conf) 906b9f07b86SLuiz Otavio O Souza { 907b9f07b86SLuiz Otavio O Souza struct arswitch_softc *sc; 908b9f07b86SLuiz Otavio O Souza 909b9f07b86SLuiz Otavio O Souza sc = device_get_softc(dev); 910b9f07b86SLuiz Otavio O Souza 911b9f07b86SLuiz Otavio O Souza /* Return the VLAN mode. */ 912b9f07b86SLuiz Otavio O Souza conf->cmd = ETHERSWITCH_CONF_VLAN_MODE; 913b9f07b86SLuiz Otavio O Souza conf->vlan_mode = sc->vlan_mode; 914b9f07b86SLuiz Otavio O Souza 915b9f07b86SLuiz Otavio O Souza return (0); 916b9f07b86SLuiz Otavio O Souza } 917b9f07b86SLuiz Otavio O Souza 918b9f07b86SLuiz Otavio O Souza static int 919b9f07b86SLuiz Otavio O Souza arswitch_setconf(device_t dev, etherswitch_conf_t *conf) 920b9f07b86SLuiz Otavio O Souza { 921b9f07b86SLuiz Otavio O Souza struct arswitch_softc *sc; 922b9f07b86SLuiz Otavio O Souza int err; 923b9f07b86SLuiz Otavio O Souza 924b9f07b86SLuiz Otavio O Souza sc = device_get_softc(dev); 925b9f07b86SLuiz Otavio O Souza 926b9f07b86SLuiz Otavio O Souza /* Set the VLAN mode. */ 927b9f07b86SLuiz Otavio O Souza if (conf->cmd & ETHERSWITCH_CONF_VLAN_MODE) { 928b9f07b86SLuiz Otavio O Souza err = arswitch_set_vlan_mode(sc, conf->vlan_mode); 929b9f07b86SLuiz Otavio O Souza if (err != 0) 930b9f07b86SLuiz Otavio O Souza return (err); 931b9f07b86SLuiz Otavio O Souza } 932b9f07b86SLuiz Otavio O Souza 933b9f07b86SLuiz Otavio O Souza return (0); 934b9f07b86SLuiz Otavio O Souza } 935b9f07b86SLuiz Otavio O Souza 9366dcbabd7SAdrian Chadd static int 9376dcbabd7SAdrian Chadd arswitch_getvgroup(device_t dev, etherswitch_vlangroup_t *e) 9386dcbabd7SAdrian Chadd { 9396dcbabd7SAdrian Chadd struct arswitch_softc *sc = device_get_softc(dev); 9406dcbabd7SAdrian Chadd 9416dcbabd7SAdrian Chadd return (sc->hal.arswitch_vlan_getvgroup(sc, e)); 9426dcbabd7SAdrian Chadd } 9436dcbabd7SAdrian Chadd 9446dcbabd7SAdrian Chadd static int 9456dcbabd7SAdrian Chadd arswitch_setvgroup(device_t dev, etherswitch_vlangroup_t *e) 9466dcbabd7SAdrian Chadd { 9476dcbabd7SAdrian Chadd struct arswitch_softc *sc = device_get_softc(dev); 9486dcbabd7SAdrian Chadd 9496dcbabd7SAdrian Chadd return (sc->hal.arswitch_vlan_setvgroup(sc, e)); 9506dcbabd7SAdrian Chadd } 9516dcbabd7SAdrian Chadd 95278549b94SAdrian Chadd static int 95378549b94SAdrian Chadd arswitch_readphy(device_t dev, int phy, int reg) 95478549b94SAdrian Chadd { 95578549b94SAdrian Chadd struct arswitch_softc *sc = device_get_softc(dev); 95678549b94SAdrian Chadd 95778549b94SAdrian Chadd return (sc->hal.arswitch_phy_read(dev, phy, reg)); 95878549b94SAdrian Chadd } 95978549b94SAdrian Chadd 96078549b94SAdrian Chadd static int 96178549b94SAdrian Chadd arswitch_writephy(device_t dev, int phy, int reg, int val) 96278549b94SAdrian Chadd { 96378549b94SAdrian Chadd struct arswitch_softc *sc = device_get_softc(dev); 96478549b94SAdrian Chadd 96578549b94SAdrian Chadd return (sc->hal.arswitch_phy_write(dev, phy, reg, val)); 96678549b94SAdrian Chadd } 96778549b94SAdrian Chadd 968a043e8c7SAdrian Chadd static device_method_t arswitch_methods[] = { 969a043e8c7SAdrian Chadd /* Device interface */ 970a043e8c7SAdrian Chadd DEVMETHOD(device_probe, arswitch_probe), 971a043e8c7SAdrian Chadd DEVMETHOD(device_attach, arswitch_attach), 972a043e8c7SAdrian Chadd DEVMETHOD(device_detach, arswitch_detach), 973a043e8c7SAdrian Chadd 974a043e8c7SAdrian Chadd /* bus interface */ 975a043e8c7SAdrian Chadd DEVMETHOD(bus_add_child, device_add_child_ordered), 976a043e8c7SAdrian Chadd 977a043e8c7SAdrian Chadd /* MII interface */ 978a043e8c7SAdrian Chadd DEVMETHOD(miibus_readreg, arswitch_readphy), 979a043e8c7SAdrian Chadd DEVMETHOD(miibus_writereg, arswitch_writephy), 980a043e8c7SAdrian Chadd DEVMETHOD(miibus_statchg, arswitch_statchg), 981a043e8c7SAdrian Chadd 982a043e8c7SAdrian Chadd /* MDIO interface */ 983a043e8c7SAdrian Chadd DEVMETHOD(mdio_readreg, arswitch_readphy), 984a043e8c7SAdrian Chadd DEVMETHOD(mdio_writereg, arswitch_writephy), 985a043e8c7SAdrian Chadd 986a043e8c7SAdrian Chadd /* etherswitch interface */ 987454d507aSAleksandr Rybalko DEVMETHOD(etherswitch_lock, arswitch_lock), 988454d507aSAleksandr Rybalko DEVMETHOD(etherswitch_unlock, arswitch_unlock), 989a043e8c7SAdrian Chadd DEVMETHOD(etherswitch_getinfo, arswitch_getinfo), 990a043e8c7SAdrian Chadd DEVMETHOD(etherswitch_readreg, arswitch_readreg), 991a043e8c7SAdrian Chadd DEVMETHOD(etherswitch_writereg, arswitch_writereg), 992a043e8c7SAdrian Chadd DEVMETHOD(etherswitch_readphyreg, arswitch_readphy), 993a043e8c7SAdrian Chadd DEVMETHOD(etherswitch_writephyreg, arswitch_writephy), 994a043e8c7SAdrian Chadd DEVMETHOD(etherswitch_getport, arswitch_getport), 995a043e8c7SAdrian Chadd DEVMETHOD(etherswitch_setport, arswitch_setport), 996a043e8c7SAdrian Chadd DEVMETHOD(etherswitch_getvgroup, arswitch_getvgroup), 997a043e8c7SAdrian Chadd DEVMETHOD(etherswitch_setvgroup, arswitch_setvgroup), 998b9f07b86SLuiz Otavio O Souza DEVMETHOD(etherswitch_getconf, arswitch_getconf), 999b9f07b86SLuiz Otavio O Souza DEVMETHOD(etherswitch_setconf, arswitch_setconf), 1000a043e8c7SAdrian Chadd 1001a043e8c7SAdrian Chadd DEVMETHOD_END 1002a043e8c7SAdrian Chadd }; 1003a043e8c7SAdrian Chadd 1004a043e8c7SAdrian Chadd DEFINE_CLASS_0(arswitch, arswitch_driver, arswitch_methods, 1005a043e8c7SAdrian Chadd sizeof(struct arswitch_softc)); 1006a043e8c7SAdrian Chadd static devclass_t arswitch_devclass; 1007a043e8c7SAdrian Chadd 1008a043e8c7SAdrian Chadd DRIVER_MODULE(arswitch, mdio, arswitch_driver, arswitch_devclass, 0, 0); 1009a043e8c7SAdrian Chadd DRIVER_MODULE(miibus, arswitch, miibus_driver, miibus_devclass, 0, 0); 1010a043e8c7SAdrian Chadd DRIVER_MODULE(mdio, arswitch, mdio_driver, mdio_devclass, 0, 0); 1011a043e8c7SAdrian Chadd DRIVER_MODULE(etherswitch, arswitch, etherswitch_driver, etherswitch_devclass, 0, 0); 1012a043e8c7SAdrian Chadd MODULE_VERSION(arswitch, 1); 1013a043e8c7SAdrian Chadd MODULE_DEPEND(arswitch, miibus, 1, 1, 1); /* XXX which versions? */ 1014a043e8c7SAdrian Chadd MODULE_DEPEND(arswitch, etherswitch, 1, 1, 1); /* XXX which versions? */ 1015