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> 35262848Sbrueffer#include <sys/lock.h> 36262848Sbrueffer#include <sys/malloc.h> 37250386Sadrian#include <sys/module.h> 38262848Sbrueffer#include <sys/mutex.h> 39250386Sadrian#include <sys/socket.h> 40250386Sadrian#include <sys/sockio.h> 41250386Sadrian#include <sys/sysctl.h> 42250386Sadrian#include <sys/systm.h> 43262848Sbrueffer#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> 49262848Sbrueffer#include <net/if_var.h> 50250386Sadrian 51250386Sadrian#include <machine/bus.h> 52250386Sadrian#include <dev/mii/mii.h> 53250386Sadrian#include <dev/mii/miivar.h> 54250386Sadrian#include <dev/etherswitch/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 87305615Spfg 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; 144250386Sadrian sc->ifname[port] = malloc(strlen(name)+1, M_IP17X, M_WAITOK); 145250386Sadrian bcopy(name, sc->ifname[port], strlen(name)+1); 146250386Sadrian if_initname(sc->ifp[port], sc->ifname[port], port); 147250386Sadrian sc->miibus[port] = malloc(sizeof(device_t), M_IP17X, 148250386Sadrian M_WAITOK | M_ZERO); 149250386Sadrian err = mii_attach(sc->sc_dev, sc->miibus[port], sc->ifp[port], 150250386Sadrian ip17x_ifmedia_upd, ip17x_ifmedia_sts, \ 151250386Sadrian BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0); 152250386Sadrian DPRINTF(sc->sc_dev, "%s attached to pseudo interface %s\n", 153250386Sadrian device_get_nameunit(*sc->miibus[port]), 154250386Sadrian sc->ifp[port]->if_xname); 155250386Sadrian if (err != 0) { 156250386Sadrian device_printf(sc->sc_dev, 157250386Sadrian "attaching PHY %d failed\n", 158250386Sadrian phy); 159250386Sadrian break; 160250386Sadrian } 161250386Sadrian sc->info.es_nports = port + 1; 162250386Sadrian if (++port >= sc->numports) 163250386Sadrian break; 164250386Sadrian } 165250386Sadrian return (err); 166250386Sadrian} 167250386Sadrian 168250386Sadrianstatic int 169250386Sadrianip17x_attach(device_t dev) 170250386Sadrian{ 171250386Sadrian struct ip17x_softc *sc; 172250386Sadrian int err; 173250386Sadrian 174250386Sadrian sc = device_get_softc(dev); 175250386Sadrian 176250386Sadrian sc->sc_dev = dev; 177250386Sadrian mtx_init(&sc->sc_mtx, "ip17x", NULL, MTX_DEF); 178250386Sadrian strlcpy(sc->info.es_name, device_get_desc(dev), 179250386Sadrian sizeof(sc->info.es_name)); 180250386Sadrian 181250386Sadrian /* XXX Defaults */ 182250386Sadrian sc->phymask = 0x0f; 183250386Sadrian sc->media = 100; 184250386Sadrian 185250386Sadrian (void) resource_int_value(device_get_name(dev), device_get_unit(dev), 186250386Sadrian "phymask", &sc->phymask); 187250386Sadrian 188250386Sadrian /* Number of vlans supported by the switch. */ 189250386Sadrian sc->info.es_nvlangroups = IP17X_MAX_VLANS; 190250386Sadrian 191250386Sadrian /* Attach the switch related functions. */ 192250386Sadrian if (IP17X_IS_SWITCH(sc, IP175C)) 193250386Sadrian ip175c_attach(sc); 194250386Sadrian else if (IP17X_IS_SWITCH(sc, IP175D)) 195250386Sadrian ip175d_attach(sc); 196250386Sadrian else 197250386Sadrian /* We don't have support to all the models yet :-/ */ 198250386Sadrian return (ENXIO); 199250386Sadrian 200250386Sadrian /* Always attach the cpu port. */ 201250386Sadrian sc->phymask |= (1 << sc->cpuport); 202250386Sadrian 203250386Sadrian sc->ifp = malloc(sizeof(struct ifnet *) * sc->numports, M_IP17X, 204250386Sadrian M_WAITOK | M_ZERO); 205250386Sadrian sc->pvid = malloc(sizeof(uint32_t) * sc->numports, M_IP17X, 206250386Sadrian M_WAITOK | M_ZERO); 207250386Sadrian sc->ifname = malloc(sizeof(char *) * sc->numports, M_IP17X, 208250386Sadrian M_WAITOK | M_ZERO); 209250386Sadrian sc->miibus = malloc(sizeof(device_t *) * sc->numports, M_IP17X, 210250386Sadrian M_WAITOK | M_ZERO); 211250386Sadrian sc->portphy = malloc(sizeof(int) * sc->numports, M_IP17X, 212250386Sadrian M_WAITOK | M_ZERO); 213250386Sadrian 214250386Sadrian /* Initialize the switch. */ 215250386Sadrian sc->hal.ip17x_reset(sc); 216250386Sadrian 217250386Sadrian /* 218250386Sadrian * Attach the PHYs and complete the bus enumeration. 219250386Sadrian */ 220250386Sadrian err = ip17x_attach_phys(sc); 221250386Sadrian if (err != 0) 222250386Sadrian return (err); 223250386Sadrian 224250386Sadrian /* 225250386Sadrian * Set the switch to port based vlans or disabled (if not supported 226250386Sadrian * on this model). 227250386Sadrian */ 228250386Sadrian sc->hal.ip17x_set_vlan_mode(sc, ETHERSWITCH_VLAN_PORT); 229250386Sadrian 230250386Sadrian bus_generic_probe(dev); 231250386Sadrian bus_enumerate_hinted_children(dev); 232250386Sadrian err = bus_generic_attach(dev); 233250386Sadrian if (err != 0) 234250386Sadrian return (err); 235250386Sadrian 236250386Sadrian callout_init(&sc->callout_tick, 0); 237250386Sadrian 238250386Sadrian ip17x_tick(sc); 239250386Sadrian 240250386Sadrian return (0); 241250386Sadrian} 242250386Sadrian 243250386Sadrianstatic int 244250386Sadrianip17x_detach(device_t dev) 245250386Sadrian{ 246250386Sadrian struct ip17x_softc *sc; 247250386Sadrian int i, port; 248250386Sadrian 249250386Sadrian sc = device_get_softc(dev); 250250386Sadrian callout_drain(&sc->callout_tick); 251250386Sadrian 252250386Sadrian for (i=0; i < MII_NPHY; i++) { 253250386Sadrian if (((1 << i) & sc->phymask) == 0) 254250386Sadrian continue; 255250386Sadrian port = sc->phyport[i]; 256250386Sadrian if (sc->miibus[port] != NULL) 257250386Sadrian device_delete_child(dev, (*sc->miibus[port])); 258250386Sadrian if (sc->ifp[port] != NULL) 259250386Sadrian if_free(sc->ifp[port]); 260250386Sadrian free(sc->ifname[port], M_IP17X); 261250386Sadrian free(sc->miibus[port], M_IP17X); 262250386Sadrian } 263250386Sadrian 264250386Sadrian free(sc->portphy, M_IP17X); 265250386Sadrian free(sc->miibus, M_IP17X); 266250386Sadrian free(sc->ifname, M_IP17X); 267250386Sadrian free(sc->pvid, M_IP17X); 268250386Sadrian free(sc->ifp, M_IP17X); 269250386Sadrian 270250386Sadrian /* Reset the switch. */ 271250386Sadrian sc->hal.ip17x_reset(sc); 272250386Sadrian 273250386Sadrian bus_generic_detach(dev); 274250386Sadrian mtx_destroy(&sc->sc_mtx); 275250386Sadrian 276250386Sadrian return (0); 277250386Sadrian} 278250386Sadrian 279250386Sadrianstatic inline struct mii_data * 280250386Sadrianip17x_miiforport(struct ip17x_softc *sc, int port) 281250386Sadrian{ 282250386Sadrian 283250386Sadrian if (port < 0 || port > sc->numports) 284250386Sadrian return (NULL); 285250386Sadrian return (device_get_softc(*sc->miibus[port])); 286250386Sadrian} 287250386Sadrian 288250386Sadrianstatic inline struct ifnet * 289250386Sadrianip17x_ifpforport(struct ip17x_softc *sc, int port) 290250386Sadrian{ 291250386Sadrian 292250386Sadrian if (port < 0 || port > sc->numports) 293250386Sadrian return (NULL); 294250386Sadrian return (sc->ifp[port]); 295250386Sadrian} 296250386Sadrian 297250386Sadrian/* 298250386Sadrian * Poll the status for all PHYs. 299250386Sadrian */ 300250386Sadrianstatic void 301250386Sadrianip17x_miipollstat(struct ip17x_softc *sc) 302250386Sadrian{ 303250386Sadrian struct mii_softc *miisc; 304250386Sadrian struct mii_data *mii; 305250386Sadrian int i, port; 306250386Sadrian 307250386Sadrian IP17X_LOCK_ASSERT(sc, MA_NOTOWNED); 308250386Sadrian 309250386Sadrian for (i = 0; i < MII_NPHY; i++) { 310250386Sadrian if (((1 << i) & sc->phymask) == 0) 311250386Sadrian continue; 312250386Sadrian port = sc->phyport[i]; 313250386Sadrian if ((*sc->miibus[port]) == NULL) 314250386Sadrian continue; 315250386Sadrian mii = device_get_softc(*sc->miibus[port]); 316250386Sadrian LIST_FOREACH(miisc, &mii->mii_phys, mii_list) { 317250386Sadrian if (IFM_INST(mii->mii_media.ifm_cur->ifm_media) != 318250386Sadrian miisc->mii_inst) 319250386Sadrian continue; 320250386Sadrian ukphy_status(miisc); 321250386Sadrian mii_phy_update(miisc, MII_POLLSTAT); 322250386Sadrian } 323250386Sadrian } 324250386Sadrian} 325250386Sadrian 326250386Sadrianstatic void 327250386Sadrianip17x_tick(void *arg) 328250386Sadrian{ 329250386Sadrian struct ip17x_softc *sc; 330250386Sadrian 331250386Sadrian sc = arg; 332250386Sadrian ip17x_miipollstat(sc); 333250386Sadrian callout_reset(&sc->callout_tick, hz, ip17x_tick, sc); 334250386Sadrian} 335250386Sadrian 336250386Sadrianstatic void 337250386Sadrianip17x_lock(device_t dev) 338250386Sadrian{ 339250386Sadrian struct ip17x_softc *sc; 340250386Sadrian 341250386Sadrian sc = device_get_softc(dev); 342250386Sadrian IP17X_LOCK_ASSERT(sc, MA_NOTOWNED); 343250386Sadrian IP17X_LOCK(sc); 344250386Sadrian} 345250386Sadrian 346250386Sadrianstatic void 347250386Sadrianip17x_unlock(device_t dev) 348250386Sadrian{ 349250386Sadrian struct ip17x_softc *sc; 350250386Sadrian 351250386Sadrian sc = device_get_softc(dev); 352250386Sadrian IP17X_LOCK_ASSERT(sc, MA_OWNED); 353250386Sadrian IP17X_UNLOCK(sc); 354250386Sadrian} 355250386Sadrian 356250386Sadrianstatic etherswitch_info_t * 357250386Sadrianip17x_getinfo(device_t dev) 358250386Sadrian{ 359250386Sadrian struct ip17x_softc *sc; 360250386Sadrian 361250386Sadrian sc = device_get_softc(dev); 362250386Sadrian return (&sc->info); 363250386Sadrian} 364250386Sadrian 365250386Sadrianstatic int 366250386Sadrianip17x_getport(device_t dev, etherswitch_port_t *p) 367250386Sadrian{ 368250386Sadrian struct ip17x_softc *sc; 369250386Sadrian struct ifmediareq *ifmr; 370250386Sadrian struct mii_data *mii; 371250386Sadrian int err, phy; 372250386Sadrian 373250386Sadrian sc = device_get_softc(dev); 374250386Sadrian if (p->es_port < 0 || p->es_port >= sc->numports) 375250386Sadrian return (ENXIO); 376250386Sadrian 377250386Sadrian phy = sc->portphy[p->es_port]; 378250386Sadrian 379250386Sadrian /* Retrieve the PVID. */ 380250386Sadrian p->es_pvid = sc->pvid[phy]; 381250386Sadrian 382250386Sadrian /* Port flags. */ 383250386Sadrian if (sc->addtag & (1 << phy)) 384250386Sadrian p->es_flags |= ETHERSWITCH_PORT_ADDTAG; 385250386Sadrian if (sc->striptag & (1 << phy)) 386250386Sadrian p->es_flags |= ETHERSWITCH_PORT_STRIPTAG; 387250386Sadrian 388250386Sadrian ifmr = &p->es_ifmr; 389250386Sadrian 390250386Sadrian /* No media settings ? */ 391250386Sadrian if (p->es_ifmr.ifm_count == 0) 392250386Sadrian return (0); 393250386Sadrian 394250386Sadrian mii = ip17x_miiforport(sc, p->es_port); 395250386Sadrian if (mii == NULL) 396250386Sadrian return (ENXIO); 397250386Sadrian if (phy == sc->cpuport) { 398250386Sadrian /* fill in fixed values for CPU port */ 399250386Sadrian p->es_flags |= ETHERSWITCH_PORT_CPU; 400250386Sadrian ifmr->ifm_count = 0; 401250386Sadrian if (sc->media == 100) 402250386Sadrian ifmr->ifm_current = ifmr->ifm_active = 403250386Sadrian IFM_ETHER | IFM_100_TX | IFM_FDX; 404250386Sadrian else 405250386Sadrian ifmr->ifm_current = ifmr->ifm_active = 406250386Sadrian IFM_ETHER | IFM_1000_T | IFM_FDX; 407250386Sadrian ifmr->ifm_mask = 0; 408250386Sadrian ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID; 409250386Sadrian } else { 410250386Sadrian err = ifmedia_ioctl(mii->mii_ifp, &p->es_ifr, 411250386Sadrian &mii->mii_media, SIOCGIFMEDIA); 412250386Sadrian if (err) 413250386Sadrian return (err); 414250386Sadrian } 415250386Sadrian return (0); 416250386Sadrian} 417250386Sadrian 418250386Sadrianstatic int 419250386Sadrianip17x_setport(device_t dev, etherswitch_port_t *p) 420250386Sadrian{ 421250386Sadrian struct ip17x_softc *sc; 422250386Sadrian struct ifmedia *ifm; 423250386Sadrian struct ifnet *ifp; 424250386Sadrian struct mii_data *mii; 425250386Sadrian int phy; 426250386Sadrian 427250386Sadrian sc = device_get_softc(dev); 428250386Sadrian if (p->es_port < 0 || p->es_port >= sc->numports) 429250386Sadrian return (ENXIO); 430250386Sadrian 431250386Sadrian phy = sc->portphy[p->es_port]; 432250386Sadrian ifp = ip17x_ifpforport(sc, p->es_port); 433250386Sadrian mii = ip17x_miiforport(sc, p->es_port); 434250386Sadrian if (ifp == NULL || mii == NULL) 435250386Sadrian return (ENXIO); 436250386Sadrian 437250386Sadrian /* Port flags. */ 438250386Sadrian if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) { 439250386Sadrian 440250386Sadrian /* Set the PVID. */ 441250386Sadrian if (p->es_pvid != 0) { 442250386Sadrian if (IP17X_IS_SWITCH(sc, IP175C) && 443250386Sadrian p->es_pvid > IP175C_LAST_VLAN) 444250386Sadrian return (ENXIO); 445250386Sadrian sc->pvid[phy] = p->es_pvid; 446250386Sadrian } 447250386Sadrian 448250386Sadrian /* Mutually exclusive. */ 449250386Sadrian if (p->es_flags & ETHERSWITCH_PORT_ADDTAG && 450250386Sadrian p->es_flags & ETHERSWITCH_PORT_STRIPTAG) 451250386Sadrian return (EINVAL); 452250386Sadrian 453250386Sadrian /* Reset the settings for this port. */ 454250386Sadrian sc->addtag &= ~(1 << phy); 455250386Sadrian sc->striptag &= ~(1 << phy); 456250386Sadrian 457250386Sadrian /* And then set it to the new value. */ 458250386Sadrian if (p->es_flags & ETHERSWITCH_PORT_ADDTAG) 459250386Sadrian sc->addtag |= (1 << phy); 460250386Sadrian if (p->es_flags & ETHERSWITCH_PORT_STRIPTAG) 461250386Sadrian sc->striptag |= (1 << phy); 462250386Sadrian } 463250386Sadrian 464250386Sadrian /* Update the switch configuration. */ 465250386Sadrian if (sc->hal.ip17x_hw_setup(sc)) 466250386Sadrian return (ENXIO); 467250386Sadrian 468250386Sadrian /* Do not allow media changes on CPU port. */ 469250386Sadrian if (phy == sc->cpuport) 470250386Sadrian return (0); 471250386Sadrian 472250386Sadrian /* No media settings ? */ 473250386Sadrian if (p->es_ifmr.ifm_count == 0) 474250386Sadrian return (0); 475250386Sadrian 476250386Sadrian ifm = &mii->mii_media; 477250386Sadrian return (ifmedia_ioctl(ifp, &p->es_ifr, ifm, SIOCSIFMEDIA)); 478250386Sadrian} 479250386Sadrian 480250386Sadrianstatic void 481250386Sadrianip17x_statchg(device_t dev) 482250386Sadrian{ 483250386Sadrian 484250386Sadrian DPRINTF(dev, "%s\n", __func__); 485250386Sadrian} 486250386Sadrian 487250386Sadrianstatic int 488250386Sadrianip17x_ifmedia_upd(struct ifnet *ifp) 489250386Sadrian{ 490250386Sadrian struct ip17x_softc *sc; 491250386Sadrian struct mii_data *mii; 492250386Sadrian 493250386Sadrian DPRINTF(sc->sc_dev, "%s\n", __func__); 494250386Sadrian sc = ifp->if_softc; 495250386Sadrian mii = ip17x_miiforport(sc, ifp->if_dunit); 496250386Sadrian if (mii == NULL) 497250386Sadrian return (ENXIO); 498250386Sadrian mii_mediachg(mii); 499250386Sadrian return (0); 500250386Sadrian} 501250386Sadrian 502250386Sadrianstatic void 503250386Sadrianip17x_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 504250386Sadrian{ 505250386Sadrian struct ip17x_softc *sc; 506250386Sadrian struct mii_data *mii; 507250386Sadrian 508250386Sadrian DPRINTF(sc->sc_dev, "%s\n", __func__); 509250386Sadrian 510250386Sadrian sc = ifp->if_softc; 511250386Sadrian mii = ip17x_miiforport(sc, ifp->if_dunit); 512250386Sadrian if (mii == NULL) 513250386Sadrian return; 514250386Sadrian mii_pollstat(mii); 515250386Sadrian ifmr->ifm_active = mii->mii_media_active; 516250386Sadrian ifmr->ifm_status = mii->mii_media_status; 517250386Sadrian} 518250386Sadrian 519250386Sadrianstatic int 520250386Sadrianip17x_readreg(device_t dev, int addr) 521250386Sadrian{ 522250386Sadrian struct ip17x_softc *sc; 523250386Sadrian 524250386Sadrian sc = device_get_softc(dev); 525250386Sadrian IP17X_LOCK_ASSERT(sc, MA_OWNED); 526250386Sadrian 527250386Sadrian /* Not supported. */ 528250386Sadrian return (0); 529250386Sadrian} 530250386Sadrian 531250386Sadrianstatic int 532250386Sadrianip17x_writereg(device_t dev, int addr, int value) 533250386Sadrian{ 534250386Sadrian struct ip17x_softc *sc; 535250386Sadrian 536250386Sadrian sc = device_get_softc(dev); 537250386Sadrian IP17X_LOCK_ASSERT(sc, MA_OWNED); 538250386Sadrian 539250386Sadrian /* Not supported. */ 540250386Sadrian return (0); 541250386Sadrian} 542250386Sadrian 543250386Sadrianstatic int 544250386Sadrianip17x_getconf(device_t dev, etherswitch_conf_t *conf) 545250386Sadrian{ 546250386Sadrian struct ip17x_softc *sc; 547250386Sadrian 548250386Sadrian sc = device_get_softc(dev); 549250386Sadrian 550250386Sadrian /* Return the VLAN mode. */ 551250386Sadrian conf->cmd = ETHERSWITCH_CONF_VLAN_MODE; 552250386Sadrian conf->vlan_mode = sc->hal.ip17x_get_vlan_mode(sc); 553250386Sadrian 554250386Sadrian return (0); 555250386Sadrian} 556250386Sadrian 557250386Sadrianstatic int 558250386Sadrianip17x_setconf(device_t dev, etherswitch_conf_t *conf) 559250386Sadrian{ 560250386Sadrian struct ip17x_softc *sc; 561250386Sadrian 562250386Sadrian sc = device_get_softc(dev); 563250386Sadrian 564250386Sadrian /* Set the VLAN mode. */ 565250386Sadrian if (conf->cmd & ETHERSWITCH_CONF_VLAN_MODE) 566250386Sadrian sc->hal.ip17x_set_vlan_mode(sc, conf->vlan_mode); 567250386Sadrian 568250386Sadrian return (0); 569250386Sadrian} 570250386Sadrian 571250386Sadrianstatic device_method_t ip17x_methods[] = { 572250386Sadrian /* Device interface */ 573250386Sadrian DEVMETHOD(device_probe, ip17x_probe), 574250386Sadrian DEVMETHOD(device_attach, ip17x_attach), 575250386Sadrian DEVMETHOD(device_detach, ip17x_detach), 576250386Sadrian 577250386Sadrian /* bus interface */ 578250386Sadrian DEVMETHOD(bus_add_child, device_add_child_ordered), 579250386Sadrian 580250386Sadrian /* MII interface */ 581250386Sadrian DEVMETHOD(miibus_readreg, ip17x_readphy), 582250386Sadrian DEVMETHOD(miibus_writereg, ip17x_writephy), 583250386Sadrian DEVMETHOD(miibus_statchg, ip17x_statchg), 584250386Sadrian 585250386Sadrian /* MDIO interface */ 586250386Sadrian DEVMETHOD(mdio_readreg, ip17x_readphy), 587250386Sadrian DEVMETHOD(mdio_writereg, ip17x_writephy), 588250386Sadrian 589250386Sadrian /* etherswitch interface */ 590250386Sadrian DEVMETHOD(etherswitch_lock, ip17x_lock), 591250386Sadrian DEVMETHOD(etherswitch_unlock, ip17x_unlock), 592250386Sadrian DEVMETHOD(etherswitch_getinfo, ip17x_getinfo), 593250386Sadrian DEVMETHOD(etherswitch_readreg, ip17x_readreg), 594250386Sadrian DEVMETHOD(etherswitch_writereg, ip17x_writereg), 595250386Sadrian DEVMETHOD(etherswitch_readphyreg, ip17x_readphy), 596250386Sadrian DEVMETHOD(etherswitch_writephyreg, ip17x_writephy), 597250386Sadrian DEVMETHOD(etherswitch_getport, ip17x_getport), 598250386Sadrian DEVMETHOD(etherswitch_setport, ip17x_setport), 599250386Sadrian DEVMETHOD(etherswitch_getvgroup, ip17x_getvgroup), 600250386Sadrian DEVMETHOD(etherswitch_setvgroup, ip17x_setvgroup), 601250386Sadrian DEVMETHOD(etherswitch_getconf, ip17x_getconf), 602250386Sadrian DEVMETHOD(etherswitch_setconf, ip17x_setconf), 603250386Sadrian 604250386Sadrian DEVMETHOD_END 605250386Sadrian}; 606250386Sadrian 607250386SadrianDEFINE_CLASS_0(ip17x, ip17x_driver, ip17x_methods, 608250386Sadrian sizeof(struct ip17x_softc)); 609250386Sadrianstatic devclass_t ip17x_devclass; 610250386Sadrian 611250386SadrianDRIVER_MODULE(ip17x, mdio, ip17x_driver, ip17x_devclass, 0, 0); 612250386SadrianDRIVER_MODULE(miibus, ip17x, miibus_driver, miibus_devclass, 0, 0); 613250386SadrianDRIVER_MODULE(mdio, ip17x, mdio_driver, mdio_devclass, 0, 0); 614250386SadrianDRIVER_MODULE(etherswitch, ip17x, etherswitch_driver, etherswitch_devclass, 0, 0); 615250386SadrianMODULE_VERSION(ip17x, 1); 616250386SadrianMODULE_DEPEND(ip17x, miibus, 1, 1, 1); /* XXX which versions? */ 617250386SadrianMODULE_DEPEND(ip17x, etherswitch, 1, 1, 1); /* XXX which versions? */ 618