xref: /freebsd/sys/dev/etherswitch/miiproxy.c (revision 42726c2fc23a463a1c43cab1bf9cca158c81a0f3)
14574da7fSAdrian Chadd /*-
2718cf2ccSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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  * $FreeBSD$
294574da7fSAdrian Chadd  */
304574da7fSAdrian Chadd 
314574da7fSAdrian Chadd #include <sys/param.h>
324574da7fSAdrian Chadd #include <sys/bus.h>
334574da7fSAdrian Chadd #include <sys/kernel.h>
34104dc214SGleb Smirnoff #include <sys/malloc.h>
354574da7fSAdrian Chadd #include <sys/module.h>
364574da7fSAdrian Chadd #include <sys/socket.h>
374574da7fSAdrian Chadd #include <sys/sockio.h>
384574da7fSAdrian Chadd #include <sys/systm.h>
394574da7fSAdrian Chadd 
404574da7fSAdrian Chadd #include <net/if.h>
414574da7fSAdrian Chadd #include <net/if_media.h>
424574da7fSAdrian Chadd 
434574da7fSAdrian Chadd #include <dev/etherswitch/miiproxy.h>
444574da7fSAdrian Chadd #include <dev/mii/mii.h>
454574da7fSAdrian Chadd #include <dev/mii/miivar.h>
464574da7fSAdrian Chadd 
474574da7fSAdrian Chadd #include "mdio_if.h"
484574da7fSAdrian Chadd #include "miibus_if.h"
494574da7fSAdrian Chadd 
504574da7fSAdrian Chadd 
514574da7fSAdrian Chadd MALLOC_DECLARE(M_MIIPROXY);
524574da7fSAdrian Chadd MALLOC_DEFINE(M_MIIPROXY, "miiproxy", "miiproxy data structures");
534574da7fSAdrian Chadd 
544574da7fSAdrian Chadd driver_t miiproxy_driver;
554574da7fSAdrian Chadd driver_t mdioproxy_driver;
564574da7fSAdrian Chadd 
574574da7fSAdrian Chadd struct miiproxy_softc {
584574da7fSAdrian Chadd 	device_t	parent;
594574da7fSAdrian Chadd 	device_t	proxy;
604574da7fSAdrian Chadd 	device_t	mdio;
614574da7fSAdrian Chadd };
624574da7fSAdrian Chadd 
634574da7fSAdrian Chadd struct mdioproxy_softc {
644574da7fSAdrian Chadd };
654574da7fSAdrian Chadd 
664574da7fSAdrian Chadd /*
6752f24367SRui Paulo  * The rendezvous data structures and functions allow two device endpoints to
684574da7fSAdrian Chadd  * match up, so that the proxy endpoint can be associated with a target
694574da7fSAdrian Chadd  * endpoint.  The proxy has to know the device name of the target that it
7052f24367SRui Paulo  * wants to associate with, for example through a hint.  The rendezvous code
714574da7fSAdrian Chadd  * makes no assumptions about the devices that want to meet.
724574da7fSAdrian Chadd  */
7352f24367SRui Paulo struct rendezvous_entry;
744574da7fSAdrian Chadd 
7552f24367SRui Paulo enum rendezvous_op {
7652f24367SRui Paulo 	RENDEZVOUS_ATTACH,
7752f24367SRui Paulo 	RENDEZVOUS_DETACH
784574da7fSAdrian Chadd };
794574da7fSAdrian Chadd 
8052f24367SRui Paulo typedef int (*rendezvous_callback_t)(enum rendezvous_op,
8152f24367SRui Paulo     struct rendezvous_entry *);
824574da7fSAdrian Chadd 
8352f24367SRui Paulo static SLIST_HEAD(rendezvoushead, rendezvous_entry) rendezvoushead =
8452f24367SRui Paulo     SLIST_HEAD_INITIALIZER(rendezvoushead);
854574da7fSAdrian Chadd 
8652f24367SRui Paulo struct rendezvous_endpoint {
874574da7fSAdrian Chadd 	device_t		device;
884574da7fSAdrian Chadd 	const char		*name;
8952f24367SRui Paulo 	rendezvous_callback_t	callback;
904574da7fSAdrian Chadd };
914574da7fSAdrian Chadd 
9252f24367SRui Paulo struct rendezvous_entry {
9352f24367SRui Paulo 	SLIST_ENTRY(rendezvous_entry)	entries;
9452f24367SRui Paulo 	struct rendezvous_endpoint	proxy;
9552f24367SRui Paulo 	struct rendezvous_endpoint	target;
964574da7fSAdrian Chadd };
974574da7fSAdrian Chadd 
984574da7fSAdrian Chadd /*
994574da7fSAdrian Chadd  * Call the callback routines for both the proxy and the target.  If either
1004574da7fSAdrian Chadd  * returns an error, undo the attachment.
1014574da7fSAdrian Chadd  */
1024574da7fSAdrian Chadd static int
10352f24367SRui Paulo rendezvous_attach(struct rendezvous_entry *e, struct rendezvous_endpoint *ep)
1044574da7fSAdrian Chadd {
1054574da7fSAdrian Chadd 	int error;
1064574da7fSAdrian Chadd 
10752f24367SRui Paulo 	error = e->proxy.callback(RENDEZVOUS_ATTACH, e);
1084574da7fSAdrian Chadd 	if (error == 0) {
10952f24367SRui Paulo 		error = e->target.callback(RENDEZVOUS_ATTACH, e);
1104574da7fSAdrian Chadd 		if (error != 0) {
11152f24367SRui Paulo 			e->proxy.callback(RENDEZVOUS_DETACH, e);
1124574da7fSAdrian Chadd 			ep->device = NULL;
1134574da7fSAdrian Chadd 			ep->callback = NULL;
1144574da7fSAdrian Chadd 		}
1154574da7fSAdrian Chadd 	}
1164574da7fSAdrian Chadd 	return (error);
1174574da7fSAdrian Chadd }
1184574da7fSAdrian Chadd 
1194574da7fSAdrian Chadd /*
12052f24367SRui Paulo  * Create an entry for the proxy in the rendezvous list.  The name parameter
1214574da7fSAdrian Chadd  * indicates the name of the device that is the target endpoint for this
12252f24367SRui Paulo  * rendezvous.  The callback will be invoked as soon as the target is
1234574da7fSAdrian Chadd  * registered: either immediately if the target registered itself earlier,
1244574da7fSAdrian Chadd  * or once the target registers.  Returns ENXIO if the target has not yet
1254574da7fSAdrian Chadd  * registered.
1264574da7fSAdrian Chadd  */
1274574da7fSAdrian Chadd static int
12852f24367SRui Paulo rendezvous_register_proxy(device_t dev, const char *name,
12952f24367SRui Paulo     rendezvous_callback_t callback)
1304574da7fSAdrian Chadd {
13152f24367SRui Paulo 	struct rendezvous_entry *e;
1324574da7fSAdrian Chadd 
1334574da7fSAdrian Chadd 	KASSERT(callback != NULL, ("callback must be set"));
13452f24367SRui Paulo 	SLIST_FOREACH(e, &rendezvoushead, entries) {
1354574da7fSAdrian Chadd 		if (strcmp(name, e->target.name) == 0) {
1364574da7fSAdrian Chadd 			/* the target is already attached */
1374574da7fSAdrian Chadd 			e->proxy.name = device_get_nameunit(dev);
1384574da7fSAdrian Chadd 		    	e->proxy.device = dev;
1394574da7fSAdrian Chadd 		    	e->proxy.callback = callback;
14052f24367SRui Paulo 			return (rendezvous_attach(e, &e->proxy));
1414574da7fSAdrian Chadd 		}
1424574da7fSAdrian Chadd 	}
1434574da7fSAdrian Chadd 	e = malloc(sizeof(*e), M_MIIPROXY, M_WAITOK | M_ZERO);
1444574da7fSAdrian Chadd 	e->proxy.name = device_get_nameunit(dev);
1454574da7fSAdrian Chadd     	e->proxy.device = dev;
1464574da7fSAdrian Chadd     	e->proxy.callback = callback;
1474574da7fSAdrian Chadd 	e->target.name = name;
14852f24367SRui Paulo 	SLIST_INSERT_HEAD(&rendezvoushead, e, entries);
1494574da7fSAdrian Chadd 	return (ENXIO);
1504574da7fSAdrian Chadd }
1514574da7fSAdrian Chadd 
1524574da7fSAdrian Chadd /*
15352f24367SRui Paulo  * Create an entry in the rendezvous list for the target.
1544574da7fSAdrian Chadd  * Returns ENXIO if the proxy has not yet registered.
1554574da7fSAdrian Chadd  */
1564574da7fSAdrian Chadd static int
15752f24367SRui Paulo rendezvous_register_target(device_t dev, rendezvous_callback_t callback)
1584574da7fSAdrian Chadd {
15952f24367SRui Paulo 	struct rendezvous_entry *e;
1604574da7fSAdrian Chadd 	const char *name;
1614574da7fSAdrian Chadd 
1624574da7fSAdrian Chadd 	KASSERT(callback != NULL, ("callback must be set"));
1634574da7fSAdrian Chadd 	name = device_get_nameunit(dev);
16452f24367SRui Paulo 	SLIST_FOREACH(e, &rendezvoushead, entries) {
1654574da7fSAdrian Chadd 		if (strcmp(name, e->target.name) == 0) {
1664574da7fSAdrian Chadd 			e->target.device = dev;
1674574da7fSAdrian Chadd 			e->target.callback = callback;
16852f24367SRui Paulo 			return (rendezvous_attach(e, &e->target));
1694574da7fSAdrian Chadd 		}
1704574da7fSAdrian Chadd 	}
1714574da7fSAdrian Chadd 	e = malloc(sizeof(*e), M_MIIPROXY, M_WAITOK | M_ZERO);
1724574da7fSAdrian Chadd 	e->target.name = name;
1734574da7fSAdrian Chadd     	e->target.device = dev;
1744574da7fSAdrian Chadd 	e->target.callback = callback;
17552f24367SRui Paulo 	SLIST_INSERT_HEAD(&rendezvoushead, e, entries);
1764574da7fSAdrian Chadd 	return (ENXIO);
1774574da7fSAdrian Chadd }
1784574da7fSAdrian Chadd 
1794574da7fSAdrian Chadd /*
1804574da7fSAdrian Chadd  * Remove the registration for the proxy.
1814574da7fSAdrian Chadd  */
1824574da7fSAdrian Chadd static int
18352f24367SRui Paulo rendezvous_unregister_proxy(device_t dev)
1844574da7fSAdrian Chadd {
18552f24367SRui Paulo 	struct rendezvous_entry *e;
1864574da7fSAdrian Chadd 	int error = 0;
1874574da7fSAdrian Chadd 
18852f24367SRui Paulo 	SLIST_FOREACH(e, &rendezvoushead, entries) {
1894574da7fSAdrian Chadd 		if (e->proxy.device == dev) {
1904574da7fSAdrian Chadd 			if (e->target.device == NULL) {
19152f24367SRui Paulo 				SLIST_REMOVE(&rendezvoushead, e, rendezvous_entry, entries);
1924574da7fSAdrian Chadd 				free(e, M_MIIPROXY);
1934574da7fSAdrian Chadd 				return (0);
1944574da7fSAdrian Chadd 			} else {
19552f24367SRui Paulo 				e->proxy.callback(RENDEZVOUS_DETACH, e);
19652f24367SRui Paulo 				e->target.callback(RENDEZVOUS_DETACH, e);
1974574da7fSAdrian Chadd 			}
1984574da7fSAdrian Chadd 			e->proxy.device = NULL;
1994574da7fSAdrian Chadd 			e->proxy.callback = NULL;
2004574da7fSAdrian Chadd 			return (error);
2014574da7fSAdrian Chadd 		}
2024574da7fSAdrian Chadd 	}
2034574da7fSAdrian Chadd 	return (ENOENT);
2044574da7fSAdrian Chadd }
2054574da7fSAdrian Chadd 
2064574da7fSAdrian Chadd /*
2074574da7fSAdrian Chadd  * Remove the registration for the target.
2084574da7fSAdrian Chadd  */
2094574da7fSAdrian Chadd static int
21052f24367SRui Paulo rendezvous_unregister_target(device_t dev)
2114574da7fSAdrian Chadd {
21252f24367SRui Paulo 	struct rendezvous_entry *e;
2134574da7fSAdrian Chadd 	int error = 0;
2144574da7fSAdrian Chadd 
21552f24367SRui Paulo 	SLIST_FOREACH(e, &rendezvoushead, entries) {
2164574da7fSAdrian Chadd 		if (e->target.device == dev) {
2174574da7fSAdrian Chadd 			if (e->proxy.device == NULL) {
21852f24367SRui Paulo 				SLIST_REMOVE(&rendezvoushead, e, rendezvous_entry, entries);
2194574da7fSAdrian Chadd 				free(e, M_MIIPROXY);
2204574da7fSAdrian Chadd 				return (0);
2214574da7fSAdrian Chadd 			} else {
22252f24367SRui Paulo 				e->proxy.callback(RENDEZVOUS_DETACH, e);
22352f24367SRui Paulo 				e->target.callback(RENDEZVOUS_DETACH, e);
2244574da7fSAdrian Chadd 			}
2254574da7fSAdrian Chadd 			e->target.device = NULL;
2264574da7fSAdrian Chadd 			e->target.callback = NULL;
2274574da7fSAdrian Chadd 			return (error);
2284574da7fSAdrian Chadd 		}
2294574da7fSAdrian Chadd 	}
2304574da7fSAdrian Chadd 	return (ENOENT);
2314574da7fSAdrian Chadd }
2324574da7fSAdrian Chadd 
2334574da7fSAdrian Chadd /*
2344574da7fSAdrian Chadd  * Functions of the proxy that is interposed between the ethernet interface
2354574da7fSAdrian Chadd  * driver and the miibus device.
2364574da7fSAdrian Chadd  */
2374574da7fSAdrian Chadd 
2384574da7fSAdrian Chadd static int
23952f24367SRui Paulo miiproxy_rendezvous_callback(enum rendezvous_op op, struct rendezvous_entry *rendezvous)
2404574da7fSAdrian Chadd {
24152f24367SRui Paulo 	struct miiproxy_softc *sc = device_get_softc(rendezvous->proxy.device);
2424574da7fSAdrian Chadd 
2434574da7fSAdrian Chadd 	switch (op) {
24452f24367SRui Paulo 	case RENDEZVOUS_ATTACH:
24552f24367SRui Paulo 		sc->mdio = device_get_parent(rendezvous->target.device);
2464574da7fSAdrian Chadd 		break;
24752f24367SRui Paulo 	case RENDEZVOUS_DETACH:
2484574da7fSAdrian Chadd 		sc->mdio = NULL;
2494574da7fSAdrian Chadd 		break;
2504574da7fSAdrian Chadd 	}
2514574da7fSAdrian Chadd 	return (0);
2524574da7fSAdrian Chadd }
2534574da7fSAdrian Chadd 
2544574da7fSAdrian Chadd static int
2554574da7fSAdrian Chadd miiproxy_probe(device_t dev)
2564574da7fSAdrian Chadd {
2574574da7fSAdrian Chadd 	device_set_desc(dev, "MII/MDIO proxy, MII side");
2584574da7fSAdrian Chadd 
2594574da7fSAdrian Chadd 	return (BUS_PROBE_SPECIFIC);
2604574da7fSAdrian Chadd }
2614574da7fSAdrian Chadd 
2624574da7fSAdrian Chadd static int
2634574da7fSAdrian Chadd miiproxy_attach(device_t dev)
2644574da7fSAdrian Chadd {
2654574da7fSAdrian Chadd 
2664574da7fSAdrian Chadd 	/*
2674574da7fSAdrian Chadd 	 * The ethernet interface needs to call mii_attach_proxy() to pass
26852f24367SRui Paulo 	 * the relevant parameters for rendezvous with the MDIO target.
2694574da7fSAdrian Chadd 	 */
2704574da7fSAdrian Chadd 	return (bus_generic_attach(dev));
2714574da7fSAdrian Chadd }
2724574da7fSAdrian Chadd 
2734574da7fSAdrian Chadd static int
2744574da7fSAdrian Chadd miiproxy_detach(device_t dev)
2754574da7fSAdrian Chadd {
2764574da7fSAdrian Chadd 
27752f24367SRui Paulo 	rendezvous_unregister_proxy(dev);
2784574da7fSAdrian Chadd 	bus_generic_detach(dev);
2794574da7fSAdrian Chadd 	return (0);
2804574da7fSAdrian Chadd }
2814574da7fSAdrian Chadd 
2824574da7fSAdrian Chadd static int
2834574da7fSAdrian Chadd miiproxy_readreg(device_t dev, int phy, int reg)
2844574da7fSAdrian Chadd {
2854574da7fSAdrian Chadd 	struct miiproxy_softc *sc = device_get_softc(dev);
2864574da7fSAdrian Chadd 
2874574da7fSAdrian Chadd 	if (sc->mdio != NULL)
2884574da7fSAdrian Chadd 		return (MDIO_READREG(sc->mdio, phy, reg));
2894574da7fSAdrian Chadd 	return (-1);
2904574da7fSAdrian Chadd }
2914574da7fSAdrian Chadd 
2924574da7fSAdrian Chadd static int
2934574da7fSAdrian Chadd miiproxy_writereg(device_t dev, int phy, int reg, int val)
2944574da7fSAdrian Chadd {
2954574da7fSAdrian Chadd 	struct miiproxy_softc *sc = device_get_softc(dev);
2964574da7fSAdrian Chadd 
2974574da7fSAdrian Chadd 	if (sc->mdio != NULL)
2984574da7fSAdrian Chadd 		return (MDIO_WRITEREG(sc->mdio, phy, reg, val));
2994574da7fSAdrian Chadd 	return (-1);
3004574da7fSAdrian Chadd }
3014574da7fSAdrian Chadd 
3024574da7fSAdrian Chadd static void
3034574da7fSAdrian Chadd miiproxy_statchg(device_t dev)
3044574da7fSAdrian Chadd {
3054574da7fSAdrian Chadd 
3064574da7fSAdrian Chadd 	MIIBUS_STATCHG(device_get_parent(dev));
3074574da7fSAdrian Chadd }
3084574da7fSAdrian Chadd 
3094574da7fSAdrian Chadd static void
3104574da7fSAdrian Chadd miiproxy_linkchg(device_t dev)
3114574da7fSAdrian Chadd {
3124574da7fSAdrian Chadd 
3134574da7fSAdrian Chadd 	MIIBUS_LINKCHG(device_get_parent(dev));
3144574da7fSAdrian Chadd }
3154574da7fSAdrian Chadd 
3164574da7fSAdrian Chadd static void
3174574da7fSAdrian Chadd miiproxy_mediainit(device_t dev)
3184574da7fSAdrian Chadd {
3194574da7fSAdrian Chadd 
3204574da7fSAdrian Chadd 	MIIBUS_MEDIAINIT(device_get_parent(dev));
3214574da7fSAdrian Chadd }
3224574da7fSAdrian Chadd 
3234574da7fSAdrian Chadd /*
3244574da7fSAdrian Chadd  * Functions for the MDIO target device driver.
3254574da7fSAdrian Chadd  */
3264574da7fSAdrian Chadd static int
32752f24367SRui Paulo mdioproxy_rendezvous_callback(enum rendezvous_op op, struct rendezvous_entry *rendezvous)
3284574da7fSAdrian Chadd {
3294574da7fSAdrian Chadd 	return (0);
3304574da7fSAdrian Chadd }
3314574da7fSAdrian Chadd 
3324574da7fSAdrian Chadd static void
3334574da7fSAdrian Chadd mdioproxy_identify(driver_t *driver, device_t parent)
3344574da7fSAdrian Chadd {
3354574da7fSAdrian Chadd 	if (device_find_child(parent, driver->name, -1) == NULL) {
336683ca803SJohn Baldwin 		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 
35252f24367SRui 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 
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
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;
39452f24367SRui 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 
435*42726c2fSJohn Baldwin DRIVER_MODULE(mdioproxy, mdio, mdioproxy_driver, 0, 0);
4363e38757dSJohn Baldwin DRIVER_MODULE(miibus, miiproxy, miibus_driver, 0, 0);
4374574da7fSAdrian Chadd MODULE_VERSION(miiproxy, 1);
4384574da7fSAdrian Chadd MODULE_DEPEND(miiproxy, miibus, 1, 1, 1);
439