1210311Sjmallett/*- 2210311Sjmallett * Copyright (c) 2010 Juli Mallett <jmallett@FreeBSD.org> 3210311Sjmallett * All rights reserved. 4210311Sjmallett * 5210311Sjmallett * Redistribution and use in source and binary forms, with or without 6210311Sjmallett * modification, are permitted provided that the following conditions 7210311Sjmallett * are met: 8210311Sjmallett * 1. Redistributions of source code must retain the above copyright 9210311Sjmallett * notice, this list of conditions and the following disclaimer. 10210311Sjmallett * 2. Redistributions in binary form must reproduce the above copyright 11210311Sjmallett * notice, this list of conditions and the following disclaimer in the 12210311Sjmallett * documentation and/or other materials provided with the distribution. 13210311Sjmallett * 14210311Sjmallett * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15210311Sjmallett * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16210311Sjmallett * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17210311Sjmallett * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18210311Sjmallett * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19210311Sjmallett * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20210311Sjmallett * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21210311Sjmallett * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22210311Sjmallett * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23210311Sjmallett * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24210311Sjmallett * SUCH DAMAGE. 25210311Sjmallett * 26210311Sjmallett * $FreeBSD$ 27210311Sjmallett */ 28210311Sjmallett 29210311Sjmallett/* 30210311Sjmallett * Cavium Octeon Ethernet devices. 31210311Sjmallett * 32210311Sjmallett * XXX This file should be moved to if_octe.c 33210311Sjmallett * XXX The driver may have sufficient locking but we need locking to protect 34210311Sjmallett * the interfaces presented here, right? 35210311Sjmallett */ 36210311Sjmallett 37210311Sjmallett#include "opt_inet.h" 38210311Sjmallett 39210311Sjmallett#include <sys/param.h> 40210311Sjmallett#include <sys/systm.h> 41210311Sjmallett#include <sys/bus.h> 42210311Sjmallett#include <sys/endian.h> 43210311Sjmallett#include <sys/kernel.h> 44210311Sjmallett#include <sys/mbuf.h> 45210311Sjmallett#include <sys/lock.h> 46210311Sjmallett#include <sys/module.h> 47210311Sjmallett#include <sys/mutex.h> 48210311Sjmallett#include <sys/rman.h> 49210311Sjmallett#include <sys/socket.h> 50210311Sjmallett#include <sys/sockio.h> 51210311Sjmallett#include <sys/sysctl.h> 52210311Sjmallett 53210311Sjmallett#include <net/bpf.h> 54210311Sjmallett#include <net/ethernet.h> 55210311Sjmallett#include <net/if.h> 56210311Sjmallett#include <net/if_dl.h> 57210311Sjmallett#include <net/if_media.h> 58210311Sjmallett#include <net/if_types.h> 59210311Sjmallett#include <net/if_var.h> 60210311Sjmallett#include <net/if_vlan_var.h> 61210311Sjmallett 62210311Sjmallett#ifdef INET 63210311Sjmallett#include <netinet/in.h> 64210311Sjmallett#include <netinet/if_ether.h> 65210311Sjmallett#endif 66210311Sjmallett 67210311Sjmallett#include <dev/mii/mii.h> 68210311Sjmallett#include <dev/mii/miivar.h> 69210311Sjmallett 70210311Sjmallett#include "wrapper-cvmx-includes.h" 71210311Sjmallett#include "cavium-ethernet.h" 72210311Sjmallett 73210311Sjmallett#include "ethernet-common.h" 74210311Sjmallett#include "ethernet-defines.h" 75210311Sjmallett#include "ethernet-mdio.h" 76210311Sjmallett#include "ethernet-tx.h" 77210311Sjmallett 78210311Sjmallett#include "miibus_if.h" 79210311Sjmallett 80210311Sjmallett#define OCTE_TX_LOCK(priv) mtx_lock(&(priv)->tx_mtx) 81210311Sjmallett#define OCTE_TX_UNLOCK(priv) mtx_unlock(&(priv)->tx_mtx) 82210311Sjmallett 83210311Sjmallettstatic int octe_probe(device_t); 84210311Sjmallettstatic int octe_attach(device_t); 85210311Sjmallettstatic int octe_detach(device_t); 86210311Sjmallettstatic int octe_shutdown(device_t); 87210311Sjmallett 88210311Sjmallettstatic int octe_miibus_readreg(device_t, int, int); 89210311Sjmallettstatic int octe_miibus_writereg(device_t, int, int, int); 90210311Sjmallett 91210311Sjmallettstatic void octe_init(void *); 92210311Sjmallettstatic void octe_stop(void *); 93215957Sjmallettstatic int octe_transmit(struct ifnet *, struct mbuf *); 94210311Sjmallett 95210311Sjmallettstatic int octe_mii_medchange(struct ifnet *); 96210311Sjmallettstatic void octe_mii_medstat(struct ifnet *, struct ifmediareq *); 97210311Sjmallett 98210311Sjmallettstatic int octe_medchange(struct ifnet *); 99210311Sjmallettstatic void octe_medstat(struct ifnet *, struct ifmediareq *); 100210311Sjmallett 101210311Sjmallettstatic int octe_ioctl(struct ifnet *, u_long, caddr_t); 102210311Sjmallett 103210311Sjmallettstatic device_method_t octe_methods[] = { 104210311Sjmallett /* Device interface */ 105210311Sjmallett DEVMETHOD(device_probe, octe_probe), 106210311Sjmallett DEVMETHOD(device_attach, octe_attach), 107210311Sjmallett DEVMETHOD(device_detach, octe_detach), 108210311Sjmallett DEVMETHOD(device_shutdown, octe_shutdown), 109210311Sjmallett 110210311Sjmallett /* MII interface */ 111210311Sjmallett DEVMETHOD(miibus_readreg, octe_miibus_readreg), 112210311Sjmallett DEVMETHOD(miibus_writereg, octe_miibus_writereg), 113210311Sjmallett 114210311Sjmallett { 0, 0 } 115210311Sjmallett}; 116210311Sjmallett 117210311Sjmallettstatic driver_t octe_driver = { 118210311Sjmallett "octe", 119210311Sjmallett octe_methods, 120210311Sjmallett sizeof (cvm_oct_private_t), 121210311Sjmallett}; 122210311Sjmallett 123210311Sjmallettstatic devclass_t octe_devclass; 124210311Sjmallett 125210311SjmallettDRIVER_MODULE(octe, octebus, octe_driver, octe_devclass, 0, 0); 126210311SjmallettDRIVER_MODULE(miibus, octe, miibus_driver, miibus_devclass, 0, 0); 127210311Sjmallett 128210311Sjmallettstatic int 129210311Sjmallettocte_probe(device_t dev) 130210311Sjmallett{ 131210311Sjmallett return (0); 132210311Sjmallett} 133210311Sjmallett 134210311Sjmallettstatic int 135210311Sjmallettocte_attach(device_t dev) 136210311Sjmallett{ 137210311Sjmallett struct ifnet *ifp; 138210311Sjmallett cvm_oct_private_t *priv; 139213762Sjmallett device_t child; 140210311Sjmallett unsigned qos; 141210311Sjmallett int error; 142210311Sjmallett 143210311Sjmallett priv = device_get_softc(dev); 144210311Sjmallett ifp = priv->ifp; 145210311Sjmallett 146210311Sjmallett if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 147210311Sjmallett 148210311Sjmallett if (priv->phy_id != -1) { 149213762Sjmallett if (priv->phy_device == NULL) { 150213893Smarius error = mii_attach(dev, &priv->miibus, ifp, 151213893Smarius octe_mii_medchange, octe_mii_medstat, 152213893Smarius BMSR_DEFCAPMASK, priv->phy_id, MII_OFFSET_ANY, 0); 153213762Sjmallett if (error != 0) 154213893Smarius device_printf(dev, "attaching PHYs failed\n"); 155213762Sjmallett } else { 156213762Sjmallett child = device_add_child(dev, priv->phy_device, -1); 157213762Sjmallett if (child == NULL) 158213762Sjmallett device_printf(dev, "missing phy %u device %s\n", priv->phy_id, priv->phy_device); 159210311Sjmallett } 160210311Sjmallett } 161210311Sjmallett 162210311Sjmallett if (priv->miibus == NULL) { 163210311Sjmallett ifmedia_init(&priv->media, 0, octe_medchange, octe_medstat); 164210311Sjmallett 165210311Sjmallett ifmedia_add(&priv->media, IFM_ETHER | IFM_AUTO, 0, NULL); 166210311Sjmallett ifmedia_set(&priv->media, IFM_ETHER | IFM_AUTO); 167210311Sjmallett } 168210311Sjmallett 169210311Sjmallett /* 170210311Sjmallett * XXX 171210311Sjmallett * We don't support programming the multicast filter right now, although it 172210311Sjmallett * ought to be easy enough. (Presumably it's just a matter of putting 173210311Sjmallett * multicast addresses in the CAM?) 174210311Sjmallett */ 175210311Sjmallett ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_ALLMULTI; 176210311Sjmallett ifp->if_init = octe_init; 177210311Sjmallett ifp->if_ioctl = octe_ioctl; 178210311Sjmallett 179210311Sjmallett priv->if_flags = ifp->if_flags; 180210311Sjmallett 181210311Sjmallett mtx_init(&priv->tx_mtx, ifp->if_xname, "octe tx send queue", MTX_DEF); 182210311Sjmallett 183210311Sjmallett for (qos = 0; qos < 16; qos++) { 184210311Sjmallett mtx_init(&priv->tx_free_queue[qos].ifq_mtx, ifp->if_xname, "octe tx free queue", MTX_DEF); 185210311Sjmallett IFQ_SET_MAXLEN(&priv->tx_free_queue[qos], MAX_OUT_QUEUE_DEPTH); 186210311Sjmallett } 187210311Sjmallett 188210311Sjmallett ether_ifattach(ifp, priv->mac); 189210311Sjmallett 190215957Sjmallett ifp->if_transmit = octe_transmit; 191215957Sjmallett 192210311Sjmallett ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 193210311Sjmallett ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_HWCSUM; 194210311Sjmallett ifp->if_capenable = ifp->if_capabilities; 195210311Sjmallett ifp->if_hwassist = CSUM_TCP | CSUM_UDP; 196210311Sjmallett 197210311Sjmallett OCTE_TX_LOCK(priv); 198210311Sjmallett IFQ_SET_MAXLEN(&ifp->if_snd, MAX_OUT_QUEUE_DEPTH); 199210311Sjmallett ifp->if_snd.ifq_drv_maxlen = MAX_OUT_QUEUE_DEPTH; 200210311Sjmallett IFQ_SET_READY(&ifp->if_snd); 201210311Sjmallett OCTE_TX_UNLOCK(priv); 202210311Sjmallett 203213762Sjmallett return (bus_generic_attach(dev)); 204210311Sjmallett} 205210311Sjmallett 206210311Sjmallettstatic int 207210311Sjmallettocte_detach(device_t dev) 208210311Sjmallett{ 209210311Sjmallett return (0); 210210311Sjmallett} 211210311Sjmallett 212210311Sjmallettstatic int 213210311Sjmallettocte_shutdown(device_t dev) 214210311Sjmallett{ 215210311Sjmallett return (octe_detach(dev)); 216210311Sjmallett} 217210311Sjmallett 218210311Sjmallettstatic int 219210311Sjmallettocte_miibus_readreg(device_t dev, int phy, int reg) 220210311Sjmallett{ 221210311Sjmallett cvm_oct_private_t *priv; 222210311Sjmallett 223210311Sjmallett priv = device_get_softc(dev); 224210311Sjmallett 225213346Sjmallett /* 226213346Sjmallett * Try interface-specific MII routine. 227213346Sjmallett */ 228213346Sjmallett if (priv->mdio_read != NULL) 229213346Sjmallett return (priv->mdio_read(priv->ifp, phy, reg)); 230213346Sjmallett 231213346Sjmallett /* 232213346Sjmallett * Try generic MII routine. 233213346Sjmallett */ 234213893Smarius KASSERT(phy == priv->phy_id, 235213893Smarius ("read from phy %u but our phy is %u", phy, priv->phy_id)); 236210311Sjmallett return (cvm_oct_mdio_read(priv->ifp, phy, reg)); 237210311Sjmallett} 238210311Sjmallett 239210311Sjmallettstatic int 240210311Sjmallettocte_miibus_writereg(device_t dev, int phy, int reg, int val) 241210311Sjmallett{ 242210311Sjmallett cvm_oct_private_t *priv; 243210311Sjmallett 244210311Sjmallett priv = device_get_softc(dev); 245210311Sjmallett 246213346Sjmallett /* 247213346Sjmallett * Try interface-specific MII routine. 248213346Sjmallett */ 249213346Sjmallett if (priv->mdio_write != NULL) { 250213346Sjmallett priv->mdio_write(priv->ifp, phy, reg, val); 251213346Sjmallett return (0); 252213346Sjmallett } 253213346Sjmallett 254213346Sjmallett /* 255213346Sjmallett * Try generic MII routine. 256213346Sjmallett */ 257210311Sjmallett KASSERT(phy == priv->phy_id, 258210311Sjmallett ("write to phy %u but our phy is %u", phy, priv->phy_id)); 259210311Sjmallett cvm_oct_mdio_write(priv->ifp, phy, reg, val); 260210311Sjmallett 261210311Sjmallett return (0); 262210311Sjmallett} 263210311Sjmallett 264210311Sjmallettstatic void 265210311Sjmallettocte_init(void *arg) 266210311Sjmallett{ 267210311Sjmallett struct ifnet *ifp; 268210311Sjmallett cvm_oct_private_t *priv; 269210311Sjmallett 270210311Sjmallett priv = arg; 271210311Sjmallett ifp = priv->ifp; 272210311Sjmallett 273210311Sjmallett if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 274210311Sjmallett octe_stop(priv); 275210311Sjmallett 276210311Sjmallett if (priv->open != NULL) 277210311Sjmallett priv->open(ifp); 278210311Sjmallett 279210311Sjmallett if (((ifp->if_flags ^ priv->if_flags) & (IFF_ALLMULTI | IFF_MULTICAST | IFF_PROMISC)) != 0) 280210311Sjmallett cvm_oct_common_set_multicast_list(ifp); 281210311Sjmallett 282210311Sjmallett cvm_oct_common_set_mac_address(ifp, IF_LLADDR(ifp)); 283210311Sjmallett 284216071Sjmallett cvm_oct_common_poll(ifp); 285216071Sjmallett 286210311Sjmallett if (priv->miibus != NULL) 287210311Sjmallett mii_mediachg(device_get_softc(priv->miibus)); 288210311Sjmallett 289210311Sjmallett ifp->if_drv_flags |= IFF_DRV_RUNNING; 290210311Sjmallett ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 291210311Sjmallett} 292210311Sjmallett 293210311Sjmallettstatic void 294210311Sjmallettocte_stop(void *arg) 295210311Sjmallett{ 296210311Sjmallett struct ifnet *ifp; 297210311Sjmallett cvm_oct_private_t *priv; 298210311Sjmallett 299210311Sjmallett priv = arg; 300210311Sjmallett ifp = priv->ifp; 301210311Sjmallett 302210311Sjmallett if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 303210311Sjmallett return; 304210311Sjmallett 305210311Sjmallett if (priv->stop != NULL) 306210311Sjmallett priv->stop(ifp); 307210311Sjmallett 308210311Sjmallett ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 309210311Sjmallett} 310210311Sjmallett 311215957Sjmallettstatic int 312215957Sjmallettocte_transmit(struct ifnet *ifp, struct mbuf *m) 313210311Sjmallett{ 314210311Sjmallett cvm_oct_private_t *priv; 315210311Sjmallett 316210311Sjmallett priv = ifp->if_softc; 317210311Sjmallett 318215957Sjmallett if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 319215957Sjmallett IFF_DRV_RUNNING) { 320215957Sjmallett m_freem(m); 321215957Sjmallett return (0); 322215957Sjmallett } 323210311Sjmallett 324215959Sjmallett return (cvm_oct_xmit(m, ifp)); 325210311Sjmallett} 326210311Sjmallett 327210311Sjmallettstatic int 328210311Sjmallettocte_mii_medchange(struct ifnet *ifp) 329210311Sjmallett{ 330210311Sjmallett cvm_oct_private_t *priv; 331210311Sjmallett struct mii_data *mii; 332221407Smarius struct mii_softc *miisc; 333210311Sjmallett 334210311Sjmallett priv = ifp->if_softc; 335210311Sjmallett mii = device_get_softc(priv->miibus); 336221407Smarius LIST_FOREACH(miisc, &mii->mii_phys, mii_list) 337221407Smarius PHY_RESET(miisc); 338210311Sjmallett mii_mediachg(mii); 339210311Sjmallett 340210311Sjmallett return (0); 341210311Sjmallett} 342210311Sjmallett 343210311Sjmallettstatic void 344210311Sjmallettocte_mii_medstat(struct ifnet *ifp, struct ifmediareq *ifm) 345210311Sjmallett{ 346210311Sjmallett cvm_oct_private_t *priv; 347210311Sjmallett struct mii_data *mii; 348210311Sjmallett 349210311Sjmallett priv = ifp->if_softc; 350210311Sjmallett mii = device_get_softc(priv->miibus); 351210311Sjmallett 352210311Sjmallett mii_pollstat(mii); 353210311Sjmallett ifm->ifm_active = mii->mii_media_active; 354210311Sjmallett ifm->ifm_status = mii->mii_media_status; 355210311Sjmallett} 356210311Sjmallett 357210311Sjmallettstatic int 358210311Sjmallettocte_medchange(struct ifnet *ifp) 359210311Sjmallett{ 360210311Sjmallett return (ENOTSUP); 361210311Sjmallett} 362210311Sjmallett 363210311Sjmallettstatic void 364210311Sjmallettocte_medstat(struct ifnet *ifp, struct ifmediareq *ifm) 365210311Sjmallett{ 366210311Sjmallett cvm_oct_private_t *priv; 367210311Sjmallett cvmx_helper_link_info_t link_info; 368210311Sjmallett 369210311Sjmallett priv = ifp->if_softc; 370210311Sjmallett 371210311Sjmallett ifm->ifm_status = IFM_AVALID; 372210311Sjmallett ifm->ifm_active = IFT_ETHER; 373210311Sjmallett 374210311Sjmallett if (priv->poll == NULL) 375210311Sjmallett return; 376210311Sjmallett priv->poll(ifp); 377210311Sjmallett 378210311Sjmallett link_info.u64 = priv->link_info; 379210311Sjmallett 380210311Sjmallett if (!link_info.s.link_up) 381210311Sjmallett return; 382210311Sjmallett 383210311Sjmallett ifm->ifm_status |= IFM_ACTIVE; 384210311Sjmallett 385210311Sjmallett switch (link_info.s.speed) { 386210311Sjmallett case 10: 387210311Sjmallett ifm->ifm_active |= IFM_10_T; 388210311Sjmallett break; 389210311Sjmallett case 100: 390210311Sjmallett ifm->ifm_active |= IFM_100_TX; 391210311Sjmallett break; 392210311Sjmallett case 1000: 393210311Sjmallett ifm->ifm_active |= IFM_1000_T; 394210311Sjmallett break; 395210311Sjmallett case 10000: 396210311Sjmallett ifm->ifm_active |= IFM_10G_T; 397210311Sjmallett break; 398210311Sjmallett } 399210311Sjmallett 400210311Sjmallett if (link_info.s.full_duplex) 401210311Sjmallett ifm->ifm_active |= IFM_FDX; 402210311Sjmallett else 403210311Sjmallett ifm->ifm_active |= IFM_HDX; 404210311Sjmallett} 405210311Sjmallett 406210311Sjmallettstatic int 407210311Sjmallettocte_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 408210311Sjmallett{ 409210311Sjmallett cvm_oct_private_t *priv; 410210311Sjmallett struct mii_data *mii; 411210311Sjmallett struct ifreq *ifr; 412210311Sjmallett#ifdef INET 413210311Sjmallett struct ifaddr *ifa; 414210311Sjmallett#endif 415210311Sjmallett int error; 416210311Sjmallett 417210311Sjmallett priv = ifp->if_softc; 418210311Sjmallett ifr = (struct ifreq *)data; 419210311Sjmallett#ifdef INET 420210311Sjmallett ifa = (struct ifaddr *)data; 421210311Sjmallett#endif 422210311Sjmallett 423210311Sjmallett switch (cmd) { 424210311Sjmallett case SIOCSIFADDR: 425210311Sjmallett#ifdef INET 426210311Sjmallett /* 427210311Sjmallett * Avoid reinitialization unless it's necessary. 428210311Sjmallett */ 429210311Sjmallett if (ifa->ifa_addr->sa_family == AF_INET) { 430210311Sjmallett ifp->if_flags |= IFF_UP; 431210311Sjmallett if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 432210311Sjmallett octe_init(priv); 433210311Sjmallett arp_ifinit(ifp, ifa); 434210311Sjmallett 435210311Sjmallett return (0); 436210311Sjmallett } 437210311Sjmallett#endif 438210311Sjmallett error = ether_ioctl(ifp, cmd, data); 439210311Sjmallett if (error != 0) 440210311Sjmallett return (error); 441210311Sjmallett return (0); 442210311Sjmallett 443210311Sjmallett case SIOCSIFFLAGS: 444210311Sjmallett if (ifp->if_flags == priv->if_flags) 445210311Sjmallett return (0); 446210311Sjmallett if ((ifp->if_flags & IFF_UP) != 0) { 447210311Sjmallett if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 448210311Sjmallett octe_init(priv); 449210311Sjmallett } else { 450210311Sjmallett if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) 451210311Sjmallett octe_stop(priv); 452210311Sjmallett } 453210311Sjmallett priv->if_flags = ifp->if_flags; 454210311Sjmallett return (0); 455210311Sjmallett 456210311Sjmallett case SIOCSIFCAP: 457210311Sjmallett /* 458210311Sjmallett * Just change the capabilities in software, currently none 459210311Sjmallett * require reprogramming hardware, they just toggle whether we 460210311Sjmallett * make use of already-present facilities in software. 461210311Sjmallett */ 462210311Sjmallett ifp->if_capenable = ifr->ifr_reqcap; 463210311Sjmallett return (0); 464210311Sjmallett 465210311Sjmallett case SIOCSIFMTU: 466210311Sjmallett error = cvm_oct_common_change_mtu(ifp, ifr->ifr_mtu); 467210311Sjmallett if (error != 0) 468210311Sjmallett return (EINVAL); 469210311Sjmallett return (0); 470210311Sjmallett 471210311Sjmallett case SIOCSIFMEDIA: 472210311Sjmallett case SIOCGIFMEDIA: 473210311Sjmallett if (priv->miibus != NULL) { 474210311Sjmallett mii = device_get_softc(priv->miibus); 475210311Sjmallett error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); 476210311Sjmallett if (error != 0) 477210311Sjmallett return (error); 478210311Sjmallett return (0); 479210311Sjmallett } 480210311Sjmallett error = ifmedia_ioctl(ifp, ifr, &priv->media, cmd); 481210311Sjmallett if (error != 0) 482210311Sjmallett return (error); 483210311Sjmallett return (0); 484210311Sjmallett 485210311Sjmallett default: 486210311Sjmallett error = ether_ioctl(ifp, cmd, data); 487210311Sjmallett if (error != 0) 488210311Sjmallett return (error); 489210311Sjmallett return (0); 490210311Sjmallett } 491210311Sjmallett} 492