arswitch.c revision 250383
1235288Sadrian/*- 2235288Sadrian * Copyright (c) 2011-2012 Stefan Bethke. 3235288Sadrian * Copyright (c) 2012 Adrian Chadd. 4235288Sadrian * All rights reserved. 5235288Sadrian * 6235288Sadrian * Redistribution and use in source and binary forms, with or without 7235288Sadrian * modification, are permitted provided that the following conditions 8235288Sadrian * are met: 9235288Sadrian * 1. Redistributions of source code must retain the above copyright 10235288Sadrian * notice, this list of conditions and the following disclaimer. 11235288Sadrian * 2. Redistributions in binary form must reproduce the above copyright 12235288Sadrian * notice, this list of conditions and the following disclaimer in the 13235288Sadrian * documentation and/or other materials provided with the distribution. 14235288Sadrian * 15235288Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16235288Sadrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17235288Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18235288Sadrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19235288Sadrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20235288Sadrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21235288Sadrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22235288Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23235288Sadrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24235288Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25235288Sadrian * SUCH DAMAGE. 26235288Sadrian * 27235288Sadrian * $FreeBSD: head/sys/dev/etherswitch/arswitch/arswitch.c 250383 2013-05-08 20:54:59Z adrian $ 28235288Sadrian */ 29235288Sadrian 30235288Sadrian#include <sys/param.h> 31235288Sadrian#include <sys/bus.h> 32235288Sadrian#include <sys/errno.h> 33235288Sadrian#include <sys/kernel.h> 34235288Sadrian#include <sys/module.h> 35235288Sadrian#include <sys/socket.h> 36235288Sadrian#include <sys/sockio.h> 37235288Sadrian#include <sys/sysctl.h> 38235288Sadrian#include <sys/systm.h> 39235288Sadrian 40235288Sadrian#include <net/if.h> 41235288Sadrian#include <net/if_arp.h> 42235288Sadrian#include <net/ethernet.h> 43235288Sadrian#include <net/if_dl.h> 44235288Sadrian#include <net/if_media.h> 45235288Sadrian#include <net/if_types.h> 46235288Sadrian 47235288Sadrian#include <machine/bus.h> 48235288Sadrian#include <dev/iicbus/iic.h> 49235288Sadrian#include <dev/iicbus/iiconf.h> 50235288Sadrian#include <dev/iicbus/iicbus.h> 51235288Sadrian#include <dev/mii/mii.h> 52235288Sadrian#include <dev/mii/miivar.h> 53235288Sadrian#include <dev/etherswitch/mdio.h> 54235288Sadrian 55235288Sadrian#include <dev/etherswitch/etherswitch.h> 56235288Sadrian 57235288Sadrian#include <dev/etherswitch/arswitch/arswitchreg.h> 58235288Sadrian#include <dev/etherswitch/arswitch/arswitchvar.h> 59235288Sadrian#include <dev/etherswitch/arswitch/arswitch_reg.h> 60235288Sadrian#include <dev/etherswitch/arswitch/arswitch_phy.h> 61235288Sadrian 62235323Sadrian#include <dev/etherswitch/arswitch/arswitch_7240.h> 63235288Sadrian#include <dev/etherswitch/arswitch/arswitch_8216.h> 64235288Sadrian#include <dev/etherswitch/arswitch/arswitch_8226.h> 65235288Sadrian#include <dev/etherswitch/arswitch/arswitch_8316.h> 66235288Sadrian 67235288Sadrian#include "mdio_if.h" 68235288Sadrian#include "miibus_if.h" 69235288Sadrian#include "etherswitch_if.h" 70235288Sadrian 71235288Sadrian#if defined(DEBUG) 72235288Sadrianstatic SYSCTL_NODE(_debug, OID_AUTO, arswitch, CTLFLAG_RD, 0, "arswitch"); 73235288Sadrian#endif 74235288Sadrian 75235288Sadrianstatic inline int arswitch_portforphy(int phy); 76235288Sadrianstatic void arswitch_tick(void *arg); 77235288Sadrianstatic int arswitch_ifmedia_upd(struct ifnet *); 78235288Sadrianstatic void arswitch_ifmedia_sts(struct ifnet *, struct ifmediareq *); 79235288Sadrian 80235288Sadrianstatic int 81235288Sadrianarswitch_probe(device_t dev) 82235288Sadrian{ 83235288Sadrian struct arswitch_softc *sc; 84235288Sadrian uint32_t id; 85235288Sadrian char *chipname, desc[256]; 86235288Sadrian 87235288Sadrian sc = device_get_softc(dev); 88235288Sadrian bzero(sc, sizeof(*sc)); 89235288Sadrian sc->page = -1; 90235323Sadrian 91235323Sadrian /* AR7240 probe */ 92235323Sadrian if (ar7240_probe(dev) == 0) { 93235323Sadrian chipname = "AR7240"; 94235323Sadrian sc->sc_switchtype = AR8X16_SWITCH_AR7240; 95241577Sray id = 0; 96235323Sadrian goto done; 97235323Sadrian } 98235323Sadrian 99235323Sadrian /* AR8xxx probe */ 100235288Sadrian id = arswitch_readreg(dev, AR8X16_REG_MASK_CTRL); 101235288Sadrian switch ((id & AR8X16_MASK_CTRL_VER_MASK) >> 102235288Sadrian AR8X16_MASK_CTRL_VER_SHIFT) { 103235288Sadrian case 1: 104235288Sadrian chipname = "AR8216"; 105235288Sadrian sc->sc_switchtype = AR8X16_SWITCH_AR8216; 106235288Sadrian break; 107235288Sadrian case 2: 108235288Sadrian chipname = "AR8226"; 109235288Sadrian sc->sc_switchtype = AR8X16_SWITCH_AR8226; 110235288Sadrian break; 111235288Sadrian case 16: 112235288Sadrian chipname = "AR8316"; 113235288Sadrian sc->sc_switchtype = AR8X16_SWITCH_AR8316; 114235288Sadrian break; 115235288Sadrian default: 116235288Sadrian chipname = NULL; 117235288Sadrian } 118235323Sadrian 119235323Sadriandone: 120235288Sadrian DPRINTF(dev, "chipname=%s, rev=%02x\n", chipname, 121235288Sadrian id & AR8X16_MASK_CTRL_REV_MASK); 122235288Sadrian if (chipname != NULL) { 123235288Sadrian snprintf(desc, sizeof(desc), 124235288Sadrian "Atheros %s Ethernet Switch", 125235288Sadrian chipname); 126235288Sadrian device_set_desc_copy(dev, desc); 127235288Sadrian return (BUS_PROBE_DEFAULT); 128235288Sadrian } 129235288Sadrian return (ENXIO); 130235288Sadrian} 131235288Sadrian 132235288Sadrianstatic int 133235288Sadrianarswitch_attach_phys(struct arswitch_softc *sc) 134235288Sadrian{ 135235288Sadrian int phy, err = 0; 136235288Sadrian char name[IFNAMSIZ]; 137235288Sadrian 138235288Sadrian /* PHYs need an interface, so we generate a dummy one */ 139235288Sadrian snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->sc_dev)); 140235288Sadrian for (phy = 0; phy < sc->numphys; phy++) { 141235288Sadrian sc->ifp[phy] = if_alloc(IFT_ETHER); 142235288Sadrian sc->ifp[phy]->if_softc = sc; 143235288Sadrian sc->ifp[phy]->if_flags |= IFF_UP | IFF_BROADCAST | 144235288Sadrian IFF_DRV_RUNNING | IFF_SIMPLEX; 145235288Sadrian sc->ifname[phy] = malloc(strlen(name)+1, M_DEVBUF, M_WAITOK); 146235288Sadrian bcopy(name, sc->ifname[phy], strlen(name)+1); 147235288Sadrian if_initname(sc->ifp[phy], sc->ifname[phy], 148235288Sadrian arswitch_portforphy(phy)); 149235288Sadrian err = mii_attach(sc->sc_dev, &sc->miibus[phy], sc->ifp[phy], 150235288Sadrian arswitch_ifmedia_upd, arswitch_ifmedia_sts, \ 151235288Sadrian BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0); 152235288Sadrian DPRINTF(sc->sc_dev, "%s attached to pseudo interface %s\n", 153235288Sadrian device_get_nameunit(sc->miibus[phy]), 154235288Sadrian sc->ifp[phy]->if_xname); 155235288Sadrian if (err != 0) { 156235288Sadrian device_printf(sc->sc_dev, 157235288Sadrian "attaching PHY %d failed\n", 158235288Sadrian phy); 159235288Sadrian } 160235288Sadrian } 161235288Sadrian return (err); 162235288Sadrian} 163235288Sadrian 164235288Sadrianstatic int 165235288Sadrianarswitch_attach(device_t dev) 166235288Sadrian{ 167235288Sadrian struct arswitch_softc *sc; 168235288Sadrian int err = 0; 169235288Sadrian 170235288Sadrian sc = device_get_softc(dev); 171235288Sadrian 172235288Sadrian /* sc->sc_switchtype is already decided in arswitch_probe() */ 173235288Sadrian sc->sc_dev = dev; 174235288Sadrian mtx_init(&sc->sc_mtx, "arswitch", NULL, MTX_DEF); 175235288Sadrian sc->page = -1; 176235288Sadrian strlcpy(sc->info.es_name, device_get_desc(dev), 177235288Sadrian sizeof(sc->info.es_name)); 178235288Sadrian 179235288Sadrian /* 180235288Sadrian * Attach switch related functions 181235288Sadrian */ 182235323Sadrian if (AR8X16_IS_SWITCH(sc, AR7240)) 183235323Sadrian ar7240_attach(sc); 184235323Sadrian else if (AR8X16_IS_SWITCH(sc, AR8216)) 185235288Sadrian ar8216_attach(sc); 186235288Sadrian else if (AR8X16_IS_SWITCH(sc, AR8226)) 187235288Sadrian ar8226_attach(sc); 188235288Sadrian else if (AR8X16_IS_SWITCH(sc, AR8316)) 189235288Sadrian ar8316_attach(sc); 190235288Sadrian else 191235288Sadrian return (ENXIO); 192235288Sadrian 193235288Sadrian /* 194235288Sadrian * XXX these two should be part of the switch attach function 195235288Sadrian */ 196235288Sadrian sc->info.es_nports = 5; /* XXX technically 6, but 6th not used */ 197235288Sadrian sc->info.es_nvlangroups = 16; 198235288Sadrian 199235288Sadrian /* XXX Defaults for externally connected AR8316 */ 200235288Sadrian sc->numphys = 4; 201235288Sadrian sc->phy4cpu = 1; 202235288Sadrian sc->is_rgmii = 1; 203235288Sadrian sc->is_gmii = 0; 204235288Sadrian 205235288Sadrian (void) resource_int_value(device_get_name(dev), device_get_unit(dev), 206235288Sadrian "numphys", &sc->numphys); 207235288Sadrian (void) resource_int_value(device_get_name(dev), device_get_unit(dev), 208235288Sadrian "phy4cpu", &sc->phy4cpu); 209235288Sadrian (void) resource_int_value(device_get_name(dev), device_get_unit(dev), 210235288Sadrian "is_rgmii", &sc->is_rgmii); 211235288Sadrian (void) resource_int_value(device_get_name(dev), device_get_unit(dev), 212235288Sadrian "is_gmii", &sc->is_gmii); 213235288Sadrian 214235377Sadrian /* 215235377Sadrian * This requires much more setup depending upon each chip, including: 216235377Sadrian * 217235377Sadrian * + Proper reinitialisation of the PHYs; 218235377Sadrian * + Initialising the VLAN table; 219235377Sadrian * + Initialising the port access table and CPU flood/broadcast 220235377Sadrian * configuration; 221235377Sadrian * + Other things I haven't yet thought of. 222235377Sadrian */ 223235288Sadrian#ifdef NOTYET 224235288Sadrian arswitch_writereg(dev, AR8X16_REG_MASK_CTRL, 225235288Sadrian AR8X16_MASK_CTRL_SOFT_RESET); 226235288Sadrian DELAY(1000); 227235288Sadrian if (arswitch_readreg(dev, AR8X16_REG_MASK_CTRL) & 228235288Sadrian AR8X16_MASK_CTRL_SOFT_RESET) { 229235288Sadrian device_printf(dev, "unable to reset switch\n"); 230235288Sadrian return (ENXIO); 231235288Sadrian } 232235288Sadrian#endif 233235288Sadrian 234235288Sadrian err = sc->hal.arswitch_hw_setup(sc); 235235288Sadrian if (err != 0) 236235288Sadrian return (err); 237235288Sadrian 238235288Sadrian err = sc->hal.arswitch_hw_global_setup(sc); 239235288Sadrian if (err != 0) 240235288Sadrian return (err); 241235288Sadrian 242235288Sadrian /* 243235288Sadrian * Attach the PHYs and complete the bus enumeration. 244235288Sadrian */ 245235288Sadrian err = arswitch_attach_phys(sc); 246235288Sadrian if (err != 0) 247235288Sadrian return (err); 248235288Sadrian 249235288Sadrian bus_generic_probe(dev); 250235288Sadrian bus_enumerate_hinted_children(dev); 251235288Sadrian err = bus_generic_attach(dev); 252235288Sadrian if (err != 0) 253235288Sadrian return (err); 254235288Sadrian 255235288Sadrian callout_init_mtx(&sc->callout_tick, &sc->sc_mtx, 0); 256241578Sray 257241578Sray ARSWITCH_LOCK(sc); 258235288Sadrian arswitch_tick(sc); 259241578Sray ARSWITCH_UNLOCK(sc); 260235288Sadrian 261235288Sadrian return (err); 262235288Sadrian} 263235288Sadrian 264235288Sadrianstatic int 265235288Sadrianarswitch_detach(device_t dev) 266235288Sadrian{ 267235288Sadrian struct arswitch_softc *sc = device_get_softc(dev); 268235288Sadrian int i; 269235288Sadrian 270235288Sadrian callout_drain(&sc->callout_tick); 271235288Sadrian 272235288Sadrian for (i=0; i < sc->numphys; i++) { 273235288Sadrian if (sc->miibus[i] != NULL) 274235288Sadrian device_delete_child(dev, sc->miibus[i]); 275235288Sadrian if (sc->ifp[i] != NULL) 276235288Sadrian if_free(sc->ifp[i]); 277235288Sadrian free(sc->ifname[i], M_DEVBUF); 278235288Sadrian } 279235288Sadrian 280235288Sadrian bus_generic_detach(dev); 281235288Sadrian mtx_destroy(&sc->sc_mtx); 282235288Sadrian 283235288Sadrian return (0); 284235288Sadrian} 285235288Sadrian 286235288Sadrian/* 287235288Sadrian * Convert PHY number to port number. PHY0 is connected to port 1, PHY1 to 288235288Sadrian * port 2, etc. 289235288Sadrian */ 290235288Sadrianstatic inline int 291235288Sadrianarswitch_portforphy(int phy) 292235288Sadrian{ 293235288Sadrian return (phy+1); 294235288Sadrian} 295235288Sadrian 296235288Sadrianstatic inline struct mii_data * 297235288Sadrianarswitch_miiforport(struct arswitch_softc *sc, int port) 298235288Sadrian{ 299235288Sadrian int phy = port-1; 300235288Sadrian 301235288Sadrian if (phy < 0 || phy >= sc->numphys) 302235288Sadrian return (NULL); 303235288Sadrian return (device_get_softc(sc->miibus[phy])); 304235288Sadrian} 305235288Sadrian 306235288Sadrianstatic inline struct ifnet * 307235288Sadrianarswitch_ifpforport(struct arswitch_softc *sc, int port) 308235288Sadrian{ 309235288Sadrian int phy = port-1; 310235288Sadrian 311235288Sadrian if (phy < 0 || phy >= sc->numphys) 312235288Sadrian return (NULL); 313235288Sadrian return (sc->ifp[phy]); 314235288Sadrian} 315235288Sadrian 316235288Sadrian/* 317235288Sadrian * Convert port status to ifmedia. 318235288Sadrian */ 319235288Sadrianstatic void 320235288Sadrianarswitch_update_ifmedia(int portstatus, u_int *media_status, u_int *media_active) 321235288Sadrian{ 322235288Sadrian *media_active = IFM_ETHER; 323235288Sadrian *media_status = IFM_AVALID; 324235288Sadrian 325235288Sadrian if ((portstatus & AR8X16_PORT_STS_LINK_UP) != 0) 326235288Sadrian *media_status |= IFM_ACTIVE; 327235288Sadrian else { 328235288Sadrian *media_active |= IFM_NONE; 329235288Sadrian return; 330235288Sadrian } 331235288Sadrian switch (portstatus & AR8X16_PORT_STS_SPEED_MASK) { 332235288Sadrian case AR8X16_PORT_STS_SPEED_10: 333235288Sadrian *media_active |= IFM_10_T; 334235288Sadrian break; 335235288Sadrian case AR8X16_PORT_STS_SPEED_100: 336235288Sadrian *media_active |= IFM_100_TX; 337235288Sadrian break; 338235288Sadrian case AR8X16_PORT_STS_SPEED_1000: 339235288Sadrian *media_active |= IFM_1000_T; 340235288Sadrian break; 341235288Sadrian } 342235288Sadrian if ((portstatus & AR8X16_PORT_STS_DUPLEX) == 0) 343235288Sadrian *media_active |= IFM_FDX; 344235288Sadrian else 345235288Sadrian *media_active |= IFM_HDX; 346235288Sadrian if ((portstatus & AR8X16_PORT_STS_TXFLOW) != 0) 347235288Sadrian *media_active |= IFM_ETH_TXPAUSE; 348235288Sadrian if ((portstatus & AR8X16_PORT_STS_RXFLOW) != 0) 349235288Sadrian *media_active |= IFM_ETH_RXPAUSE; 350235288Sadrian} 351235288Sadrian 352235288Sadrian/* 353235288Sadrian * Poll the status for all PHYs. We're using the switch port status because 354235288Sadrian * thats a lot quicker to read than talking to all the PHYs. Care must be 355235288Sadrian * taken that the resulting ifmedia_active is identical to what the PHY will 356235288Sadrian * compute, or gratuitous link status changes will occur whenever the PHYs 357235288Sadrian * update function is called. 358235288Sadrian */ 359235288Sadrianstatic void 360235288Sadrianarswitch_miipollstat(struct arswitch_softc *sc) 361235288Sadrian{ 362235288Sadrian int i; 363235288Sadrian struct mii_data *mii; 364235288Sadrian struct mii_softc *miisc; 365235288Sadrian int portstatus; 366235288Sadrian 367241578Sray ARSWITCH_LOCK_ASSERT(sc, MA_OWNED); 368241578Sray 369235288Sadrian for (i = 0; i < sc->numphys; i++) { 370235288Sadrian if (sc->miibus[i] == NULL) 371235288Sadrian continue; 372235288Sadrian mii = device_get_softc(sc->miibus[i]); 373235288Sadrian portstatus = arswitch_readreg(sc->sc_dev, 374235288Sadrian AR8X16_REG_PORT_STS(arswitch_portforphy(i))); 375235288Sadrian#if 0 376235288Sadrian DPRINTF(sc->sc_dev, "p[%d]=%b\n", 377235288Sadrian arge_portforphy(i), 378235288Sadrian portstatus, 379235288Sadrian "\20\3TXMAC\4RXMAC\5TXFLOW\6RXFLOW\7" 380235288Sadrian "DUPLEX\11LINK_UP\12LINK_AUTO\13LINK_PAUSE"); 381235288Sadrian#endif 382235288Sadrian arswitch_update_ifmedia(portstatus, &mii->mii_media_status, 383235288Sadrian &mii->mii_media_active); 384235288Sadrian LIST_FOREACH(miisc, &mii->mii_phys, mii_list) { 385235288Sadrian if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) != 386235288Sadrian miisc->mii_inst) 387235288Sadrian continue; 388235288Sadrian mii_phy_update(miisc, MII_POLLSTAT); 389235288Sadrian } 390235288Sadrian } 391235288Sadrian} 392235288Sadrian 393235288Sadrianstatic void 394235288Sadrianarswitch_tick(void *arg) 395235288Sadrian{ 396235288Sadrian struct arswitch_softc *sc = arg; 397235288Sadrian 398235288Sadrian arswitch_miipollstat(sc); 399235288Sadrian callout_reset(&sc->callout_tick, hz, arswitch_tick, sc); 400235288Sadrian} 401235288Sadrian 402241578Sraystatic void 403241578Srayarswitch_lock(device_t dev) 404241578Sray{ 405241578Sray struct arswitch_softc *sc = device_get_softc(dev); 406241578Sray 407241578Sray ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED); 408241578Sray ARSWITCH_LOCK(sc); 409241578Sray} 410241578Sray 411241578Sraystatic void 412241578Srayarswitch_unlock(device_t dev) 413241578Sray{ 414241578Sray struct arswitch_softc *sc = device_get_softc(dev); 415241578Sray 416241578Sray ARSWITCH_LOCK_ASSERT(sc, MA_OWNED); 417241578Sray ARSWITCH_UNLOCK(sc); 418241578Sray} 419241578Sray 420235288Sadrianstatic etherswitch_info_t * 421235288Sadrianarswitch_getinfo(device_t dev) 422235288Sadrian{ 423235288Sadrian struct arswitch_softc *sc = device_get_softc(dev); 424235288Sadrian 425235288Sadrian return (&sc->info); 426235288Sadrian} 427235288Sadrian 428235288Sadrianstatic int 429235288Sadrianarswitch_getport(device_t dev, etherswitch_port_t *p) 430235288Sadrian{ 431235288Sadrian struct arswitch_softc *sc = device_get_softc(dev); 432235288Sadrian struct mii_data *mii; 433235288Sadrian struct ifmediareq *ifmr = &p->es_ifmr; 434235288Sadrian int err; 435235288Sadrian 436235288Sadrian if (p->es_port < 0 || p->es_port >= AR8X16_NUM_PORTS) 437235288Sadrian return (ENXIO); 438249775Sadrian p->es_pvid = 0; 439235288Sadrian 440235288Sadrian mii = arswitch_miiforport(sc, p->es_port); 441235288Sadrian if (p->es_port == 0) { 442235288Sadrian /* fill in fixed values for CPU port */ 443250383Sadrian p->es_flags |= ETHERSWITCH_PORT_CPU; 444235288Sadrian ifmr->ifm_count = 0; 445235288Sadrian ifmr->ifm_current = ifmr->ifm_active = 446235288Sadrian IFM_ETHER | IFM_1000_T | IFM_FDX; 447235288Sadrian ifmr->ifm_mask = 0; 448235288Sadrian ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID; 449235288Sadrian } else if (mii != NULL) { 450235288Sadrian err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr, 451235288Sadrian &mii->mii_media, SIOCGIFMEDIA); 452235288Sadrian if (err) 453235288Sadrian return (err); 454235288Sadrian } else { 455235288Sadrian return (ENXIO); 456235288Sadrian } 457235288Sadrian return (0); 458235288Sadrian} 459235288Sadrian 460235288Sadrian/* 461235288Sadrian * XXX doesn't yet work? 462235288Sadrian */ 463235288Sadrianstatic int 464235288Sadrianarswitch_setport(device_t dev, etherswitch_port_t *p) 465235288Sadrian{ 466235288Sadrian int err; 467235288Sadrian struct arswitch_softc *sc; 468235288Sadrian struct ifmedia *ifm; 469235288Sadrian struct mii_data *mii; 470235288Sadrian struct ifnet *ifp; 471235288Sadrian 472235288Sadrian /* 473235288Sadrian * XXX check the sc numphys, or the #define ? 474235288Sadrian */ 475235288Sadrian if (p->es_port < 0 || p->es_port >= AR8X16_NUM_PHYS) 476235288Sadrian return (ENXIO); 477235288Sadrian 478235288Sadrian sc = device_get_softc(dev); 479235288Sadrian 480235288Sadrian /* 481235288Sadrian * XXX TODO: don't set the CPU port? 482235288Sadrian */ 483235288Sadrian 484235288Sadrian mii = arswitch_miiforport(sc, p->es_port); 485235288Sadrian if (mii == NULL) 486235288Sadrian return (ENXIO); 487235288Sadrian 488235288Sadrian ifp = arswitch_ifpforport(sc, p->es_port); 489235288Sadrian 490235288Sadrian ifm = &mii->mii_media; 491235288Sadrian err = ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA); 492235288Sadrian return (err); 493235288Sadrian} 494235288Sadrian 495235288Sadrianstatic int 496235288Sadrianarswitch_getvgroup(device_t dev, etherswitch_vlangroup_t *vg) 497235288Sadrian{ 498235288Sadrian 499235288Sadrian /* XXX not implemented yet */ 500235288Sadrian vg->es_vid = 0; 501235288Sadrian vg->es_member_ports = 0; 502235288Sadrian vg->es_untagged_ports = 0; 503235288Sadrian vg->es_fid = 0; 504235288Sadrian return (0); 505235288Sadrian} 506235288Sadrian 507235288Sadrianstatic int 508235288Sadrianarswitch_setvgroup(device_t dev, etherswitch_vlangroup_t *vg) 509235288Sadrian{ 510235288Sadrian 511235288Sadrian /* XXX not implemented yet */ 512235288Sadrian return (0); 513235288Sadrian} 514235288Sadrian 515235288Sadrianstatic void 516235288Sadrianarswitch_statchg(device_t dev) 517235288Sadrian{ 518235288Sadrian 519235288Sadrian DPRINTF(dev, "%s\n", __func__); 520235288Sadrian} 521235288Sadrian 522235288Sadrianstatic int 523235288Sadrianarswitch_ifmedia_upd(struct ifnet *ifp) 524235288Sadrian{ 525235288Sadrian struct arswitch_softc *sc = ifp->if_softc; 526235288Sadrian struct mii_data *mii = arswitch_miiforport(sc, ifp->if_dunit); 527235288Sadrian 528235288Sadrian if (mii == NULL) 529235288Sadrian return (ENXIO); 530235288Sadrian mii_mediachg(mii); 531235288Sadrian return (0); 532235288Sadrian} 533235288Sadrian 534235288Sadrianstatic void 535235288Sadrianarswitch_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 536235288Sadrian{ 537235288Sadrian struct arswitch_softc *sc = ifp->if_softc; 538235288Sadrian struct mii_data *mii = arswitch_miiforport(sc, ifp->if_dunit); 539235288Sadrian 540235288Sadrian DPRINTF(sc->sc_dev, "%s\n", __func__); 541235288Sadrian 542235288Sadrian if (mii == NULL) 543235288Sadrian return; 544235288Sadrian mii_pollstat(mii); 545235288Sadrian ifmr->ifm_active = mii->mii_media_active; 546235288Sadrian ifmr->ifm_status = mii->mii_media_status; 547235288Sadrian} 548235288Sadrian 549235288Sadrianstatic device_method_t arswitch_methods[] = { 550235288Sadrian /* Device interface */ 551235288Sadrian DEVMETHOD(device_probe, arswitch_probe), 552235288Sadrian DEVMETHOD(device_attach, arswitch_attach), 553235288Sadrian DEVMETHOD(device_detach, arswitch_detach), 554235288Sadrian 555235288Sadrian /* bus interface */ 556235288Sadrian DEVMETHOD(bus_add_child, device_add_child_ordered), 557235288Sadrian 558235288Sadrian /* MII interface */ 559235288Sadrian DEVMETHOD(miibus_readreg, arswitch_readphy), 560235288Sadrian DEVMETHOD(miibus_writereg, arswitch_writephy), 561235288Sadrian DEVMETHOD(miibus_statchg, arswitch_statchg), 562235288Sadrian 563235288Sadrian /* MDIO interface */ 564235288Sadrian DEVMETHOD(mdio_readreg, arswitch_readphy), 565235288Sadrian DEVMETHOD(mdio_writereg, arswitch_writephy), 566235288Sadrian 567235288Sadrian /* etherswitch interface */ 568241578Sray DEVMETHOD(etherswitch_lock, arswitch_lock), 569241578Sray DEVMETHOD(etherswitch_unlock, arswitch_unlock), 570235288Sadrian DEVMETHOD(etherswitch_getinfo, arswitch_getinfo), 571235288Sadrian DEVMETHOD(etherswitch_readreg, arswitch_readreg), 572235288Sadrian DEVMETHOD(etherswitch_writereg, arswitch_writereg), 573235288Sadrian DEVMETHOD(etherswitch_readphyreg, arswitch_readphy), 574235288Sadrian DEVMETHOD(etherswitch_writephyreg, arswitch_writephy), 575235288Sadrian DEVMETHOD(etherswitch_getport, arswitch_getport), 576235288Sadrian DEVMETHOD(etherswitch_setport, arswitch_setport), 577235288Sadrian DEVMETHOD(etherswitch_getvgroup, arswitch_getvgroup), 578235288Sadrian DEVMETHOD(etherswitch_setvgroup, arswitch_setvgroup), 579235288Sadrian 580235288Sadrian DEVMETHOD_END 581235288Sadrian}; 582235288Sadrian 583235288SadrianDEFINE_CLASS_0(arswitch, arswitch_driver, arswitch_methods, 584235288Sadrian sizeof(struct arswitch_softc)); 585235288Sadrianstatic devclass_t arswitch_devclass; 586235288Sadrian 587235288SadrianDRIVER_MODULE(arswitch, mdio, arswitch_driver, arswitch_devclass, 0, 0); 588235288SadrianDRIVER_MODULE(miibus, arswitch, miibus_driver, miibus_devclass, 0, 0); 589235288SadrianDRIVER_MODULE(mdio, arswitch, mdio_driver, mdio_devclass, 0, 0); 590235288SadrianDRIVER_MODULE(etherswitch, arswitch, etherswitch_driver, etherswitch_devclass, 0, 0); 591235288SadrianMODULE_VERSION(arswitch, 1); 592235288SadrianMODULE_DEPEND(arswitch, miibus, 1, 1, 1); /* XXX which versions? */ 593235288SadrianMODULE_DEPEND(arswitch, etherswitch, 1, 1, 1); /* XXX which versions? */ 594