xref: /freebsd/sys/dev/etherswitch/miiproxy.c (revision 52f243678d00f8c8fe82d78afd8d93bb14eb901b)
14574da7fSAdrian Chadd /*-
24574da7fSAdrian Chadd  * Copyright (c) 2011-2012 Stefan Bethke.
34574da7fSAdrian Chadd  * All rights reserved.
44574da7fSAdrian Chadd  *
54574da7fSAdrian Chadd  * Redistribution and use in source and binary forms, with or without
64574da7fSAdrian Chadd  * modification, are permitted provided that the following conditions
74574da7fSAdrian Chadd  * are met:
84574da7fSAdrian Chadd  * 1. Redistributions of source code must retain the above copyright
94574da7fSAdrian Chadd  *    notice, this list of conditions and the following disclaimer.
104574da7fSAdrian Chadd  * 2. Redistributions in binary form must reproduce the above copyright
114574da7fSAdrian Chadd  *    notice, this list of conditions and the following disclaimer in the
124574da7fSAdrian Chadd  *    documentation and/or other materials provided with the distribution.
134574da7fSAdrian Chadd  *
144574da7fSAdrian Chadd  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
154574da7fSAdrian Chadd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
164574da7fSAdrian Chadd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
174574da7fSAdrian Chadd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
184574da7fSAdrian Chadd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
194574da7fSAdrian Chadd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
204574da7fSAdrian Chadd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
214574da7fSAdrian Chadd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
224574da7fSAdrian Chadd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
234574da7fSAdrian Chadd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
244574da7fSAdrian Chadd  * SUCH DAMAGE.
254574da7fSAdrian Chadd  *
264574da7fSAdrian Chadd  * $FreeBSD$
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 /*
65*52f24367SRui 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
68*52f24367SRui 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  */
71*52f24367SRui Paulo struct rendezvous_entry;
724574da7fSAdrian Chadd 
73*52f24367SRui Paulo enum rendezvous_op {
74*52f24367SRui Paulo 	RENDEZVOUS_ATTACH,
75*52f24367SRui Paulo 	RENDEZVOUS_DETACH
764574da7fSAdrian Chadd };
774574da7fSAdrian Chadd 
78*52f24367SRui Paulo typedef int (*rendezvous_callback_t)(enum rendezvous_op,
79*52f24367SRui Paulo     struct rendezvous_entry *);
804574da7fSAdrian Chadd 
81*52f24367SRui Paulo static SLIST_HEAD(rendezvoushead, rendezvous_entry) rendezvoushead =
82*52f24367SRui Paulo     SLIST_HEAD_INITIALIZER(rendezvoushead);
834574da7fSAdrian Chadd 
84*52f24367SRui Paulo struct rendezvous_endpoint {
854574da7fSAdrian Chadd 	device_t		device;
864574da7fSAdrian Chadd 	const char		*name;
87*52f24367SRui Paulo 	rendezvous_callback_t	callback;
884574da7fSAdrian Chadd };
894574da7fSAdrian Chadd 
90*52f24367SRui Paulo struct rendezvous_entry {
91*52f24367SRui Paulo 	SLIST_ENTRY(rendezvous_entry)	entries;
92*52f24367SRui Paulo 	struct rendezvous_endpoint	proxy;
93*52f24367SRui 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
101*52f24367SRui Paulo rendezvous_attach(struct rendezvous_entry *e, struct rendezvous_endpoint *ep)
1024574da7fSAdrian Chadd {
1034574da7fSAdrian Chadd 	int error;
1044574da7fSAdrian Chadd 
105*52f24367SRui Paulo 	error = e->proxy.callback(RENDEZVOUS_ATTACH, e);
1064574da7fSAdrian Chadd 	if (error == 0) {
107*52f24367SRui Paulo 		error = e->target.callback(RENDEZVOUS_ATTACH, e);
1084574da7fSAdrian Chadd 		if (error != 0) {
109*52f24367SRui 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 /*
118*52f24367SRui 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
120*52f24367SRui 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
126*52f24367SRui Paulo rendezvous_register_proxy(device_t dev, const char *name,
127*52f24367SRui Paulo     rendezvous_callback_t callback)
1284574da7fSAdrian Chadd {
129*52f24367SRui Paulo 	struct rendezvous_entry *e;
1304574da7fSAdrian Chadd 
1314574da7fSAdrian Chadd 	KASSERT(callback != NULL, ("callback must be set"));
132*52f24367SRui 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;
138*52f24367SRui 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;
146*52f24367SRui Paulo 	SLIST_INSERT_HEAD(&rendezvoushead, e, entries);
1474574da7fSAdrian Chadd 	return (ENXIO);
1484574da7fSAdrian Chadd }
1494574da7fSAdrian Chadd 
1504574da7fSAdrian Chadd /*
151*52f24367SRui 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
155*52f24367SRui Paulo rendezvous_register_target(device_t dev, rendezvous_callback_t callback)
1564574da7fSAdrian Chadd {
157*52f24367SRui 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);
162*52f24367SRui 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;
166*52f24367SRui 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;
173*52f24367SRui 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
181*52f24367SRui Paulo rendezvous_unregister_proxy(device_t dev)
1824574da7fSAdrian Chadd {
183*52f24367SRui Paulo 	struct rendezvous_entry *e;
1844574da7fSAdrian Chadd 	int error = 0;
1854574da7fSAdrian Chadd 
186*52f24367SRui Paulo 	SLIST_FOREACH(e, &rendezvoushead, entries) {
1874574da7fSAdrian Chadd 		if (e->proxy.device == dev) {
1884574da7fSAdrian Chadd 			if (e->target.device == NULL) {
189*52f24367SRui Paulo 				SLIST_REMOVE(&rendezvoushead, e, rendezvous_entry, entries);
1904574da7fSAdrian Chadd 				free(e, M_MIIPROXY);
1914574da7fSAdrian Chadd 				return (0);
1924574da7fSAdrian Chadd 			} else {
193*52f24367SRui Paulo 				e->proxy.callback(RENDEZVOUS_DETACH, e);
194*52f24367SRui 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
208*52f24367SRui Paulo rendezvous_unregister_target(device_t dev)
2094574da7fSAdrian Chadd {
210*52f24367SRui Paulo 	struct rendezvous_entry *e;
2114574da7fSAdrian Chadd 	int error = 0;
2124574da7fSAdrian Chadd 
213*52f24367SRui Paulo 	SLIST_FOREACH(e, &rendezvoushead, entries) {
2144574da7fSAdrian Chadd 		if (e->target.device == dev) {
2154574da7fSAdrian Chadd 			if (e->proxy.device == NULL) {
216*52f24367SRui Paulo 				SLIST_REMOVE(&rendezvoushead, e, rendezvous_entry, entries);
2174574da7fSAdrian Chadd 				free(e, M_MIIPROXY);
2184574da7fSAdrian Chadd 				return (0);
2194574da7fSAdrian Chadd 			} else {
220*52f24367SRui Paulo 				e->proxy.callback(RENDEZVOUS_DETACH, e);
221*52f24367SRui 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
237*52f24367SRui Paulo miiproxy_rendezvous_callback(enum rendezvous_op op, struct rendezvous_entry *rendezvous)
2384574da7fSAdrian Chadd {
239*52f24367SRui Paulo 	struct miiproxy_softc *sc = device_get_softc(rendezvous->proxy.device);
2404574da7fSAdrian Chadd 
2414574da7fSAdrian Chadd 	switch (op) {
242*52f24367SRui Paulo 	case RENDEZVOUS_ATTACH:
243*52f24367SRui Paulo 		sc->mdio = device_get_parent(rendezvous->target.device);
2444574da7fSAdrian Chadd 		break;
245*52f24367SRui 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
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
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
266*52f24367SRui Paulo 	 * the relevant parameters for rendezvous with the MDIO target.
2674574da7fSAdrian Chadd 	 */
2684574da7fSAdrian Chadd 	return (bus_generic_attach(dev));
2694574da7fSAdrian Chadd }
2704574da7fSAdrian Chadd 
2714574da7fSAdrian Chadd static int
2724574da7fSAdrian Chadd miiproxy_detach(device_t dev)
2734574da7fSAdrian Chadd {
2744574da7fSAdrian Chadd 
275*52f24367SRui Paulo 	rendezvous_unregister_proxy(dev);
2764574da7fSAdrian Chadd 	bus_generic_detach(dev);
2774574da7fSAdrian Chadd 	return (0);
2784574da7fSAdrian Chadd }
2794574da7fSAdrian Chadd 
2804574da7fSAdrian Chadd static int
2814574da7fSAdrian Chadd miiproxy_readreg(device_t dev, int phy, int reg)
2824574da7fSAdrian Chadd {
2834574da7fSAdrian Chadd 	struct miiproxy_softc *sc = device_get_softc(dev);
2844574da7fSAdrian Chadd 
2854574da7fSAdrian Chadd 	if (sc->mdio != NULL)
2864574da7fSAdrian Chadd 		return (MDIO_READREG(sc->mdio, phy, reg));
2874574da7fSAdrian Chadd 	return (-1);
2884574da7fSAdrian Chadd }
2894574da7fSAdrian Chadd 
2904574da7fSAdrian Chadd static int
2914574da7fSAdrian Chadd miiproxy_writereg(device_t dev, int phy, int reg, int val)
2924574da7fSAdrian Chadd {
2934574da7fSAdrian Chadd 	struct miiproxy_softc *sc = device_get_softc(dev);
2944574da7fSAdrian Chadd 
2954574da7fSAdrian Chadd 	if (sc->mdio != NULL)
2964574da7fSAdrian Chadd 		return (MDIO_WRITEREG(sc->mdio, phy, reg, val));
2974574da7fSAdrian Chadd 	return (-1);
2984574da7fSAdrian Chadd }
2994574da7fSAdrian Chadd 
3004574da7fSAdrian Chadd static void
3014574da7fSAdrian Chadd miiproxy_statchg(device_t dev)
3024574da7fSAdrian Chadd {
3034574da7fSAdrian Chadd 
3044574da7fSAdrian Chadd 	MIIBUS_STATCHG(device_get_parent(dev));
3054574da7fSAdrian Chadd }
3064574da7fSAdrian Chadd 
3074574da7fSAdrian Chadd static void
3084574da7fSAdrian Chadd miiproxy_linkchg(device_t dev)
3094574da7fSAdrian Chadd {
3104574da7fSAdrian Chadd 
3114574da7fSAdrian Chadd 	MIIBUS_LINKCHG(device_get_parent(dev));
3124574da7fSAdrian Chadd }
3134574da7fSAdrian Chadd 
3144574da7fSAdrian Chadd static void
3154574da7fSAdrian Chadd miiproxy_mediainit(device_t dev)
3164574da7fSAdrian Chadd {
3174574da7fSAdrian Chadd 
3184574da7fSAdrian Chadd 	MIIBUS_MEDIAINIT(device_get_parent(dev));
3194574da7fSAdrian Chadd }
3204574da7fSAdrian Chadd 
3214574da7fSAdrian Chadd /*
3224574da7fSAdrian Chadd  * Functions for the MDIO target device driver.
3234574da7fSAdrian Chadd  */
3244574da7fSAdrian Chadd static int
325*52f24367SRui Paulo mdioproxy_rendezvous_callback(enum rendezvous_op op, struct rendezvous_entry *rendezvous)
3264574da7fSAdrian Chadd {
3274574da7fSAdrian Chadd 	return (0);
3284574da7fSAdrian Chadd }
3294574da7fSAdrian Chadd 
3304574da7fSAdrian Chadd static void
3314574da7fSAdrian Chadd mdioproxy_identify(driver_t *driver, device_t parent)
3324574da7fSAdrian Chadd {
3334574da7fSAdrian Chadd 	device_t child;
3344574da7fSAdrian Chadd 
3354574da7fSAdrian Chadd 	if (device_find_child(parent, driver->name, -1) == NULL) {
3364574da7fSAdrian Chadd 		child = BUS_ADD_CHILD(parent, 0, driver->name, -1);
3374574da7fSAdrian Chadd 	}
3384574da7fSAdrian Chadd }
3394574da7fSAdrian Chadd 
3404574da7fSAdrian Chadd static int
3414574da7fSAdrian Chadd mdioproxy_probe(device_t dev)
3424574da7fSAdrian Chadd {
3434574da7fSAdrian Chadd 	device_set_desc(dev, "MII/MDIO proxy, MDIO side");
3444574da7fSAdrian Chadd 
3454574da7fSAdrian Chadd 	return (BUS_PROBE_SPECIFIC);
3464574da7fSAdrian Chadd }
3474574da7fSAdrian Chadd 
3484574da7fSAdrian Chadd static int
3494574da7fSAdrian Chadd mdioproxy_attach(device_t dev)
3504574da7fSAdrian Chadd {
3514574da7fSAdrian Chadd 
352*52f24367SRui Paulo 	rendezvous_register_target(dev, mdioproxy_rendezvous_callback);
3534574da7fSAdrian Chadd 	return (bus_generic_attach(dev));
3544574da7fSAdrian Chadd }
3554574da7fSAdrian Chadd 
3564574da7fSAdrian Chadd static int
3574574da7fSAdrian Chadd mdioproxy_detach(device_t dev)
3584574da7fSAdrian Chadd {
3594574da7fSAdrian Chadd 
360*52f24367SRui 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
3704574da7fSAdrian Chadd mii_attach_proxy(device_t dev)
3714574da7fSAdrian Chadd {
3724574da7fSAdrian Chadd 	struct miiproxy_softc *sc;
3734574da7fSAdrian Chadd 	int		error;
3744574da7fSAdrian Chadd 	const char	*name;
3754574da7fSAdrian Chadd 	device_t	miiproxy;
3764574da7fSAdrian Chadd 
3774574da7fSAdrian Chadd 	if (resource_string_value(device_get_name(dev),
3784574da7fSAdrian Chadd 	    device_get_unit(dev), "mdio", &name) != 0) {
3794574da7fSAdrian Chadd 	    	if (bootverbose)
3804574da7fSAdrian Chadd 			printf("mii_attach_proxy: not attaching, no mdio"
3814574da7fSAdrian Chadd 			    " device hint for %s\n", device_get_nameunit(dev));
3824574da7fSAdrian Chadd 		return (NULL);
3834574da7fSAdrian Chadd 	}
3844574da7fSAdrian Chadd 
3854574da7fSAdrian Chadd 	miiproxy = device_add_child(dev, miiproxy_driver.name, -1);
3864574da7fSAdrian Chadd 	error = bus_generic_attach(dev);
3874574da7fSAdrian Chadd 	if (error != 0) {
3884574da7fSAdrian Chadd 		device_printf(dev, "can't attach miiproxy\n");
3894574da7fSAdrian Chadd 		return (NULL);
3904574da7fSAdrian Chadd 	}
3914574da7fSAdrian Chadd 	sc = device_get_softc(miiproxy);
3924574da7fSAdrian Chadd 	sc->parent = dev;
3934574da7fSAdrian Chadd 	sc->proxy = miiproxy;
394*52f24367SRui Paulo 	if (rendezvous_register_proxy(miiproxy, name, miiproxy_rendezvous_callback) != 0) {
3954574da7fSAdrian Chadd 		device_printf(dev, "can't attach proxy\n");
3964574da7fSAdrian Chadd 		return (NULL);
3974574da7fSAdrian Chadd 	}
3984574da7fSAdrian Chadd 	device_printf(miiproxy, "attached to target %s\n", device_get_nameunit(sc->mdio));
3994574da7fSAdrian Chadd 	return (miiproxy);
4004574da7fSAdrian Chadd }
4014574da7fSAdrian Chadd 
4024574da7fSAdrian Chadd static device_method_t miiproxy_methods[] = {
4034574da7fSAdrian Chadd 	/* device interface */
4044574da7fSAdrian Chadd 	DEVMETHOD(device_probe,		miiproxy_probe),
4054574da7fSAdrian Chadd 	DEVMETHOD(device_attach,	miiproxy_attach),
4064574da7fSAdrian Chadd 	DEVMETHOD(device_detach,	miiproxy_detach),
4074574da7fSAdrian Chadd 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
4084574da7fSAdrian Chadd 
4094574da7fSAdrian Chadd 	/* MII interface */
4104574da7fSAdrian Chadd 	DEVMETHOD(miibus_readreg,	miiproxy_readreg),
4114574da7fSAdrian Chadd 	DEVMETHOD(miibus_writereg,	miiproxy_writereg),
4124574da7fSAdrian Chadd 	DEVMETHOD(miibus_statchg,	miiproxy_statchg),
4134574da7fSAdrian Chadd 	DEVMETHOD(miibus_linkchg,	miiproxy_linkchg),
4144574da7fSAdrian Chadd 	DEVMETHOD(miibus_mediainit,	miiproxy_mediainit),
4154574da7fSAdrian Chadd 
4164574da7fSAdrian Chadd 	DEVMETHOD_END
4174574da7fSAdrian Chadd };
4184574da7fSAdrian Chadd 
4194574da7fSAdrian Chadd static device_method_t mdioproxy_methods[] = {
4204574da7fSAdrian Chadd 	/* device interface */
4214574da7fSAdrian Chadd 	DEVMETHOD(device_identify,	mdioproxy_identify),
4224574da7fSAdrian Chadd 	DEVMETHOD(device_probe,		mdioproxy_probe),
4234574da7fSAdrian Chadd 	DEVMETHOD(device_attach,	mdioproxy_attach),
4244574da7fSAdrian Chadd 	DEVMETHOD(device_detach,	mdioproxy_detach),
4254574da7fSAdrian Chadd 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
4264574da7fSAdrian Chadd 
4274574da7fSAdrian Chadd 	DEVMETHOD_END
4284574da7fSAdrian Chadd };
4294574da7fSAdrian Chadd 
4304574da7fSAdrian Chadd DEFINE_CLASS_0(miiproxy, miiproxy_driver, miiproxy_methods,
4314574da7fSAdrian Chadd     sizeof(struct miiproxy_softc));
4324574da7fSAdrian Chadd DEFINE_CLASS_0(mdioproxy, mdioproxy_driver, mdioproxy_methods,
4334574da7fSAdrian Chadd     sizeof(struct mdioproxy_softc));
4344574da7fSAdrian Chadd 
4354574da7fSAdrian Chadd devclass_t miiproxy_devclass;
4364574da7fSAdrian Chadd static devclass_t mdioproxy_devclass;
4374574da7fSAdrian Chadd 
4384574da7fSAdrian Chadd DRIVER_MODULE(mdioproxy, mdio, mdioproxy_driver, mdioproxy_devclass, 0, 0);
4394574da7fSAdrian Chadd DRIVER_MODULE(miibus, miiproxy, miibus_driver, miibus_devclass, 0, 0);
4404574da7fSAdrian Chadd MODULE_VERSION(miiproxy, 1);
4414574da7fSAdrian Chadd MODULE_DEPEND(miiproxy, miibus, 1, 1, 1);
442