14574da7fSAdrian Chadd /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
44574da7fSAdrian Chadd * Copyright (c) 2011-2012 Stefan Bethke.
54574da7fSAdrian Chadd * All rights reserved.
64574da7fSAdrian Chadd *
74574da7fSAdrian Chadd * Redistribution and use in source and binary forms, with or without
84574da7fSAdrian Chadd * modification, are permitted provided that the following conditions
94574da7fSAdrian Chadd * are met:
104574da7fSAdrian Chadd * 1. Redistributions of source code must retain the above copyright
114574da7fSAdrian Chadd * notice, this list of conditions and the following disclaimer.
124574da7fSAdrian Chadd * 2. Redistributions in binary form must reproduce the above copyright
134574da7fSAdrian Chadd * notice, this list of conditions and the following disclaimer in the
144574da7fSAdrian Chadd * documentation and/or other materials provided with the distribution.
154574da7fSAdrian Chadd *
164574da7fSAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
174574da7fSAdrian Chadd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
184574da7fSAdrian Chadd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
194574da7fSAdrian Chadd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
204574da7fSAdrian Chadd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
214574da7fSAdrian Chadd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
224574da7fSAdrian Chadd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
234574da7fSAdrian Chadd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
244574da7fSAdrian Chadd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
254574da7fSAdrian Chadd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
264574da7fSAdrian Chadd * SUCH DAMAGE.
274574da7fSAdrian Chadd */
284574da7fSAdrian Chadd
294574da7fSAdrian Chadd #include <sys/param.h>
304574da7fSAdrian Chadd #include <sys/bus.h>
314574da7fSAdrian Chadd #include <sys/kernel.h>
32104dc214SGleb Smirnoff #include <sys/malloc.h>
334574da7fSAdrian Chadd #include <sys/module.h>
344574da7fSAdrian Chadd #include <sys/socket.h>
354574da7fSAdrian Chadd #include <sys/sockio.h>
364574da7fSAdrian Chadd #include <sys/systm.h>
374574da7fSAdrian Chadd
384574da7fSAdrian Chadd #include <net/if.h>
394574da7fSAdrian Chadd #include <net/if_media.h>
404574da7fSAdrian Chadd
414574da7fSAdrian Chadd #include <dev/etherswitch/miiproxy.h>
424574da7fSAdrian Chadd #include <dev/mii/mii.h>
434574da7fSAdrian Chadd #include <dev/mii/miivar.h>
444574da7fSAdrian Chadd
454574da7fSAdrian Chadd #include "mdio_if.h"
464574da7fSAdrian Chadd #include "miibus_if.h"
474574da7fSAdrian Chadd
484574da7fSAdrian Chadd
494574da7fSAdrian Chadd MALLOC_DECLARE(M_MIIPROXY);
504574da7fSAdrian Chadd MALLOC_DEFINE(M_MIIPROXY, "miiproxy", "miiproxy data structures");
514574da7fSAdrian Chadd
524574da7fSAdrian Chadd driver_t miiproxy_driver;
534574da7fSAdrian Chadd driver_t mdioproxy_driver;
544574da7fSAdrian Chadd
554574da7fSAdrian Chadd struct miiproxy_softc {
564574da7fSAdrian Chadd device_t parent;
574574da7fSAdrian Chadd device_t proxy;
584574da7fSAdrian Chadd device_t mdio;
594574da7fSAdrian Chadd };
604574da7fSAdrian Chadd
614574da7fSAdrian Chadd struct mdioproxy_softc {
624574da7fSAdrian Chadd };
634574da7fSAdrian Chadd
644574da7fSAdrian Chadd /*
6552f24367SRui Paulo * The rendezvous data structures and functions allow two device endpoints to
664574da7fSAdrian Chadd * match up, so that the proxy endpoint can be associated with a target
674574da7fSAdrian Chadd * endpoint. The proxy has to know the device name of the target that it
6852f24367SRui Paulo * wants to associate with, for example through a hint. The rendezvous code
694574da7fSAdrian Chadd * makes no assumptions about the devices that want to meet.
704574da7fSAdrian Chadd */
7152f24367SRui Paulo struct rendezvous_entry;
724574da7fSAdrian Chadd
7352f24367SRui Paulo enum rendezvous_op {
7452f24367SRui Paulo RENDEZVOUS_ATTACH,
7552f24367SRui Paulo RENDEZVOUS_DETACH
764574da7fSAdrian Chadd };
774574da7fSAdrian Chadd
7852f24367SRui Paulo typedef int (*rendezvous_callback_t)(enum rendezvous_op,
7952f24367SRui Paulo struct rendezvous_entry *);
804574da7fSAdrian Chadd
8152f24367SRui Paulo static SLIST_HEAD(rendezvoushead, rendezvous_entry) rendezvoushead =
8252f24367SRui Paulo SLIST_HEAD_INITIALIZER(rendezvoushead);
834574da7fSAdrian Chadd
8452f24367SRui Paulo struct rendezvous_endpoint {
854574da7fSAdrian Chadd device_t device;
864574da7fSAdrian Chadd const char *name;
8752f24367SRui Paulo rendezvous_callback_t callback;
884574da7fSAdrian Chadd };
894574da7fSAdrian Chadd
9052f24367SRui Paulo struct rendezvous_entry {
9152f24367SRui Paulo SLIST_ENTRY(rendezvous_entry) entries;
9252f24367SRui Paulo struct rendezvous_endpoint proxy;
9352f24367SRui Paulo struct rendezvous_endpoint target;
944574da7fSAdrian Chadd };
954574da7fSAdrian Chadd
964574da7fSAdrian Chadd /*
974574da7fSAdrian Chadd * Call the callback routines for both the proxy and the target. If either
984574da7fSAdrian Chadd * returns an error, undo the attachment.
994574da7fSAdrian Chadd */
1004574da7fSAdrian Chadd static int
rendezvous_attach(struct rendezvous_entry * e,struct rendezvous_endpoint * ep)10152f24367SRui Paulo rendezvous_attach(struct rendezvous_entry *e, struct rendezvous_endpoint *ep)
1024574da7fSAdrian Chadd {
1034574da7fSAdrian Chadd int error;
1044574da7fSAdrian Chadd
10552f24367SRui Paulo error = e->proxy.callback(RENDEZVOUS_ATTACH, e);
1064574da7fSAdrian Chadd if (error == 0) {
10752f24367SRui Paulo error = e->target.callback(RENDEZVOUS_ATTACH, e);
1084574da7fSAdrian Chadd if (error != 0) {
10952f24367SRui Paulo e->proxy.callback(RENDEZVOUS_DETACH, e);
1104574da7fSAdrian Chadd ep->device = NULL;
1114574da7fSAdrian Chadd ep->callback = NULL;
1124574da7fSAdrian Chadd }
1134574da7fSAdrian Chadd }
1144574da7fSAdrian Chadd return (error);
1154574da7fSAdrian Chadd }
1164574da7fSAdrian Chadd
1174574da7fSAdrian Chadd /*
11852f24367SRui Paulo * Create an entry for the proxy in the rendezvous list. The name parameter
1194574da7fSAdrian Chadd * indicates the name of the device that is the target endpoint for this
12052f24367SRui Paulo * rendezvous. The callback will be invoked as soon as the target is
1214574da7fSAdrian Chadd * registered: either immediately if the target registered itself earlier,
1224574da7fSAdrian Chadd * or once the target registers. Returns ENXIO if the target has not yet
1234574da7fSAdrian Chadd * registered.
1244574da7fSAdrian Chadd */
1254574da7fSAdrian Chadd static int
rendezvous_register_proxy(device_t dev,const char * name,rendezvous_callback_t callback)12652f24367SRui Paulo rendezvous_register_proxy(device_t dev, const char *name,
12752f24367SRui Paulo rendezvous_callback_t callback)
1284574da7fSAdrian Chadd {
12952f24367SRui Paulo struct rendezvous_entry *e;
1304574da7fSAdrian Chadd
1314574da7fSAdrian Chadd KASSERT(callback != NULL, ("callback must be set"));
13252f24367SRui Paulo SLIST_FOREACH(e, &rendezvoushead, entries) {
1334574da7fSAdrian Chadd if (strcmp(name, e->target.name) == 0) {
1344574da7fSAdrian Chadd /* the target is already attached */
1354574da7fSAdrian Chadd e->proxy.name = device_get_nameunit(dev);
1364574da7fSAdrian Chadd e->proxy.device = dev;
1374574da7fSAdrian Chadd e->proxy.callback = callback;
13852f24367SRui Paulo return (rendezvous_attach(e, &e->proxy));
1394574da7fSAdrian Chadd }
1404574da7fSAdrian Chadd }
1414574da7fSAdrian Chadd e = malloc(sizeof(*e), M_MIIPROXY, M_WAITOK | M_ZERO);
1424574da7fSAdrian Chadd e->proxy.name = device_get_nameunit(dev);
1434574da7fSAdrian Chadd e->proxy.device = dev;
1444574da7fSAdrian Chadd e->proxy.callback = callback;
1454574da7fSAdrian Chadd e->target.name = name;
14652f24367SRui Paulo SLIST_INSERT_HEAD(&rendezvoushead, e, entries);
1474574da7fSAdrian Chadd return (ENXIO);
1484574da7fSAdrian Chadd }
1494574da7fSAdrian Chadd
1504574da7fSAdrian Chadd /*
15152f24367SRui Paulo * Create an entry in the rendezvous list for the target.
1524574da7fSAdrian Chadd * Returns ENXIO if the proxy has not yet registered.
1534574da7fSAdrian Chadd */
1544574da7fSAdrian Chadd static int
rendezvous_register_target(device_t dev,rendezvous_callback_t callback)15552f24367SRui Paulo rendezvous_register_target(device_t dev, rendezvous_callback_t callback)
1564574da7fSAdrian Chadd {
15752f24367SRui Paulo struct rendezvous_entry *e;
1584574da7fSAdrian Chadd const char *name;
1594574da7fSAdrian Chadd
1604574da7fSAdrian Chadd KASSERT(callback != NULL, ("callback must be set"));
1614574da7fSAdrian Chadd name = device_get_nameunit(dev);
16252f24367SRui Paulo SLIST_FOREACH(e, &rendezvoushead, entries) {
1634574da7fSAdrian Chadd if (strcmp(name, e->target.name) == 0) {
1644574da7fSAdrian Chadd e->target.device = dev;
1654574da7fSAdrian Chadd e->target.callback = callback;
16652f24367SRui Paulo return (rendezvous_attach(e, &e->target));
1674574da7fSAdrian Chadd }
1684574da7fSAdrian Chadd }
1694574da7fSAdrian Chadd e = malloc(sizeof(*e), M_MIIPROXY, M_WAITOK | M_ZERO);
1704574da7fSAdrian Chadd e->target.name = name;
1714574da7fSAdrian Chadd e->target.device = dev;
1724574da7fSAdrian Chadd e->target.callback = callback;
17352f24367SRui Paulo SLIST_INSERT_HEAD(&rendezvoushead, e, entries);
1744574da7fSAdrian Chadd return (ENXIO);
1754574da7fSAdrian Chadd }
1764574da7fSAdrian Chadd
1774574da7fSAdrian Chadd /*
1784574da7fSAdrian Chadd * Remove the registration for the proxy.
1794574da7fSAdrian Chadd */
1804574da7fSAdrian Chadd static int
rendezvous_unregister_proxy(device_t dev)18152f24367SRui Paulo rendezvous_unregister_proxy(device_t dev)
1824574da7fSAdrian Chadd {
18352f24367SRui Paulo struct rendezvous_entry *e;
1844574da7fSAdrian Chadd int error = 0;
1854574da7fSAdrian Chadd
18652f24367SRui Paulo SLIST_FOREACH(e, &rendezvoushead, entries) {
1874574da7fSAdrian Chadd if (e->proxy.device == dev) {
1884574da7fSAdrian Chadd if (e->target.device == NULL) {
18952f24367SRui Paulo SLIST_REMOVE(&rendezvoushead, e, rendezvous_entry, entries);
1904574da7fSAdrian Chadd free(e, M_MIIPROXY);
1914574da7fSAdrian Chadd return (0);
1924574da7fSAdrian Chadd } else {
19352f24367SRui Paulo e->proxy.callback(RENDEZVOUS_DETACH, e);
19452f24367SRui Paulo e->target.callback(RENDEZVOUS_DETACH, e);
1954574da7fSAdrian Chadd }
1964574da7fSAdrian Chadd e->proxy.device = NULL;
1974574da7fSAdrian Chadd e->proxy.callback = NULL;
1984574da7fSAdrian Chadd return (error);
1994574da7fSAdrian Chadd }
2004574da7fSAdrian Chadd }
2014574da7fSAdrian Chadd return (ENOENT);
2024574da7fSAdrian Chadd }
2034574da7fSAdrian Chadd
2044574da7fSAdrian Chadd /*
2054574da7fSAdrian Chadd * Remove the registration for the target.
2064574da7fSAdrian Chadd */
2074574da7fSAdrian Chadd static int
rendezvous_unregister_target(device_t dev)20852f24367SRui Paulo rendezvous_unregister_target(device_t dev)
2094574da7fSAdrian Chadd {
21052f24367SRui Paulo struct rendezvous_entry *e;
2114574da7fSAdrian Chadd int error = 0;
2124574da7fSAdrian Chadd
21352f24367SRui Paulo SLIST_FOREACH(e, &rendezvoushead, entries) {
2144574da7fSAdrian Chadd if (e->target.device == dev) {
2154574da7fSAdrian Chadd if (e->proxy.device == NULL) {
21652f24367SRui Paulo SLIST_REMOVE(&rendezvoushead, e, rendezvous_entry, entries);
2174574da7fSAdrian Chadd free(e, M_MIIPROXY);
2184574da7fSAdrian Chadd return (0);
2194574da7fSAdrian Chadd } else {
22052f24367SRui Paulo e->proxy.callback(RENDEZVOUS_DETACH, e);
22152f24367SRui Paulo e->target.callback(RENDEZVOUS_DETACH, e);
2224574da7fSAdrian Chadd }
2234574da7fSAdrian Chadd e->target.device = NULL;
2244574da7fSAdrian Chadd e->target.callback = NULL;
2254574da7fSAdrian Chadd return (error);
2264574da7fSAdrian Chadd }
2274574da7fSAdrian Chadd }
2284574da7fSAdrian Chadd return (ENOENT);
2294574da7fSAdrian Chadd }
2304574da7fSAdrian Chadd
2314574da7fSAdrian Chadd /*
2324574da7fSAdrian Chadd * Functions of the proxy that is interposed between the ethernet interface
2334574da7fSAdrian Chadd * driver and the miibus device.
2344574da7fSAdrian Chadd */
2354574da7fSAdrian Chadd
2364574da7fSAdrian Chadd static int
miiproxy_rendezvous_callback(enum rendezvous_op op,struct rendezvous_entry * rendezvous)23752f24367SRui Paulo miiproxy_rendezvous_callback(enum rendezvous_op op, struct rendezvous_entry *rendezvous)
2384574da7fSAdrian Chadd {
23952f24367SRui Paulo struct miiproxy_softc *sc = device_get_softc(rendezvous->proxy.device);
2404574da7fSAdrian Chadd
2414574da7fSAdrian Chadd switch (op) {
24252f24367SRui Paulo case RENDEZVOUS_ATTACH:
24352f24367SRui Paulo sc->mdio = device_get_parent(rendezvous->target.device);
2444574da7fSAdrian Chadd break;
24552f24367SRui Paulo case RENDEZVOUS_DETACH:
2464574da7fSAdrian Chadd sc->mdio = NULL;
2474574da7fSAdrian Chadd break;
2484574da7fSAdrian Chadd }
2494574da7fSAdrian Chadd return (0);
2504574da7fSAdrian Chadd }
2514574da7fSAdrian Chadd
2524574da7fSAdrian Chadd static int
miiproxy_probe(device_t dev)2534574da7fSAdrian Chadd miiproxy_probe(device_t dev)
2544574da7fSAdrian Chadd {
2554574da7fSAdrian Chadd device_set_desc(dev, "MII/MDIO proxy, MII side");
2564574da7fSAdrian Chadd
2574574da7fSAdrian Chadd return (BUS_PROBE_SPECIFIC);
2584574da7fSAdrian Chadd }
2594574da7fSAdrian Chadd
2604574da7fSAdrian Chadd static int
miiproxy_attach(device_t dev)2614574da7fSAdrian Chadd miiproxy_attach(device_t dev)
2624574da7fSAdrian Chadd {
2634574da7fSAdrian Chadd
2644574da7fSAdrian Chadd /*
2654574da7fSAdrian Chadd * The ethernet interface needs to call mii_attach_proxy() to pass
26652f24367SRui Paulo * the relevant parameters for rendezvous with the MDIO target.
2674574da7fSAdrian Chadd */
268*18250ec6SJohn Baldwin bus_attach_children(dev);
269*18250ec6SJohn Baldwin return (0);
2704574da7fSAdrian Chadd }
2714574da7fSAdrian Chadd
2724574da7fSAdrian Chadd static int
miiproxy_detach(device_t dev)2734574da7fSAdrian Chadd miiproxy_detach(device_t dev)
2744574da7fSAdrian Chadd {
2754574da7fSAdrian Chadd
27652f24367SRui Paulo rendezvous_unregister_proxy(dev);
2774574da7fSAdrian Chadd bus_generic_detach(dev);
2784574da7fSAdrian Chadd return (0);
2794574da7fSAdrian Chadd }
2804574da7fSAdrian Chadd
2814574da7fSAdrian Chadd static int
miiproxy_readreg(device_t dev,int phy,int reg)2824574da7fSAdrian Chadd miiproxy_readreg(device_t dev, int phy, int reg)
2834574da7fSAdrian Chadd {
2844574da7fSAdrian Chadd struct miiproxy_softc *sc = device_get_softc(dev);
2854574da7fSAdrian Chadd
2864574da7fSAdrian Chadd if (sc->mdio != NULL)
2874574da7fSAdrian Chadd return (MDIO_READREG(sc->mdio, phy, reg));
2884574da7fSAdrian Chadd return (-1);
2894574da7fSAdrian Chadd }
2904574da7fSAdrian Chadd
2914574da7fSAdrian Chadd static int
miiproxy_writereg(device_t dev,int phy,int reg,int val)2924574da7fSAdrian Chadd miiproxy_writereg(device_t dev, int phy, int reg, int val)
2934574da7fSAdrian Chadd {
2944574da7fSAdrian Chadd struct miiproxy_softc *sc = device_get_softc(dev);
2954574da7fSAdrian Chadd
2964574da7fSAdrian Chadd if (sc->mdio != NULL)
2974574da7fSAdrian Chadd return (MDIO_WRITEREG(sc->mdio, phy, reg, val));
2984574da7fSAdrian Chadd return (-1);
2994574da7fSAdrian Chadd }
3004574da7fSAdrian Chadd
3014574da7fSAdrian Chadd static void
miiproxy_statchg(device_t dev)3024574da7fSAdrian Chadd miiproxy_statchg(device_t dev)
3034574da7fSAdrian Chadd {
3044574da7fSAdrian Chadd
3054574da7fSAdrian Chadd MIIBUS_STATCHG(device_get_parent(dev));
3064574da7fSAdrian Chadd }
3074574da7fSAdrian Chadd
3084574da7fSAdrian Chadd static void
miiproxy_linkchg(device_t dev)3094574da7fSAdrian Chadd miiproxy_linkchg(device_t dev)
3104574da7fSAdrian Chadd {
3114574da7fSAdrian Chadd
3124574da7fSAdrian Chadd MIIBUS_LINKCHG(device_get_parent(dev));
3134574da7fSAdrian Chadd }
3144574da7fSAdrian Chadd
3154574da7fSAdrian Chadd static void
miiproxy_mediainit(device_t dev)3164574da7fSAdrian Chadd miiproxy_mediainit(device_t dev)
3174574da7fSAdrian Chadd {
3184574da7fSAdrian Chadd
3194574da7fSAdrian Chadd MIIBUS_MEDIAINIT(device_get_parent(dev));
3204574da7fSAdrian Chadd }
3214574da7fSAdrian Chadd
3224574da7fSAdrian Chadd /*
3234574da7fSAdrian Chadd * Functions for the MDIO target device driver.
3244574da7fSAdrian Chadd */
3254574da7fSAdrian Chadd static int
mdioproxy_rendezvous_callback(enum rendezvous_op op,struct rendezvous_entry * rendezvous)32652f24367SRui Paulo mdioproxy_rendezvous_callback(enum rendezvous_op op, struct rendezvous_entry *rendezvous)
3274574da7fSAdrian Chadd {
3284574da7fSAdrian Chadd return (0);
3294574da7fSAdrian Chadd }
3304574da7fSAdrian Chadd
3314574da7fSAdrian Chadd static void
mdioproxy_identify(driver_t * driver,device_t parent)3324574da7fSAdrian Chadd mdioproxy_identify(driver_t *driver, device_t parent)
3334574da7fSAdrian Chadd {
3344574da7fSAdrian Chadd if (device_find_child(parent, driver->name, -1) == NULL) {
335a05a6804SWarner Losh BUS_ADD_CHILD(parent, 0, driver->name, DEVICE_UNIT_ANY);
3364574da7fSAdrian Chadd }
3374574da7fSAdrian Chadd }
3384574da7fSAdrian Chadd
3394574da7fSAdrian Chadd static int
mdioproxy_probe(device_t dev)3404574da7fSAdrian Chadd mdioproxy_probe(device_t dev)
3414574da7fSAdrian Chadd {
3424574da7fSAdrian Chadd device_set_desc(dev, "MII/MDIO proxy, MDIO side");
3434574da7fSAdrian Chadd
3444574da7fSAdrian Chadd return (BUS_PROBE_SPECIFIC);
3454574da7fSAdrian Chadd }
3464574da7fSAdrian Chadd
3474574da7fSAdrian Chadd static int
mdioproxy_attach(device_t dev)3484574da7fSAdrian Chadd mdioproxy_attach(device_t dev)
3494574da7fSAdrian Chadd {
3504574da7fSAdrian Chadd
35152f24367SRui Paulo rendezvous_register_target(dev, mdioproxy_rendezvous_callback);
352*18250ec6SJohn Baldwin bus_attach_children(dev);
353*18250ec6SJohn Baldwin return (0);
3544574da7fSAdrian Chadd }
3554574da7fSAdrian Chadd
3564574da7fSAdrian Chadd static int
mdioproxy_detach(device_t dev)3574574da7fSAdrian Chadd mdioproxy_detach(device_t dev)
3584574da7fSAdrian Chadd {
3594574da7fSAdrian Chadd
36052f24367SRui Paulo rendezvous_unregister_target(dev);
3614574da7fSAdrian Chadd bus_generic_detach(dev);
3624574da7fSAdrian Chadd return (0);
3634574da7fSAdrian Chadd }
3644574da7fSAdrian Chadd
3654574da7fSAdrian Chadd /*
3664574da7fSAdrian Chadd * Attach this proxy in place of miibus. The target MDIO must be attached
3674574da7fSAdrian Chadd * already. Returns NULL on error.
3684574da7fSAdrian Chadd */
3694574da7fSAdrian Chadd device_t
mii_attach_proxy(device_t dev)3704574da7fSAdrian Chadd mii_attach_proxy(device_t dev)
3714574da7fSAdrian Chadd {
3724574da7fSAdrian Chadd struct miiproxy_softc *sc;
3734574da7fSAdrian Chadd const char *name;
3744574da7fSAdrian Chadd device_t miiproxy;
3754574da7fSAdrian Chadd
3764574da7fSAdrian Chadd if (resource_string_value(device_get_name(dev),
3774574da7fSAdrian Chadd device_get_unit(dev), "mdio", &name) != 0) {
3784574da7fSAdrian Chadd if (bootverbose)
3794574da7fSAdrian Chadd printf("mii_attach_proxy: not attaching, no mdio"
3804574da7fSAdrian Chadd " device hint for %s\n", device_get_nameunit(dev));
3814574da7fSAdrian Chadd return (NULL);
3824574da7fSAdrian Chadd }
3834574da7fSAdrian Chadd
3845b56413dSWarner Losh miiproxy = device_add_child(dev, miiproxy_driver.name, DEVICE_UNIT_ANY);
385*18250ec6SJohn Baldwin bus_attach_children(dev);
3864574da7fSAdrian Chadd sc = device_get_softc(miiproxy);
3874574da7fSAdrian Chadd sc->parent = dev;
3884574da7fSAdrian Chadd sc->proxy = miiproxy;
38952f24367SRui Paulo if (rendezvous_register_proxy(miiproxy, name, miiproxy_rendezvous_callback) != 0) {
3904574da7fSAdrian Chadd device_printf(dev, "can't attach proxy\n");
3914574da7fSAdrian Chadd return (NULL);
3924574da7fSAdrian Chadd }
3934574da7fSAdrian Chadd device_printf(miiproxy, "attached to target %s\n", device_get_nameunit(sc->mdio));
3944574da7fSAdrian Chadd return (miiproxy);
3954574da7fSAdrian Chadd }
3964574da7fSAdrian Chadd
3974574da7fSAdrian Chadd static device_method_t miiproxy_methods[] = {
3984574da7fSAdrian Chadd /* device interface */
3994574da7fSAdrian Chadd DEVMETHOD(device_probe, miiproxy_probe),
4004574da7fSAdrian Chadd DEVMETHOD(device_attach, miiproxy_attach),
4014574da7fSAdrian Chadd DEVMETHOD(device_detach, miiproxy_detach),
4024574da7fSAdrian Chadd DEVMETHOD(device_shutdown, bus_generic_shutdown),
4034574da7fSAdrian Chadd
4044574da7fSAdrian Chadd /* MII interface */
4054574da7fSAdrian Chadd DEVMETHOD(miibus_readreg, miiproxy_readreg),
4064574da7fSAdrian Chadd DEVMETHOD(miibus_writereg, miiproxy_writereg),
4074574da7fSAdrian Chadd DEVMETHOD(miibus_statchg, miiproxy_statchg),
4084574da7fSAdrian Chadd DEVMETHOD(miibus_linkchg, miiproxy_linkchg),
4094574da7fSAdrian Chadd DEVMETHOD(miibus_mediainit, miiproxy_mediainit),
4104574da7fSAdrian Chadd
4114574da7fSAdrian Chadd DEVMETHOD_END
4124574da7fSAdrian Chadd };
4134574da7fSAdrian Chadd
4144574da7fSAdrian Chadd static device_method_t mdioproxy_methods[] = {
4154574da7fSAdrian Chadd /* device interface */
4164574da7fSAdrian Chadd DEVMETHOD(device_identify, mdioproxy_identify),
4174574da7fSAdrian Chadd DEVMETHOD(device_probe, mdioproxy_probe),
4184574da7fSAdrian Chadd DEVMETHOD(device_attach, mdioproxy_attach),
4194574da7fSAdrian Chadd DEVMETHOD(device_detach, mdioproxy_detach),
4204574da7fSAdrian Chadd DEVMETHOD(device_shutdown, bus_generic_shutdown),
4214574da7fSAdrian Chadd
4224574da7fSAdrian Chadd DEVMETHOD_END
4234574da7fSAdrian Chadd };
4244574da7fSAdrian Chadd
4254574da7fSAdrian Chadd DEFINE_CLASS_0(miiproxy, miiproxy_driver, miiproxy_methods,
4264574da7fSAdrian Chadd sizeof(struct miiproxy_softc));
4274574da7fSAdrian Chadd DEFINE_CLASS_0(mdioproxy, mdioproxy_driver, mdioproxy_methods,
4284574da7fSAdrian Chadd sizeof(struct mdioproxy_softc));
4294574da7fSAdrian Chadd
43042726c2fSJohn Baldwin DRIVER_MODULE(mdioproxy, mdio, mdioproxy_driver, 0, 0);
4313e38757dSJohn Baldwin DRIVER_MODULE(miibus, miiproxy, miibus_driver, 0, 0);
4324574da7fSAdrian Chadd MODULE_VERSION(miiproxy, 1);
4334574da7fSAdrian Chadd MODULE_DEPEND(miiproxy, miibus, 1, 1, 1);
434