1250386Sadrian/*- 2250386Sadrian * Copyright (c) 2013 Luiz Otavio O Souza. 3250386Sadrian * Copyright (c) 2011-2012 Stefan Bethke. 4250386Sadrian * Copyright (c) 2012 Adrian Chadd. 5250386Sadrian * All rights reserved. 6250386Sadrian * 7250386Sadrian * Redistribution and use in source and binary forms, with or without 8250386Sadrian * modification, are permitted provided that the following conditions 9250386Sadrian * are met: 10250386Sadrian * 1. Redistributions of source code must retain the above copyright 11250386Sadrian * notice, this list of conditions and the following disclaimer. 12250386Sadrian * 2. Redistributions in binary form must reproduce the above copyright 13250386Sadrian * notice, this list of conditions and the following disclaimer in the 14250386Sadrian * documentation and/or other materials provided with the distribution. 15250386Sadrian * 16250386Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17250386Sadrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18250386Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19250386Sadrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20250386Sadrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21250386Sadrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22250386Sadrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23250386Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24250386Sadrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25250386Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26250386Sadrian * SUCH DAMAGE. 27250386Sadrian * 28250386Sadrian * $FreeBSD$ 29250386Sadrian */ 30250386Sadrian 31250386Sadrian#include <sys/param.h> 32250386Sadrian#include <sys/bus.h> 33250386Sadrian#include <sys/errno.h> 34250386Sadrian#include <sys/kernel.h> 35262571Sbrueffer#include <sys/lock.h> 36262571Sbrueffer#include <sys/malloc.h> 37250386Sadrian#include <sys/module.h> 38262571Sbrueffer#include <sys/mutex.h> 39250386Sadrian#include <sys/socket.h> 40250386Sadrian#include <sys/sockio.h> 41250386Sadrian#include <sys/sysctl.h> 42250386Sadrian#include <sys/systm.h> 43262571Sbrueffer#include <sys/types.h> 44250386Sadrian 45250386Sadrian#include <net/if.h> 46250386Sadrian#include <net/ethernet.h> 47250386Sadrian#include <net/if_media.h> 48250386Sadrian#include <net/if_types.h> 49262571Sbrueffer#include <net/if_var.h> 50250386Sadrian 51250386Sadrian#include <machine/bus.h> 52250386Sadrian#include <dev/mii/mii.h> 53250386Sadrian#include <dev/mii/miivar.h> 54292738Sadrian#include <dev/mdio/mdio.h> 55250386Sadrian 56250386Sadrian#include <dev/etherswitch/etherswitch.h> 57250386Sadrian#include <dev/etherswitch/ip17x/ip17x_phy.h> 58250386Sadrian#include <dev/etherswitch/ip17x/ip17x_reg.h> 59250386Sadrian#include <dev/etherswitch/ip17x/ip17x_var.h> 60250386Sadrian#include <dev/etherswitch/ip17x/ip17x_vlans.h> 61250386Sadrian#include <dev/etherswitch/ip17x/ip175c.h> 62250386Sadrian#include <dev/etherswitch/ip17x/ip175d.h> 63250386Sadrian 64250386Sadrian#include "mdio_if.h" 65250386Sadrian#include "miibus_if.h" 66250386Sadrian#include "etherswitch_if.h" 67250386Sadrian 68250386SadrianMALLOC_DECLARE(M_IP17X); 69250386SadrianMALLOC_DEFINE(M_IP17X, "ip17x", "ip17x data structures"); 70250386Sadrian 71250386Sadrianstatic void ip17x_tick(void *); 72250386Sadrianstatic int ip17x_ifmedia_upd(struct ifnet *); 73250386Sadrianstatic void ip17x_ifmedia_sts(struct ifnet *, struct ifmediareq *); 74250386Sadrian 75250386Sadrianstatic int 76250386Sadrianip17x_probe(device_t dev) 77250386Sadrian{ 78250386Sadrian struct ip17x_softc *sc; 79250386Sadrian uint32_t oui, model, phy_id1, phy_id2; 80250386Sadrian 81250386Sadrian sc = device_get_softc(dev); 82250386Sadrian 83250386Sadrian /* Read ID from PHY 0. */ 84250386Sadrian phy_id1 = MDIO_READREG(device_get_parent(dev), 0, MII_PHYIDR1); 85250386Sadrian phy_id2 = MDIO_READREG(device_get_parent(dev), 0, MII_PHYIDR2); 86250386Sadrian 87305614Spfg oui = MII_OUI(phy_id1, phy_id2); 88250386Sadrian model = MII_MODEL(phy_id2); 89250386Sadrian /* We only care about IC+ devices. */ 90250386Sadrian if (oui != IP17X_OUI) { 91250386Sadrian device_printf(dev, 92250386Sadrian "Unsupported IC+ switch. Unknown OUI: %#x\n", oui); 93250386Sadrian return (ENXIO); 94250386Sadrian } 95250386Sadrian 96250386Sadrian switch (model) { 97250386Sadrian case IP17X_IP175A: 98250386Sadrian sc->sc_switchtype = IP17X_SWITCH_IP175A; 99250386Sadrian break; 100250386Sadrian case IP17X_IP175C: 101250386Sadrian sc->sc_switchtype = IP17X_SWITCH_IP175C; 102250386Sadrian break; 103250386Sadrian default: 104250386Sadrian device_printf(dev, "Unsupported IC+ switch model: %#x\n", 105250386Sadrian model); 106250386Sadrian return (ENXIO); 107250386Sadrian } 108250386Sadrian 109250386Sadrian /* IP175D has a specific ID register. */ 110250386Sadrian model = MDIO_READREG(device_get_parent(dev), IP175D_ID_PHY, 111250386Sadrian IP175D_ID_REG); 112250386Sadrian if (model == 0x175d) 113250386Sadrian sc->sc_switchtype = IP17X_SWITCH_IP175D; 114250386Sadrian else { 115250386Sadrian /* IP178 has more PHYs. Try it. */ 116250386Sadrian model = MDIO_READREG(device_get_parent(dev), 5, MII_PHYIDR1); 117250386Sadrian if (phy_id1 == model) 118250386Sadrian sc->sc_switchtype = IP17X_SWITCH_IP178C; 119250386Sadrian } 120250386Sadrian 121250386Sadrian device_set_desc_copy(dev, "IC+ IP17x switch driver"); 122250386Sadrian return (BUS_PROBE_DEFAULT); 123250386Sadrian} 124250386Sadrian 125250386Sadrianstatic int 126250386Sadrianip17x_attach_phys(struct ip17x_softc *sc) 127250386Sadrian{ 128250386Sadrian int err, phy, port; 129250386Sadrian char name[IFNAMSIZ]; 130250386Sadrian 131250386Sadrian port = err = 0; 132250386Sadrian 133250386Sadrian /* PHYs need an interface, so we generate a dummy one */ 134250386Sadrian snprintf(name, IFNAMSIZ, "%sport", device_get_nameunit(sc->sc_dev)); 135250386Sadrian for (phy = 0; phy < MII_NPHY; phy++) { 136250386Sadrian if (((1 << phy) & sc->phymask) == 0) 137250386Sadrian continue; 138250386Sadrian sc->phyport[phy] = port; 139250386Sadrian sc->portphy[port] = phy; 140250386Sadrian sc->ifp[port] = if_alloc(IFT_ETHER); 141250386Sadrian sc->ifp[port]->if_softc = sc; 142250386Sadrian sc->ifp[port]->if_flags |= IFF_UP | IFF_BROADCAST | 143250386Sadrian IFF_DRV_RUNNING | IFF_SIMPLEX; 144265770Sloos if_initname(sc->ifp[port], name, port); 145250386Sadrian sc->miibus[port] = malloc(sizeof(device_t), M_IP17X, 146250386Sadrian M_WAITOK | M_ZERO); 147250386Sadrian err = mii_attach(sc->sc_dev, sc->miibus[port], sc->ifp[port], 148250386Sadrian ip17x_ifmedia_upd, ip17x_ifmedia_sts, \ 149250386Sadrian BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0); 150250386Sadrian DPRINTF(sc->sc_dev, "%s attached to pseudo interface %s\n", 151250386Sadrian device_get_nameunit(*sc->miibus[port]), 152250386Sadrian sc->ifp[port]->if_xname); 153250386Sadrian if (err != 0) { 154250386Sadrian device_printf(sc->sc_dev, 155250386Sadrian "attaching PHY %d failed\n", 156250386Sadrian phy); 157250386Sadrian break; 158250386Sadrian } 159250386Sadrian sc->info.es_nports = port + 1; 160250386Sadrian if (++port >= sc->numports) 161250386Sadrian break; 162250386Sadrian } 163250386Sadrian return (err); 164250386Sadrian} 165250386Sadrian 166250386Sadrianstatic int 167250386Sadrianip17x_attach(device_t dev) 168250386Sadrian{ 169250386Sadrian struct ip17x_softc *sc; 170250386Sadrian int err; 171250386Sadrian 172250386Sadrian sc = device_get_softc(dev); 173250386Sadrian 174250386Sadrian sc->sc_dev = dev; 175250386Sadrian mtx_init(&sc->sc_mtx, "ip17x", NULL, MTX_DEF); 176250386Sadrian strlcpy(sc->info.es_name, device_get_desc(dev), 177250386Sadrian sizeof(sc->info.es_name)); 178250386Sadrian 179250386Sadrian /* XXX Defaults */ 180250386Sadrian sc->phymask = 0x0f; 181250386Sadrian sc->media = 100; 182250386Sadrian 183250386Sadrian (void) resource_int_value(device_get_name(dev), device_get_unit(dev), 184250386Sadrian "phymask", &sc->phymask); 185250386Sadrian 186250386Sadrian /* Number of vlans supported by the switch. */ 187250386Sadrian sc->info.es_nvlangroups = IP17X_MAX_VLANS; 188250386Sadrian 189250386Sadrian /* Attach the switch related functions. */ 190250386Sadrian if (IP17X_IS_SWITCH(sc, IP175C)) 191250386Sadrian ip175c_attach(sc); 192250386Sadrian else if (IP17X_IS_SWITCH(sc, IP175D)) 193250386Sadrian ip175d_attach(sc); 194250386Sadrian else 195250386Sadrian /* We don't have support to all the models yet :-/ */ 196250386Sadrian return (ENXIO); 197250386Sadrian 198250386Sadrian /* Always attach the cpu port. */ 199250386Sadrian sc->phymask |= (1 << sc->cpuport); 200250386Sadrian 201250386Sadrian sc->ifp = malloc(sizeof(struct ifnet *) * sc->numports, M_IP17X, 202250386Sadrian M_WAITOK | M_ZERO); 203250386Sadrian sc->pvid = malloc(sizeof(uint32_t) * sc->numports, M_IP17X, 204250386Sadrian M_WAITOK | M_ZERO); 205250386Sadrian sc->miibus = malloc(sizeof(device_t *) * sc->numports, M_IP17X, 206250386Sadrian M_WAITOK | M_ZERO); 207250386Sadrian sc->portphy = malloc(sizeof(int) * sc->numports, M_IP17X, 208250386Sadrian M_WAITOK | M_ZERO); 209250386Sadrian 210250386Sadrian /* Initialize the switch. */ 211250386Sadrian sc->hal.ip17x_reset(sc); 212250386Sadrian 213250386Sadrian /* 214250386Sadrian * Attach the PHYs and complete the bus enumeration. 215250386Sadrian */ 216250386Sadrian err = ip17x_attach_phys(sc); 217250386Sadrian if (err != 0) 218250386Sadrian return (err); 219250386Sadrian 220250386Sadrian /* 221250386Sadrian * Set the switch to port based vlans or disabled (if not supported 222250386Sadrian * on this model). 223250386Sadrian */ 224250386Sadrian sc->hal.ip17x_set_vlan_mode(sc, ETHERSWITCH_VLAN_PORT); 225250386Sadrian 226250386Sadrian bus_generic_probe(dev); 227250386Sadrian bus_enumerate_hinted_children(dev); 228250386Sadrian err = bus_generic_attach(dev); 229250386Sadrian if (err != 0) 230250386Sadrian return (err); 231250386Sadrian 232250386Sadrian callout_init(&sc->callout_tick, 0); 233250386Sadrian 234250386Sadrian ip17x_tick(sc); 235250386Sadrian 236250386Sadrian return (0); 237250386Sadrian} 238250386Sadrian 239250386Sadrianstatic int 240250386Sadrianip17x_detach(device_t dev) 241250386Sadrian{ 242250386Sadrian struct ip17x_softc *sc; 243250386Sadrian int i, port; 244250386Sadrian 245250386Sadrian sc = device_get_softc(dev); 246250386Sadrian callout_drain(&sc->callout_tick); 247250386Sadrian 248250386Sadrian for (i=0; i < MII_NPHY; i++) { 249250386Sadrian if (((1 << i) & sc->phymask) == 0) 250250386Sadrian continue; 251250386Sadrian port = sc->phyport[i]; 252250386Sadrian if (sc->miibus[port] != NULL) 253250386Sadrian device_delete_child(dev, (*sc->miibus[port])); 254250386Sadrian if (sc->ifp[port] != NULL) 255250386Sadrian if_free(sc->ifp[port]); 256250386Sadrian free(sc->miibus[port], M_IP17X); 257250386Sadrian } 258250386Sadrian 259250386Sadrian free(sc->portphy, M_IP17X); 260250386Sadrian free(sc->miibus, M_IP17X); 261250386Sadrian free(sc->pvid, M_IP17X); 262250386Sadrian free(sc->ifp, M_IP17X); 263250386Sadrian 264250386Sadrian /* Reset the switch. */ 265250386Sadrian sc->hal.ip17x_reset(sc); 266250386Sadrian 267250386Sadrian bus_generic_detach(dev); 268250386Sadrian mtx_destroy(&sc->sc_mtx); 269250386Sadrian 270250386Sadrian return (0); 271250386Sadrian} 272250386Sadrian 273250386Sadrianstatic inline struct mii_data * 274250386Sadrianip17x_miiforport(struct ip17x_softc *sc, int port) 275250386Sadrian{ 276250386Sadrian 277250386Sadrian if (port < 0 || port > sc->numports) 278250386Sadrian return (NULL); 279250386Sadrian return (device_get_softc(*sc->miibus[port])); 280250386Sadrian} 281250386Sadrian 282250386Sadrianstatic inline struct ifnet * 283250386Sadrianip17x_ifpforport(struct ip17x_softc *sc, int port) 284250386Sadrian{ 285250386Sadrian 286250386Sadrian if (port < 0 || port > sc->numports) 287250386Sadrian return (NULL); 288250386Sadrian return (sc->ifp[port]); 289250386Sadrian} 290250386Sadrian 291250386Sadrian/* 292250386Sadrian * Poll the status for all PHYs. 293250386Sadrian */ 294250386Sadrianstatic void 295250386Sadrianip17x_miipollstat(struct ip17x_softc *sc) 296250386Sadrian{ 297250386Sadrian struct mii_softc *miisc; 298250386Sadrian struct mii_data *mii; 299250386Sadrian int i, port; 300250386Sadrian 301250386Sadrian IP17X_LOCK_ASSERT(sc, MA_NOTOWNED); 302250386Sadrian 303250386Sadrian for (i = 0; i < MII_NPHY; i++) { 304250386Sadrian if (((1 << i) & sc->phymask) == 0) 305250386Sadrian continue; 306250386Sadrian port = sc->phyport[i]; 307250386Sadrian if ((*sc->miibus[port]) == NULL) 308250386Sadrian continue; 309250386Sadrian mii = device_get_softc(*sc->miibus[port]); 310250386Sadrian LIST_FOREACH(miisc, &mii->mii_phys, mii_list) { 311250386Sadrian if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) != 312250386Sadrian miisc->mii_inst) 313250386Sadrian continue; 314250386Sadrian ukphy_status(miisc); 315250386Sadrian mii_phy_update(miisc, MII_POLLSTAT); 316250386Sadrian } 317250386Sadrian } 318250386Sadrian} 319250386Sadrian 320250386Sadrianstatic void 321250386Sadrianip17x_tick(void *arg) 322250386Sadrian{ 323250386Sadrian struct ip17x_softc *sc; 324250386Sadrian 325250386Sadrian sc = arg; 326250386Sadrian ip17x_miipollstat(sc); 327250386Sadrian callout_reset(&sc->callout_tick, hz, ip17x_tick, sc); 328250386Sadrian} 329250386Sadrian 330250386Sadrianstatic void 331250386Sadrianip17x_lock(device_t dev) 332250386Sadrian{ 333250386Sadrian struct ip17x_softc *sc; 334250386Sadrian 335250386Sadrian sc = device_get_softc(dev); 336250386Sadrian IP17X_LOCK_ASSERT(sc, MA_NOTOWNED); 337250386Sadrian IP17X_LOCK(sc); 338250386Sadrian} 339250386Sadrian 340250386Sadrianstatic void 341250386Sadrianip17x_unlock(device_t dev) 342250386Sadrian{ 343250386Sadrian struct ip17x_softc *sc; 344250386Sadrian 345250386Sadrian sc = device_get_softc(dev); 346250386Sadrian IP17X_LOCK_ASSERT(sc, MA_OWNED); 347250386Sadrian IP17X_UNLOCK(sc); 348250386Sadrian} 349250386Sadrian 350250386Sadrianstatic etherswitch_info_t * 351250386Sadrianip17x_getinfo(device_t dev) 352250386Sadrian{ 353250386Sadrian struct ip17x_softc *sc; 354250386Sadrian 355250386Sadrian sc = device_get_softc(dev); 356250386Sadrian return (&sc->info); 357250386Sadrian} 358250386Sadrian 359250386Sadrianstatic int 360250386Sadrianip17x_getport(device_t dev, etherswitch_port_t *p) 361250386Sadrian{ 362250386Sadrian struct ip17x_softc *sc; 363250386Sadrian struct ifmediareq *ifmr; 364250386Sadrian struct mii_data *mii; 365250386Sadrian int err, phy; 366250386Sadrian 367250386Sadrian sc = device_get_softc(dev); 368250386Sadrian if (p->es_port < 0 || p->es_port >= sc->numports) 369250386Sadrian return (ENXIO); 370250386Sadrian 371250386Sadrian phy = sc->portphy[p->es_port]; 372250386Sadrian 373250386Sadrian /* Retrieve the PVID. */ 374250386Sadrian p->es_pvid = sc->pvid[phy]; 375250386Sadrian 376250386Sadrian /* Port flags. */ 377250386Sadrian if (sc->addtag & (1 << phy)) 378250386Sadrian p->es_flags |= ETHERSWITCH_PORT_ADDTAG; 379250386Sadrian if (sc->striptag & (1 << phy)) 380250386Sadrian p->es_flags |= ETHERSWITCH_PORT_STRIPTAG; 381250386Sadrian 382250386Sadrian ifmr = &p->es_ifmr; 383250386Sadrian 384250386Sadrian /* No media settings ? */ 385250386Sadrian if (p->es_ifmr.ifm_count == 0) 386250386Sadrian return (0); 387250386Sadrian 388250386Sadrian mii = ip17x_miiforport(sc, p->es_port); 389250386Sadrian if (mii == NULL) 390250386Sadrian return (ENXIO); 391250386Sadrian if (phy == sc->cpuport) { 392250386Sadrian /* fill in fixed values for CPU port */ 393250386Sadrian p->es_flags |= ETHERSWITCH_PORT_CPU; 394250386Sadrian ifmr->ifm_count = 0; 395250386Sadrian if (sc->media == 100) 396250386Sadrian ifmr->ifm_current = ifmr->ifm_active = 397250386Sadrian IFM_ETHER | IFM_100_TX | IFM_FDX; 398250386Sadrian else 399250386Sadrian ifmr->ifm_current = ifmr->ifm_active = 400250386Sadrian IFM_ETHER | IFM_1000_T | IFM_FDX; 401250386Sadrian ifmr->ifm_mask = 0; 402250386Sadrian ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID; 403250386Sadrian } else { 404250386Sadrian err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr, 405250386Sadrian &mii->mii_media, SIOCGIFMEDIA); 406250386Sadrian if (err) 407250386Sadrian return (err); 408250386Sadrian } 409250386Sadrian return (0); 410250386Sadrian} 411250386Sadrian 412250386Sadrianstatic int 413250386Sadrianip17x_setport(device_t dev, etherswitch_port_t *p) 414250386Sadrian{ 415250386Sadrian struct ip17x_softc *sc; 416250386Sadrian struct ifmedia *ifm; 417250386Sadrian struct ifnet *ifp; 418250386Sadrian struct mii_data *mii; 419250386Sadrian int phy; 420250386Sadrian 421250386Sadrian sc = device_get_softc(dev); 422250386Sadrian if (p->es_port < 0 || p->es_port >= sc->numports) 423250386Sadrian return (ENXIO); 424250386Sadrian 425250386Sadrian phy = sc->portphy[p->es_port]; 426250386Sadrian ifp = ip17x_ifpforport(sc, p->es_port); 427250386Sadrian mii = ip17x_miiforport(sc, p->es_port); 428250386Sadrian if (ifp == NULL || mii == NULL) 429250386Sadrian return (ENXIO); 430250386Sadrian 431250386Sadrian /* Port flags. */ 432250386Sadrian if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) { 433250386Sadrian 434250386Sadrian /* Set the PVID. */ 435250386Sadrian if (p->es_pvid != 0) { 436250386Sadrian if (IP17X_IS_SWITCH(sc, IP175C) && 437250386Sadrian p->es_pvid > IP175C_LAST_VLAN) 438250386Sadrian return (ENXIO); 439250386Sadrian sc->pvid[phy] = p->es_pvid; 440250386Sadrian } 441250386Sadrian 442250386Sadrian /* Mutually exclusive. */ 443250386Sadrian if (p->es_flags & ETHERSWITCH_PORT_ADDTAG && 444250386Sadrian p->es_flags & ETHERSWITCH_PORT_STRIPTAG) 445250386Sadrian return (EINVAL); 446250386Sadrian 447250386Sadrian /* Reset the settings for this port. */ 448250386Sadrian sc->addtag &= ~(1 << phy); 449250386Sadrian sc->striptag &= ~(1 << phy); 450250386Sadrian 451250386Sadrian /* And then set it to the new value. */ 452250386Sadrian if (p->es_flags & ETHERSWITCH_PORT_ADDTAG) 453250386Sadrian sc->addtag |= (1 << phy); 454250386Sadrian if (p->es_flags & ETHERSWITCH_PORT_STRIPTAG) 455250386Sadrian sc->striptag |= (1 << phy); 456250386Sadrian } 457250386Sadrian 458250386Sadrian /* Update the switch configuration. */ 459250386Sadrian if (sc->hal.ip17x_hw_setup(sc)) 460250386Sadrian return (ENXIO); 461250386Sadrian 462250386Sadrian /* Do not allow media changes on CPU port. */ 463250386Sadrian if (phy == sc->cpuport) 464250386Sadrian return (0); 465250386Sadrian 466250386Sadrian /* No media settings ? */ 467250386Sadrian if (p->es_ifmr.ifm_count == 0) 468250386Sadrian return (0); 469250386Sadrian 470250386Sadrian ifm = &mii->mii_media; 471250386Sadrian return (ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA)); 472250386Sadrian} 473250386Sadrian 474250386Sadrianstatic void 475250386Sadrianip17x_statchg(device_t dev) 476250386Sadrian{ 477250386Sadrian 478250386Sadrian DPRINTF(dev, "%s\n", __func__); 479250386Sadrian} 480250386Sadrian 481250386Sadrianstatic int 482250386Sadrianip17x_ifmedia_upd(struct ifnet *ifp) 483250386Sadrian{ 484250386Sadrian struct ip17x_softc *sc; 485250386Sadrian struct mii_data *mii; 486250386Sadrian 487265770Sloos sc = ifp->if_softc; 488250386Sadrian DPRINTF(sc->sc_dev, "%s\n", __func__); 489250386Sadrian mii = ip17x_miiforport(sc, ifp->if_dunit); 490250386Sadrian if (mii == NULL) 491250386Sadrian return (ENXIO); 492250386Sadrian mii_mediachg(mii); 493265770Sloos 494250386Sadrian return (0); 495250386Sadrian} 496250386Sadrian 497250386Sadrianstatic void 498250386Sadrianip17x_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 499250386Sadrian{ 500250386Sadrian struct ip17x_softc *sc; 501250386Sadrian struct mii_data *mii; 502250386Sadrian 503265770Sloos sc = ifp->if_softc; 504250386Sadrian DPRINTF(sc->sc_dev, "%s\n", __func__); 505250386Sadrian mii = ip17x_miiforport(sc, ifp->if_dunit); 506250386Sadrian if (mii == NULL) 507250386Sadrian return; 508250386Sadrian mii_pollstat(mii); 509250386Sadrian ifmr->ifm_active = mii->mii_media_active; 510250386Sadrian ifmr->ifm_status = mii->mii_media_status; 511250386Sadrian} 512250386Sadrian 513250386Sadrianstatic int 514250386Sadrianip17x_readreg(device_t dev, int addr) 515250386Sadrian{ 516250386Sadrian struct ip17x_softc *sc; 517250386Sadrian 518250386Sadrian sc = device_get_softc(dev); 519250386Sadrian IP17X_LOCK_ASSERT(sc, MA_OWNED); 520250386Sadrian 521250386Sadrian /* Not supported. */ 522250386Sadrian return (0); 523250386Sadrian} 524250386Sadrian 525250386Sadrianstatic int 526250386Sadrianip17x_writereg(device_t dev, int addr, int value) 527250386Sadrian{ 528250386Sadrian struct ip17x_softc *sc; 529250386Sadrian 530250386Sadrian sc = device_get_softc(dev); 531250386Sadrian IP17X_LOCK_ASSERT(sc, MA_OWNED); 532250386Sadrian 533250386Sadrian /* Not supported. */ 534250386Sadrian return (0); 535250386Sadrian} 536250386Sadrian 537250386Sadrianstatic int 538250386Sadrianip17x_getconf(device_t dev, etherswitch_conf_t *conf) 539250386Sadrian{ 540250386Sadrian struct ip17x_softc *sc; 541250386Sadrian 542250386Sadrian sc = device_get_softc(dev); 543250386Sadrian 544250386Sadrian /* Return the VLAN mode. */ 545250386Sadrian conf->cmd = ETHERSWITCH_CONF_VLAN_MODE; 546250386Sadrian conf->vlan_mode = sc->hal.ip17x_get_vlan_mode(sc); 547250386Sadrian 548250386Sadrian return (0); 549250386Sadrian} 550250386Sadrian 551250386Sadrianstatic int 552250386Sadrianip17x_setconf(device_t dev, etherswitch_conf_t *conf) 553250386Sadrian{ 554250386Sadrian struct ip17x_softc *sc; 555250386Sadrian 556250386Sadrian sc = device_get_softc(dev); 557250386Sadrian 558250386Sadrian /* Set the VLAN mode. */ 559250386Sadrian if (conf->cmd & ETHERSWITCH_CONF_VLAN_MODE) 560250386Sadrian sc->hal.ip17x_set_vlan_mode(sc, conf->vlan_mode); 561250386Sadrian 562250386Sadrian return (0); 563250386Sadrian} 564250386Sadrian 565250386Sadrianstatic device_method_t ip17x_methods[] = { 566250386Sadrian /* Device interface */ 567250386Sadrian DEVMETHOD(device_probe, ip17x_probe), 568250386Sadrian DEVMETHOD(device_attach, ip17x_attach), 569250386Sadrian DEVMETHOD(device_detach, ip17x_detach), 570250386Sadrian 571250386Sadrian /* bus interface */ 572250386Sadrian DEVMETHOD(bus_add_child, device_add_child_ordered), 573250386Sadrian 574250386Sadrian /* MII interface */ 575250386Sadrian DEVMETHOD(miibus_readreg, ip17x_readphy), 576250386Sadrian DEVMETHOD(miibus_writereg, ip17x_writephy), 577250386Sadrian DEVMETHOD(miibus_statchg, ip17x_statchg), 578250386Sadrian 579250386Sadrian /* MDIO interface */ 580250386Sadrian DEVMETHOD(mdio_readreg, ip17x_readphy), 581250386Sadrian DEVMETHOD(mdio_writereg, ip17x_writephy), 582250386Sadrian 583250386Sadrian /* etherswitch interface */ 584250386Sadrian DEVMETHOD(etherswitch_lock, ip17x_lock), 585250386Sadrian DEVMETHOD(etherswitch_unlock, ip17x_unlock), 586250386Sadrian DEVMETHOD(etherswitch_getinfo, ip17x_getinfo), 587250386Sadrian DEVMETHOD(etherswitch_readreg, ip17x_readreg), 588250386Sadrian DEVMETHOD(etherswitch_writereg, ip17x_writereg), 589250386Sadrian DEVMETHOD(etherswitch_readphyreg, ip17x_readphy), 590250386Sadrian DEVMETHOD(etherswitch_writephyreg, ip17x_writephy), 591250386Sadrian DEVMETHOD(etherswitch_getport, ip17x_getport), 592250386Sadrian DEVMETHOD(etherswitch_setport, ip17x_setport), 593250386Sadrian DEVMETHOD(etherswitch_getvgroup, ip17x_getvgroup), 594250386Sadrian DEVMETHOD(etherswitch_setvgroup, ip17x_setvgroup), 595250386Sadrian DEVMETHOD(etherswitch_getconf, ip17x_getconf), 596250386Sadrian DEVMETHOD(etherswitch_setconf, ip17x_setconf), 597250386Sadrian 598250386Sadrian DEVMETHOD_END 599250386Sadrian}; 600250386Sadrian 601250386SadrianDEFINE_CLASS_0(ip17x, ip17x_driver, ip17x_methods, 602250386Sadrian sizeof(struct ip17x_softc)); 603250386Sadrianstatic devclass_t ip17x_devclass; 604250386Sadrian 605250386SadrianDRIVER_MODULE(ip17x, mdio, ip17x_driver, ip17x_devclass, 0, 0); 606250386SadrianDRIVER_MODULE(miibus, ip17x, miibus_driver, miibus_devclass, 0, 0); 607250386SadrianDRIVER_MODULE(mdio, ip17x, mdio_driver, mdio_devclass, 0, 0); 608250386SadrianDRIVER_MODULE(etherswitch, ip17x, etherswitch_driver, etherswitch_devclass, 0, 0); 609250386SadrianMODULE_VERSION(ip17x, 1); 610250386SadrianMODULE_DEPEND(ip17x, miibus, 1, 1, 1); /* XXX which versions? */ 611250386SadrianMODULE_DEPEND(ip17x, etherswitch, 1, 1, 1); /* XXX which versions? */ 612