xref: /freebsd/sys/dev/etherswitch/miiproxy.c (revision 18250ec6c089c0c50cbd9fd87d78e03ff89916df)
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