1*4574da7fSAdrian Chadd /*- 2*4574da7fSAdrian Chadd * Copyright (c) 2011-2012 Stefan Bethke. 3*4574da7fSAdrian Chadd * All rights reserved. 4*4574da7fSAdrian Chadd * 5*4574da7fSAdrian Chadd * Redistribution and use in source and binary forms, with or without 6*4574da7fSAdrian Chadd * modification, are permitted provided that the following conditions 7*4574da7fSAdrian Chadd * are met: 8*4574da7fSAdrian Chadd * 1. Redistributions of source code must retain the above copyright 9*4574da7fSAdrian Chadd * notice, this list of conditions and the following disclaimer. 10*4574da7fSAdrian Chadd * 2. Redistributions in binary form must reproduce the above copyright 11*4574da7fSAdrian Chadd * notice, this list of conditions and the following disclaimer in the 12*4574da7fSAdrian Chadd * documentation and/or other materials provided with the distribution. 13*4574da7fSAdrian Chadd * 14*4574da7fSAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*4574da7fSAdrian Chadd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*4574da7fSAdrian Chadd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*4574da7fSAdrian Chadd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*4574da7fSAdrian Chadd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*4574da7fSAdrian Chadd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*4574da7fSAdrian Chadd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*4574da7fSAdrian Chadd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*4574da7fSAdrian Chadd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*4574da7fSAdrian Chadd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*4574da7fSAdrian Chadd * SUCH DAMAGE. 25*4574da7fSAdrian Chadd * 26*4574da7fSAdrian Chadd * $FreeBSD$ 27*4574da7fSAdrian Chadd */ 28*4574da7fSAdrian Chadd 29*4574da7fSAdrian Chadd #include <sys/param.h> 30*4574da7fSAdrian Chadd #include <sys/bus.h> 31*4574da7fSAdrian Chadd #include <sys/kernel.h> 32*4574da7fSAdrian Chadd #include <sys/module.h> 33*4574da7fSAdrian Chadd #include <sys/socket.h> 34*4574da7fSAdrian Chadd #include <sys/sockio.h> 35*4574da7fSAdrian Chadd #include <sys/systm.h> 36*4574da7fSAdrian Chadd 37*4574da7fSAdrian Chadd #include <net/if.h> 38*4574da7fSAdrian Chadd #include <net/if_arp.h> 39*4574da7fSAdrian Chadd #include <net/ethernet.h> 40*4574da7fSAdrian Chadd #include <net/if_dl.h> 41*4574da7fSAdrian Chadd #include <net/if_media.h> 42*4574da7fSAdrian Chadd #include <net/if_types.h> 43*4574da7fSAdrian Chadd 44*4574da7fSAdrian Chadd #include <dev/etherswitch/miiproxy.h> 45*4574da7fSAdrian Chadd #include <dev/mii/mii.h> 46*4574da7fSAdrian Chadd #include <dev/mii/miivar.h> 47*4574da7fSAdrian Chadd 48*4574da7fSAdrian Chadd #include "mdio_if.h" 49*4574da7fSAdrian Chadd #include "miibus_if.h" 50*4574da7fSAdrian Chadd 51*4574da7fSAdrian Chadd 52*4574da7fSAdrian Chadd MALLOC_DECLARE(M_MIIPROXY); 53*4574da7fSAdrian Chadd MALLOC_DEFINE(M_MIIPROXY, "miiproxy", "miiproxy data structures"); 54*4574da7fSAdrian Chadd 55*4574da7fSAdrian Chadd driver_t miiproxy_driver; 56*4574da7fSAdrian Chadd driver_t mdioproxy_driver; 57*4574da7fSAdrian Chadd 58*4574da7fSAdrian Chadd struct miiproxy_softc { 59*4574da7fSAdrian Chadd device_t parent; 60*4574da7fSAdrian Chadd device_t proxy; 61*4574da7fSAdrian Chadd device_t mdio; 62*4574da7fSAdrian Chadd }; 63*4574da7fSAdrian Chadd 64*4574da7fSAdrian Chadd struct mdioproxy_softc { 65*4574da7fSAdrian Chadd }; 66*4574da7fSAdrian Chadd 67*4574da7fSAdrian Chadd /* 68*4574da7fSAdrian Chadd * The rendevous data structures and functions allow two device endpoints to 69*4574da7fSAdrian Chadd * match up, so that the proxy endpoint can be associated with a target 70*4574da7fSAdrian Chadd * endpoint. The proxy has to know the device name of the target that it 71*4574da7fSAdrian Chadd * wants to associate with, for example through a hint. The rendevous code 72*4574da7fSAdrian Chadd * makes no assumptions about the devices that want to meet. 73*4574da7fSAdrian Chadd */ 74*4574da7fSAdrian Chadd struct rendevous_entry; 75*4574da7fSAdrian Chadd 76*4574da7fSAdrian Chadd enum rendevous_op { 77*4574da7fSAdrian Chadd RENDEVOUS_ATTACH, 78*4574da7fSAdrian Chadd RENDEVOUS_DETACH 79*4574da7fSAdrian Chadd }; 80*4574da7fSAdrian Chadd 81*4574da7fSAdrian Chadd typedef int (*rendevous_callback_t)(enum rendevous_op, 82*4574da7fSAdrian Chadd struct rendevous_entry *); 83*4574da7fSAdrian Chadd 84*4574da7fSAdrian Chadd static SLIST_HEAD(rendevoushead, rendevous_entry) rendevoushead = 85*4574da7fSAdrian Chadd SLIST_HEAD_INITIALIZER(rendevoushead); 86*4574da7fSAdrian Chadd 87*4574da7fSAdrian Chadd struct rendevous_endpoint { 88*4574da7fSAdrian Chadd device_t device; 89*4574da7fSAdrian Chadd const char *name; 90*4574da7fSAdrian Chadd rendevous_callback_t callback; 91*4574da7fSAdrian Chadd }; 92*4574da7fSAdrian Chadd 93*4574da7fSAdrian Chadd struct rendevous_entry { 94*4574da7fSAdrian Chadd SLIST_ENTRY(rendevous_entry) entries; 95*4574da7fSAdrian Chadd struct rendevous_endpoint proxy; 96*4574da7fSAdrian Chadd struct rendevous_endpoint target; 97*4574da7fSAdrian Chadd }; 98*4574da7fSAdrian Chadd 99*4574da7fSAdrian Chadd /* 100*4574da7fSAdrian Chadd * Call the callback routines for both the proxy and the target. If either 101*4574da7fSAdrian Chadd * returns an error, undo the attachment. 102*4574da7fSAdrian Chadd */ 103*4574da7fSAdrian Chadd static int 104*4574da7fSAdrian Chadd rendevous_attach(struct rendevous_entry *e, struct rendevous_endpoint *ep) 105*4574da7fSAdrian Chadd { 106*4574da7fSAdrian Chadd int error; 107*4574da7fSAdrian Chadd 108*4574da7fSAdrian Chadd error = e->proxy.callback(RENDEVOUS_ATTACH, e); 109*4574da7fSAdrian Chadd if (error == 0) { 110*4574da7fSAdrian Chadd error = e->target.callback(RENDEVOUS_ATTACH, e); 111*4574da7fSAdrian Chadd if (error != 0) { 112*4574da7fSAdrian Chadd e->proxy.callback(RENDEVOUS_DETACH, e); 113*4574da7fSAdrian Chadd ep->device = NULL; 114*4574da7fSAdrian Chadd ep->callback = NULL; 115*4574da7fSAdrian Chadd } 116*4574da7fSAdrian Chadd } 117*4574da7fSAdrian Chadd return (error); 118*4574da7fSAdrian Chadd } 119*4574da7fSAdrian Chadd 120*4574da7fSAdrian Chadd /* 121*4574da7fSAdrian Chadd * Create an entry for the proxy in the rendevous list. The name parameter 122*4574da7fSAdrian Chadd * indicates the name of the device that is the target endpoint for this 123*4574da7fSAdrian Chadd * rendevous. The callback will be invoked as soon as the target is 124*4574da7fSAdrian Chadd * registered: either immediately if the target registered itself earlier, 125*4574da7fSAdrian Chadd * or once the target registers. Returns ENXIO if the target has not yet 126*4574da7fSAdrian Chadd * registered. 127*4574da7fSAdrian Chadd */ 128*4574da7fSAdrian Chadd static int 129*4574da7fSAdrian Chadd rendevous_register_proxy(device_t dev, const char *name, 130*4574da7fSAdrian Chadd rendevous_callback_t callback) 131*4574da7fSAdrian Chadd { 132*4574da7fSAdrian Chadd struct rendevous_entry *e; 133*4574da7fSAdrian Chadd 134*4574da7fSAdrian Chadd KASSERT(callback != NULL, ("callback must be set")); 135*4574da7fSAdrian Chadd SLIST_FOREACH(e, &rendevoushead, entries) { 136*4574da7fSAdrian Chadd if (strcmp(name, e->target.name) == 0) { 137*4574da7fSAdrian Chadd /* the target is already attached */ 138*4574da7fSAdrian Chadd e->proxy.name = device_get_nameunit(dev); 139*4574da7fSAdrian Chadd e->proxy.device = dev; 140*4574da7fSAdrian Chadd e->proxy.callback = callback; 141*4574da7fSAdrian Chadd return (rendevous_attach(e, &e->proxy)); 142*4574da7fSAdrian Chadd } 143*4574da7fSAdrian Chadd } 144*4574da7fSAdrian Chadd e = malloc(sizeof(*e), M_MIIPROXY, M_WAITOK | M_ZERO); 145*4574da7fSAdrian Chadd e->proxy.name = device_get_nameunit(dev); 146*4574da7fSAdrian Chadd e->proxy.device = dev; 147*4574da7fSAdrian Chadd e->proxy.callback = callback; 148*4574da7fSAdrian Chadd e->target.name = name; 149*4574da7fSAdrian Chadd SLIST_INSERT_HEAD(&rendevoushead, e, entries); 150*4574da7fSAdrian Chadd return (ENXIO); 151*4574da7fSAdrian Chadd } 152*4574da7fSAdrian Chadd 153*4574da7fSAdrian Chadd /* 154*4574da7fSAdrian Chadd * Create an entry in the rendevous list for the target. 155*4574da7fSAdrian Chadd * Returns ENXIO if the proxy has not yet registered. 156*4574da7fSAdrian Chadd */ 157*4574da7fSAdrian Chadd static int 158*4574da7fSAdrian Chadd rendevous_register_target(device_t dev, rendevous_callback_t callback) 159*4574da7fSAdrian Chadd { 160*4574da7fSAdrian Chadd struct rendevous_entry *e; 161*4574da7fSAdrian Chadd const char *name; 162*4574da7fSAdrian Chadd 163*4574da7fSAdrian Chadd KASSERT(callback != NULL, ("callback must be set")); 164*4574da7fSAdrian Chadd name = device_get_nameunit(dev); 165*4574da7fSAdrian Chadd SLIST_FOREACH(e, &rendevoushead, entries) { 166*4574da7fSAdrian Chadd if (strcmp(name, e->target.name) == 0) { 167*4574da7fSAdrian Chadd e->target.device = dev; 168*4574da7fSAdrian Chadd e->target.callback = callback; 169*4574da7fSAdrian Chadd return (rendevous_attach(e, &e->target)); 170*4574da7fSAdrian Chadd } 171*4574da7fSAdrian Chadd } 172*4574da7fSAdrian Chadd e = malloc(sizeof(*e), M_MIIPROXY, M_WAITOK | M_ZERO); 173*4574da7fSAdrian Chadd e->target.name = name; 174*4574da7fSAdrian Chadd e->target.device = dev; 175*4574da7fSAdrian Chadd e->target.callback = callback; 176*4574da7fSAdrian Chadd SLIST_INSERT_HEAD(&rendevoushead, e, entries); 177*4574da7fSAdrian Chadd return (ENXIO); 178*4574da7fSAdrian Chadd } 179*4574da7fSAdrian Chadd 180*4574da7fSAdrian Chadd /* 181*4574da7fSAdrian Chadd * Remove the registration for the proxy. 182*4574da7fSAdrian Chadd */ 183*4574da7fSAdrian Chadd static int 184*4574da7fSAdrian Chadd rendevous_unregister_proxy(device_t dev) 185*4574da7fSAdrian Chadd { 186*4574da7fSAdrian Chadd struct rendevous_entry *e; 187*4574da7fSAdrian Chadd int error = 0; 188*4574da7fSAdrian Chadd 189*4574da7fSAdrian Chadd SLIST_FOREACH(e, &rendevoushead, entries) { 190*4574da7fSAdrian Chadd if (e->proxy.device == dev) { 191*4574da7fSAdrian Chadd if (e->target.device == NULL) { 192*4574da7fSAdrian Chadd SLIST_REMOVE(&rendevoushead, e, rendevous_entry, entries); 193*4574da7fSAdrian Chadd free(e, M_MIIPROXY); 194*4574da7fSAdrian Chadd return (0); 195*4574da7fSAdrian Chadd } else { 196*4574da7fSAdrian Chadd e->proxy.callback(RENDEVOUS_DETACH, e); 197*4574da7fSAdrian Chadd e->target.callback(RENDEVOUS_DETACH, e); 198*4574da7fSAdrian Chadd } 199*4574da7fSAdrian Chadd e->proxy.device = NULL; 200*4574da7fSAdrian Chadd e->proxy.callback = NULL; 201*4574da7fSAdrian Chadd return (error); 202*4574da7fSAdrian Chadd } 203*4574da7fSAdrian Chadd } 204*4574da7fSAdrian Chadd return (ENOENT); 205*4574da7fSAdrian Chadd } 206*4574da7fSAdrian Chadd 207*4574da7fSAdrian Chadd /* 208*4574da7fSAdrian Chadd * Remove the registration for the target. 209*4574da7fSAdrian Chadd */ 210*4574da7fSAdrian Chadd static int 211*4574da7fSAdrian Chadd rendevous_unregister_target(device_t dev) 212*4574da7fSAdrian Chadd { 213*4574da7fSAdrian Chadd struct rendevous_entry *e; 214*4574da7fSAdrian Chadd int error = 0; 215*4574da7fSAdrian Chadd 216*4574da7fSAdrian Chadd SLIST_FOREACH(e, &rendevoushead, entries) { 217*4574da7fSAdrian Chadd if (e->target.device == dev) { 218*4574da7fSAdrian Chadd if (e->proxy.device == NULL) { 219*4574da7fSAdrian Chadd SLIST_REMOVE(&rendevoushead, e, rendevous_entry, entries); 220*4574da7fSAdrian Chadd free(e, M_MIIPROXY); 221*4574da7fSAdrian Chadd return (0); 222*4574da7fSAdrian Chadd } else { 223*4574da7fSAdrian Chadd e->proxy.callback(RENDEVOUS_DETACH, e); 224*4574da7fSAdrian Chadd e->target.callback(RENDEVOUS_DETACH, e); 225*4574da7fSAdrian Chadd } 226*4574da7fSAdrian Chadd e->target.device = NULL; 227*4574da7fSAdrian Chadd e->target.callback = NULL; 228*4574da7fSAdrian Chadd return (error); 229*4574da7fSAdrian Chadd } 230*4574da7fSAdrian Chadd } 231*4574da7fSAdrian Chadd return (ENOENT); 232*4574da7fSAdrian Chadd } 233*4574da7fSAdrian Chadd 234*4574da7fSAdrian Chadd /* 235*4574da7fSAdrian Chadd * Functions of the proxy that is interposed between the ethernet interface 236*4574da7fSAdrian Chadd * driver and the miibus device. 237*4574da7fSAdrian Chadd */ 238*4574da7fSAdrian Chadd 239*4574da7fSAdrian Chadd static int 240*4574da7fSAdrian Chadd miiproxy_rendevous_callback(enum rendevous_op op, struct rendevous_entry *rendevous) 241*4574da7fSAdrian Chadd { 242*4574da7fSAdrian Chadd struct miiproxy_softc *sc = device_get_softc(rendevous->proxy.device); 243*4574da7fSAdrian Chadd 244*4574da7fSAdrian Chadd switch (op) { 245*4574da7fSAdrian Chadd case RENDEVOUS_ATTACH: 246*4574da7fSAdrian Chadd sc->mdio = device_get_parent(rendevous->target.device); 247*4574da7fSAdrian Chadd break; 248*4574da7fSAdrian Chadd case RENDEVOUS_DETACH: 249*4574da7fSAdrian Chadd sc->mdio = NULL; 250*4574da7fSAdrian Chadd break; 251*4574da7fSAdrian Chadd } 252*4574da7fSAdrian Chadd return (0); 253*4574da7fSAdrian Chadd } 254*4574da7fSAdrian Chadd 255*4574da7fSAdrian Chadd static int 256*4574da7fSAdrian Chadd miiproxy_probe(device_t dev) 257*4574da7fSAdrian Chadd { 258*4574da7fSAdrian Chadd device_set_desc(dev, "MII/MDIO proxy, MII side"); 259*4574da7fSAdrian Chadd 260*4574da7fSAdrian Chadd return (BUS_PROBE_SPECIFIC); 261*4574da7fSAdrian Chadd } 262*4574da7fSAdrian Chadd 263*4574da7fSAdrian Chadd static int 264*4574da7fSAdrian Chadd miiproxy_attach(device_t dev) 265*4574da7fSAdrian Chadd { 266*4574da7fSAdrian Chadd 267*4574da7fSAdrian Chadd /* 268*4574da7fSAdrian Chadd * The ethernet interface needs to call mii_attach_proxy() to pass 269*4574da7fSAdrian Chadd * the relevant parameters for rendevous with the MDIO target. 270*4574da7fSAdrian Chadd */ 271*4574da7fSAdrian Chadd return (bus_generic_attach(dev)); 272*4574da7fSAdrian Chadd } 273*4574da7fSAdrian Chadd 274*4574da7fSAdrian Chadd static int 275*4574da7fSAdrian Chadd miiproxy_detach(device_t dev) 276*4574da7fSAdrian Chadd { 277*4574da7fSAdrian Chadd 278*4574da7fSAdrian Chadd rendevous_unregister_proxy(dev); 279*4574da7fSAdrian Chadd bus_generic_detach(dev); 280*4574da7fSAdrian Chadd return (0); 281*4574da7fSAdrian Chadd } 282*4574da7fSAdrian Chadd 283*4574da7fSAdrian Chadd static int 284*4574da7fSAdrian Chadd miiproxy_readreg(device_t dev, int phy, int reg) 285*4574da7fSAdrian Chadd { 286*4574da7fSAdrian Chadd struct miiproxy_softc *sc = device_get_softc(dev); 287*4574da7fSAdrian Chadd 288*4574da7fSAdrian Chadd if (sc->mdio != NULL) 289*4574da7fSAdrian Chadd return (MDIO_READREG(sc->mdio, phy, reg)); 290*4574da7fSAdrian Chadd return (-1); 291*4574da7fSAdrian Chadd } 292*4574da7fSAdrian Chadd 293*4574da7fSAdrian Chadd static int 294*4574da7fSAdrian Chadd miiproxy_writereg(device_t dev, int phy, int reg, int val) 295*4574da7fSAdrian Chadd { 296*4574da7fSAdrian Chadd struct miiproxy_softc *sc = device_get_softc(dev); 297*4574da7fSAdrian Chadd 298*4574da7fSAdrian Chadd if (sc->mdio != NULL) 299*4574da7fSAdrian Chadd return (MDIO_WRITEREG(sc->mdio, phy, reg, val)); 300*4574da7fSAdrian Chadd return (-1); 301*4574da7fSAdrian Chadd } 302*4574da7fSAdrian Chadd 303*4574da7fSAdrian Chadd static void 304*4574da7fSAdrian Chadd miiproxy_statchg(device_t dev) 305*4574da7fSAdrian Chadd { 306*4574da7fSAdrian Chadd 307*4574da7fSAdrian Chadd MIIBUS_STATCHG(device_get_parent(dev)); 308*4574da7fSAdrian Chadd } 309*4574da7fSAdrian Chadd 310*4574da7fSAdrian Chadd static void 311*4574da7fSAdrian Chadd miiproxy_linkchg(device_t dev) 312*4574da7fSAdrian Chadd { 313*4574da7fSAdrian Chadd 314*4574da7fSAdrian Chadd MIIBUS_LINKCHG(device_get_parent(dev)); 315*4574da7fSAdrian Chadd } 316*4574da7fSAdrian Chadd 317*4574da7fSAdrian Chadd static void 318*4574da7fSAdrian Chadd miiproxy_mediainit(device_t dev) 319*4574da7fSAdrian Chadd { 320*4574da7fSAdrian Chadd 321*4574da7fSAdrian Chadd MIIBUS_MEDIAINIT(device_get_parent(dev)); 322*4574da7fSAdrian Chadd } 323*4574da7fSAdrian Chadd 324*4574da7fSAdrian Chadd /* 325*4574da7fSAdrian Chadd * Functions for the MDIO target device driver. 326*4574da7fSAdrian Chadd */ 327*4574da7fSAdrian Chadd static int 328*4574da7fSAdrian Chadd mdioproxy_rendevous_callback(enum rendevous_op op, struct rendevous_entry *rendevous) 329*4574da7fSAdrian Chadd { 330*4574da7fSAdrian Chadd return (0); 331*4574da7fSAdrian Chadd } 332*4574da7fSAdrian Chadd 333*4574da7fSAdrian Chadd static void 334*4574da7fSAdrian Chadd mdioproxy_identify(driver_t *driver, device_t parent) 335*4574da7fSAdrian Chadd { 336*4574da7fSAdrian Chadd device_t child; 337*4574da7fSAdrian Chadd 338*4574da7fSAdrian Chadd if (device_find_child(parent, driver->name, -1) == NULL) { 339*4574da7fSAdrian Chadd child = BUS_ADD_CHILD(parent, 0, driver->name, -1); 340*4574da7fSAdrian Chadd } 341*4574da7fSAdrian Chadd } 342*4574da7fSAdrian Chadd 343*4574da7fSAdrian Chadd static int 344*4574da7fSAdrian Chadd mdioproxy_probe(device_t dev) 345*4574da7fSAdrian Chadd { 346*4574da7fSAdrian Chadd device_set_desc(dev, "MII/MDIO proxy, MDIO side"); 347*4574da7fSAdrian Chadd 348*4574da7fSAdrian Chadd return (BUS_PROBE_SPECIFIC); 349*4574da7fSAdrian Chadd } 350*4574da7fSAdrian Chadd 351*4574da7fSAdrian Chadd static int 352*4574da7fSAdrian Chadd mdioproxy_attach(device_t dev) 353*4574da7fSAdrian Chadd { 354*4574da7fSAdrian Chadd 355*4574da7fSAdrian Chadd rendevous_register_target(dev, mdioproxy_rendevous_callback); 356*4574da7fSAdrian Chadd return (bus_generic_attach(dev)); 357*4574da7fSAdrian Chadd } 358*4574da7fSAdrian Chadd 359*4574da7fSAdrian Chadd static int 360*4574da7fSAdrian Chadd mdioproxy_detach(device_t dev) 361*4574da7fSAdrian Chadd { 362*4574da7fSAdrian Chadd 363*4574da7fSAdrian Chadd rendevous_unregister_target(dev); 364*4574da7fSAdrian Chadd bus_generic_detach(dev); 365*4574da7fSAdrian Chadd return (0); 366*4574da7fSAdrian Chadd } 367*4574da7fSAdrian Chadd 368*4574da7fSAdrian Chadd /* 369*4574da7fSAdrian Chadd * Attach this proxy in place of miibus. The target MDIO must be attached 370*4574da7fSAdrian Chadd * already. Returns NULL on error. 371*4574da7fSAdrian Chadd */ 372*4574da7fSAdrian Chadd device_t 373*4574da7fSAdrian Chadd mii_attach_proxy(device_t dev) 374*4574da7fSAdrian Chadd { 375*4574da7fSAdrian Chadd struct miiproxy_softc *sc; 376*4574da7fSAdrian Chadd int error; 377*4574da7fSAdrian Chadd const char *name; 378*4574da7fSAdrian Chadd device_t miiproxy; 379*4574da7fSAdrian Chadd 380*4574da7fSAdrian Chadd if (resource_string_value(device_get_name(dev), 381*4574da7fSAdrian Chadd device_get_unit(dev), "mdio", &name) != 0) { 382*4574da7fSAdrian Chadd if (bootverbose) 383*4574da7fSAdrian Chadd printf("mii_attach_proxy: not attaching, no mdio" 384*4574da7fSAdrian Chadd " device hint for %s\n", device_get_nameunit(dev)); 385*4574da7fSAdrian Chadd return (NULL); 386*4574da7fSAdrian Chadd } 387*4574da7fSAdrian Chadd 388*4574da7fSAdrian Chadd miiproxy = device_add_child(dev, miiproxy_driver.name, -1); 389*4574da7fSAdrian Chadd error = bus_generic_attach(dev); 390*4574da7fSAdrian Chadd if (error != 0) { 391*4574da7fSAdrian Chadd device_printf(dev, "can't attach miiproxy\n"); 392*4574da7fSAdrian Chadd return (NULL); 393*4574da7fSAdrian Chadd } 394*4574da7fSAdrian Chadd sc = device_get_softc(miiproxy); 395*4574da7fSAdrian Chadd sc->parent = dev; 396*4574da7fSAdrian Chadd sc->proxy = miiproxy; 397*4574da7fSAdrian Chadd if (rendevous_register_proxy(miiproxy, name, miiproxy_rendevous_callback) != 0) { 398*4574da7fSAdrian Chadd device_printf(dev, "can't attach proxy\n"); 399*4574da7fSAdrian Chadd return (NULL); 400*4574da7fSAdrian Chadd } 401*4574da7fSAdrian Chadd device_printf(miiproxy, "attached to target %s\n", device_get_nameunit(sc->mdio)); 402*4574da7fSAdrian Chadd return (miiproxy); 403*4574da7fSAdrian Chadd } 404*4574da7fSAdrian Chadd 405*4574da7fSAdrian Chadd static device_method_t miiproxy_methods[] = { 406*4574da7fSAdrian Chadd /* device interface */ 407*4574da7fSAdrian Chadd DEVMETHOD(device_probe, miiproxy_probe), 408*4574da7fSAdrian Chadd DEVMETHOD(device_attach, miiproxy_attach), 409*4574da7fSAdrian Chadd DEVMETHOD(device_detach, miiproxy_detach), 410*4574da7fSAdrian Chadd DEVMETHOD(device_shutdown, bus_generic_shutdown), 411*4574da7fSAdrian Chadd 412*4574da7fSAdrian Chadd /* MII interface */ 413*4574da7fSAdrian Chadd DEVMETHOD(miibus_readreg, miiproxy_readreg), 414*4574da7fSAdrian Chadd DEVMETHOD(miibus_writereg, miiproxy_writereg), 415*4574da7fSAdrian Chadd DEVMETHOD(miibus_statchg, miiproxy_statchg), 416*4574da7fSAdrian Chadd DEVMETHOD(miibus_linkchg, miiproxy_linkchg), 417*4574da7fSAdrian Chadd DEVMETHOD(miibus_mediainit, miiproxy_mediainit), 418*4574da7fSAdrian Chadd 419*4574da7fSAdrian Chadd DEVMETHOD_END 420*4574da7fSAdrian Chadd }; 421*4574da7fSAdrian Chadd 422*4574da7fSAdrian Chadd static device_method_t mdioproxy_methods[] = { 423*4574da7fSAdrian Chadd /* device interface */ 424*4574da7fSAdrian Chadd DEVMETHOD(device_identify, mdioproxy_identify), 425*4574da7fSAdrian Chadd DEVMETHOD(device_probe, mdioproxy_probe), 426*4574da7fSAdrian Chadd DEVMETHOD(device_attach, mdioproxy_attach), 427*4574da7fSAdrian Chadd DEVMETHOD(device_detach, mdioproxy_detach), 428*4574da7fSAdrian Chadd DEVMETHOD(device_shutdown, bus_generic_shutdown), 429*4574da7fSAdrian Chadd 430*4574da7fSAdrian Chadd DEVMETHOD_END 431*4574da7fSAdrian Chadd }; 432*4574da7fSAdrian Chadd 433*4574da7fSAdrian Chadd DEFINE_CLASS_0(miiproxy, miiproxy_driver, miiproxy_methods, 434*4574da7fSAdrian Chadd sizeof(struct miiproxy_softc)); 435*4574da7fSAdrian Chadd DEFINE_CLASS_0(mdioproxy, mdioproxy_driver, mdioproxy_methods, 436*4574da7fSAdrian Chadd sizeof(struct mdioproxy_softc)); 437*4574da7fSAdrian Chadd 438*4574da7fSAdrian Chadd devclass_t miiproxy_devclass; 439*4574da7fSAdrian Chadd static devclass_t mdioproxy_devclass; 440*4574da7fSAdrian Chadd 441*4574da7fSAdrian Chadd DRIVER_MODULE(mdioproxy, mdio, mdioproxy_driver, mdioproxy_devclass, 0, 0); 442*4574da7fSAdrian Chadd DRIVER_MODULE(miibus, miiproxy, miibus_driver, miibus_devclass, 0, 0); 443*4574da7fSAdrian Chadd MODULE_VERSION(miiproxy, 1); 444*4574da7fSAdrian Chadd MODULE_DEPEND(miiproxy, miibus, 1, 1, 1); 445