Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 21 Jan 2012 00:08:34 +0100
From:      Stefan Bethke <stb@lassitu.de>
To:        FreeBSD-arch <freebsd-arch@freebsd.org>
Subject:   Re: Extending sys/dev/mii
Message-ID:  <66DDA0A2-F878-43FF-8824-54868F493B18@lassitu.de>
In-Reply-To: <20120111193738.GB44286@alchemy.franken.de>
References:  <8D025847-4BE4-4B2C-87D7-97E72CC9D325@lassitu.de> <20120104215930.GM90831@alchemy.franken.de> <47ABA638-7E08-4350-A03C-3D4A23BF2D7E@lassitu.de> <1763C3FF-1EA0-4DC0-891D-63816EBF4A04@lassitu.de> <20120106182756.GA88161@alchemy.franken.de> <95372FB3-406F-46C2-8684-4FDB672D9FCF@lassitu.de> <20120106214741.GB88161@alchemy.franken.de> <F60B2B70-049F-4497-BBA8-3C421088C1EA@lassitu.de> <20120108130039.GG88161@alchemy.franken.de> <23477898-8D85-498C-8E30-192810BD68A8@lassitu.de> <20120111193738.GB44286@alchemy.franken.de>

next in thread | previous in thread | raw e-mail | index | archive | help

--Apple-Mail=_213E4B8A-6009-4FF8-A23A-C6A4E1D4CE37
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain;
	charset=us-ascii

Am 11.01.2012 um 20:37 schrieb Marius Strobl:

> Okay, I suggest to postpone this discussion until then. For the
> scenario when mdiobus is the parent of miibus I see no technical
> need to change miibus to support what you want to do, just implement
> the miibus_if in mdiobus and redirect it to the device_t of the
> MAC there. Moreover, that way the hack to sidestep newbus is contained
> in the layer that actually needs it and not scattered over multiple
> frameworks.

I've posted to -net a patch that implements a workaround along those =
lines.  It solves two issues: talking to two upstream devices, and =
providing a proper attachment for miibus.

There's a number of things that made this harder than I would have =
liked:
- miibus has a funny way of attaching to it's parent.  Making the parent =
a bus that automatically attaches matching children does not lead to =
good results.
- miibus uses it's parents ivars.  To clarify: device_get_ivars get's a =
devices ivars, but those are owned by the parent; the bus uses =
device_[gs]et_ivars(9) to manipulate it's own private per-child data =
storage.  The device must not manipulate them.  I believe those =
variables can be moved to mii_data.
- miibus makes assumptions about it's children, namely that they have =
specific softc's and that they provide callbacks outside of the newbus =
method mechanism
- miibus assumes that all devices attached to that mdio have certain =
registers that have certain bits set or cleared
- miibus calls it's parent methods and two explicit callbacks, plus =
various calls into the interface management code.

The second problem is that there's currently no way to express a =
dependency between two devices other than a parent-child relationship.   =
I would be interested to learn why this appears to be so uncommon that I =
could not find any discussion of such a feature.  Has it really never =
before come up?

Leaving aside the miibus issue, the newbus problem is that the ethernet =
driver (which is attached to some bus) needs to associate with some =
other driver that might not be in it's vincinity, in particular neither =
it's parent nor one of it's children.  Compounding the problem is that =
there is no way to express an attachment ordering constraint so that the =
ethernet driver is only attached once the required mdio driver has =
attached.


Stefan

--=20
Stefan Bethke <stb@lassitu.de>   Fon +49 151 14070811



--Apple-Mail=_213E4B8A-6009-4FF8-A23A-C6A4E1D4CE37
Content-Disposition: attachment;
	filename=miiproxy.patch
Content-Type: application/octet-stream;
	name="miiproxy.patch"
Content-Transfer-Encoding: 7bit

diff --git a/sys/dev/etherswitch/mdio.c b/sys/dev/etherswitch/mdio.c
new file mode 100644
index 0000000..9302075
--- /dev/null
+++ b/sys/dev/etherswitch/mdio.c
@@ -0,0 +1,156 @@
+/*-
+ * Copyright (c) 2011-2012 Stefan Bethke.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/systm.h>
+
+#include <dev/etherswitch/mdio.h>
+
+#include "mdio_if.h"
+
+static void
+mdio_identify(driver_t *driver, device_t parent)
+{
+	if (device_find_child(parent, mdio_driver.name, -1) == NULL)
+		BUS_ADD_CHILD(parent, 0, mdio_driver.name, -1);
+}
+
+static int
+mdio_probe(device_t dev)
+{
+	device_set_desc(dev, "MDIO");
+
+	return (BUS_PROBE_SPECIFIC);
+}
+
+static int
+mdio_attach(device_t dev)
+{
+	bus_generic_probe(dev);
+	bus_enumerate_hinted_children(dev);
+	return (bus_generic_attach(dev));
+}
+
+static int
+mdio_detach(device_t dev)
+{
+	bus_generic_detach(dev);
+	return (0);
+}
+
+static int
+mdio_readreg(device_t dev, int phy, int reg)
+{
+	return MDIO_READREG(device_get_parent(dev), phy, reg);
+}
+
+static int
+mdio_writereg(device_t dev, int phy, int reg, int val)
+{
+	return MDIO_WRITEREG(device_get_parent(dev), phy, reg, val);
+}
+
+static int
+mdio_print_child(device_t dev, device_t child)
+{
+	int retval;
+
+	retval = bus_print_child_header(dev, child);
+	retval += bus_print_child_footer(dev, child);
+
+	return (retval);
+}
+
+static int
+mdio_read_ivar(device_t dev, device_t child __unused, int which,
+    uintptr_t *result)
+{
+	struct miibus_ivars *ivars;
+
+	ivars = device_get_ivars(dev);
+	switch (which) {
+	default:
+		return (ENOENT);
+	}
+	return (0);
+}
+
+static int
+mdio_child_pnpinfo_str(device_t dev __unused, device_t child, char *buf,
+    size_t buflen)
+{
+	buf[0] = '\0';
+	return (0);
+}
+
+static int
+mdio_child_location_str(device_t dev __unused, device_t child, char *buf,
+    size_t buflen)
+{
+	buf[0] = '\0';
+	return (0);
+}
+
+static void
+mdio_hinted_child(device_t dev, const char *name, int unit)
+{
+	device_add_child(dev, name, unit);
+}
+
+static device_method_t mdio_methods[] = {
+	/* device interface */
+	DEVMETHOD(device_identify,	mdio_identify),
+	DEVMETHOD(device_probe,		mdio_probe),
+	DEVMETHOD(device_attach,	mdio_attach),
+	DEVMETHOD(device_detach,	mdio_detach),
+	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
+
+	/* bus interface */
+	DEVMETHOD(bus_print_child,	mdio_print_child),
+	DEVMETHOD(bus_read_ivar,	mdio_read_ivar),
+	DEVMETHOD(bus_child_pnpinfo_str, mdio_child_pnpinfo_str),
+	DEVMETHOD(bus_child_location_str, mdio_child_location_str),
+	DEVMETHOD(bus_add_child,	device_add_child_ordered),
+	DEVMETHOD(bus_hinted_child,	mdio_hinted_child),
+
+	/* MDIO access */
+	DEVMETHOD(mdio_readreg,		mdio_readreg),
+	DEVMETHOD(mdio_writereg,	mdio_writereg),
+
+	DEVMETHOD_END
+};
+
+driver_t mdio_driver = {
+	"mdio",
+	mdio_methods,
+	0
+};
+
+devclass_t mdio_devclass;
+
diff --git a/sys/dev/etherswitch/mdio.h b/sys/dev/etherswitch/mdio.h
new file mode 100644
index 0000000..52eddbd
--- /dev/null
+++ b/sys/dev/etherswitch/mdio.h
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2011-2012 Stefan Bethke.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_MII_MDIO_H_
+#define	_DEV_MII_MDIO_H_
+
+extern driver_t mdio_driver;
+extern devclass_t mdio_devclass;
+
+#endif
diff --git a/sys/dev/etherswitch/mdio_if.m b/sys/dev/etherswitch/mdio_if.m
new file mode 100644
index 0000000..9aedd92
--- /dev/null
+++ b/sys/dev/etherswitch/mdio_if.m
@@ -0,0 +1,24 @@
+# $FreeBSD$
+
+#include <sys/bus.h>
+
+INTERFACE mdio;
+
+#
+# Read register from device on MDIO bus
+#
+METHOD int readreg {
+	device_t		dev;
+	int			phy;
+	int			reg;
+};
+
+#
+# Write register to device on MDIO bus
+#
+METHOD int writereg {
+	device_t		dev;
+	int			phy;
+	int			reg;
+	int			val;
+};
diff --git a/sys/dev/etherswitch/miiproxy.c b/sys/dev/etherswitch/miiproxy.c
new file mode 100644
index 0000000..2791082
--- /dev/null
+++ b/sys/dev/etherswitch/miiproxy.c
@@ -0,0 +1,437 @@
+/*-
+ * Copyright (c) 2011-2012 Stefan Bethke.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/systm.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+
+#include <dev/etherswitch/miiproxy.h>
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include "mdio_if.h"
+#include "miibus_if.h"
+
+
+MALLOC_DECLARE(M_MIIPROXY);
+MALLOC_DEFINE(M_MIIPROXY, "miiproxy", "miiproxy data structures");
+
+driver_t miiproxy_driver;
+driver_t mdioproxy_driver;
+
+struct miiproxy_softc {
+	device_t	parent;
+	device_t	proxy;
+	device_t	mdio;
+	miiproxy_attach_callback_t	attach_callback;
+	void		*attach_arg;
+};
+
+struct mdioproxy_softc {
+};
+
+/*
+ * The rendevous data structures and functions allow two device endpoints to
+ * match up, so that the proxy endpoint can be associated with a target
+ * endpoint.  The proxy has to know the device name of the target that it
+ * wants to associate with, for example through a hint.  The rendevous code
+ * makes no assumptions about the devices that want to meet.
+ */
+struct rendevous_entry;
+
+enum rendevous_op {
+	RENDEVOUS_ATTACH,
+	RENDEVOUS_DETACH
+};
+
+typedef int (*rendevous_callback_t)(enum rendevous_op,
+    struct rendevous_entry *);
+
+static SLIST_HEAD(rendevoushead, rendevous_entry) rendevoushead =
+    SLIST_HEAD_INITIALIZER(rendevoushead);
+
+struct rendevous_endpoint {
+	device_t		device;
+	const char		*name;
+	rendevous_callback_t	callback;
+};
+
+struct rendevous_entry {
+	SLIST_ENTRY(rendevous_entry)	entries;
+	struct rendevous_endpoint	proxy;
+	struct rendevous_endpoint	target;
+};
+
+/*
+ * Call the callback routines for both the proxy and the target.  If either
+ * returns an error, undo the attachment.
+ */
+static int
+rendevous_attach(struct rendevous_entry *e, struct rendevous_endpoint *ep)
+{
+	int error;
+	
+	error = e->proxy.callback(RENDEVOUS_ATTACH, e);
+	if (error == 0)
+		error = e->target.callback(RENDEVOUS_ATTACH, e);
+	if (error != 0) {
+		e->proxy.callback(RENDEVOUS_DETACH, e);
+		ep->device = NULL;
+		ep->callback = NULL;
+	}
+	return (error);
+}
+
+/*
+ * Create an entry for the proxy in the rendevous list.  The name parameter
+ * indicates the name of the device that is the target endpoint for this
+ * rendevous.  The callback will be invoked as soon as the target is
+ * registered: either immediately if the target registered itself earlier,
+ * or once the target registers.
+ */
+static int
+rendevous_register_proxy(device_t dev, const char *name,
+    rendevous_callback_t callback)
+{
+	struct rendevous_entry *e;
+
+	KASSERT(callback != NULL, ("callback must not be NULL"));
+	SLIST_FOREACH(e, &rendevoushead, entries) {
+		if (strcmp(name, e->target.name) == 0) {
+			/* the target is already attached */
+		    	e->proxy.name = device_get_nameunit(dev);
+		    	e->proxy.device = dev;
+		    	e->proxy.callback = callback;
+			return (rendevous_attach(e, &e->proxy));
+		}
+	}
+	e = malloc(sizeof(*e), M_MIIPROXY, M_WAITOK | M_ZERO);
+    	e->proxy.name = device_get_nameunit(dev);
+    	e->proxy.device = dev;
+    	e->proxy.callback = callback;
+	e->target.name = name;
+	SLIST_INSERT_HEAD(&rendevoushead, e, entries);
+	return (0);
+}
+
+/*
+ * Create an entry in the rendevous list for the target.  The callback will
+ * be called once the proxy has registered.
+ */
+static int
+rendevous_register_target(device_t dev, rendevous_callback_t callback)
+{
+	struct rendevous_entry *e;
+	const char *name;
+	
+	KASSERT(callback != NULL, ("callback must not be NULL"));
+	name = device_get_nameunit(dev);
+	SLIST_FOREACH(e, &rendevoushead, entries) {
+		if (strcmp(name, e->target.name) == 0) {
+			e->target.device = dev;
+			e->target.callback = callback;
+			return (rendevous_attach(e, &e->target));
+		}
+	}
+	e = malloc(sizeof(*e), M_MIIPROXY, M_WAITOK | M_ZERO);
+	e->target.name = name;
+    	e->target.device = dev;
+	e->target.callback = callback;
+	SLIST_INSERT_HEAD(&rendevoushead, e, entries);
+	return (0);
+}
+
+/*
+ * Remove the registration for the proxy.
+ */
+static int
+rendevous_unregister_proxy(device_t dev)
+{
+	struct rendevous_entry *e;
+	int error = 0;
+	
+	SLIST_FOREACH(e, &rendevoushead, entries) {
+		if (e->proxy.device == dev) {
+			if (e->target.device == NULL) {
+				SLIST_REMOVE(&rendevoushead, e, rendevous_entry, entries);
+				free(e, M_MIIPROXY);
+				return (0);
+			} else {
+				e->proxy.callback(RENDEVOUS_DETACH, e);
+				e->target.callback(RENDEVOUS_DETACH, e);
+			}
+			e->proxy.device = NULL;
+			e->proxy.callback = NULL;
+			return (error);
+		}
+	}
+	return (ENOENT);
+}
+
+/*
+ * Remove the registration for the target.
+ */
+static int
+rendevous_unregister_target(device_t dev)
+{
+	struct rendevous_entry *e;
+	int error = 0;
+	
+	SLIST_FOREACH(e, &rendevoushead, entries) {
+		if (e->target.device == dev) {
+			if (e->proxy.device == NULL) {
+				SLIST_REMOVE(&rendevoushead, e, rendevous_entry, entries);
+				free(e, M_MIIPROXY);
+				return (0);
+			} else {
+				e->proxy.callback(RENDEVOUS_DETACH, e);
+				e->target.callback(RENDEVOUS_DETACH, e);
+			}
+			e->target.device = NULL;
+			e->target.callback = NULL;
+			return (error);
+		}
+	}
+	return (ENOENT);
+}
+
+/*
+ * Functions of the proxy that is interposed between the ethernet interface
+ * driver and the miibus device.
+ */
+
+static int
+miiproxy_rendevous_callback(enum rendevous_op op, struct rendevous_entry *rendevous)
+{
+	struct miiproxy_softc *sc = device_get_softc(rendevous->proxy.device);
+
+	switch (op) {
+	case RENDEVOUS_ATTACH:
+		sc->mdio = device_get_parent(rendevous->target.device);
+		(sc->attach_callback)(sc->attach_arg);
+		break;
+	case RENDEVOUS_DETACH:
+		sc->mdio = NULL;
+		/* detach miibus */
+	}
+	return (0);
+}
+
+static int
+miiproxy_probe(device_t dev)
+{
+	device_set_desc(dev, "MII/MDIO proxy, MII side");
+
+	return (BUS_PROBE_SPECIFIC);
+}
+
+static int
+miiproxy_attach(device_t dev)
+{
+	/*
+	 * The ethernet interface needs to call mii_attach_proxy() to pass
+	 * the relevant parameters for rendevous with the MDIO target.
+	 */
+	return (bus_generic_attach(dev));
+}
+
+static int
+miiproxy_detach(device_t dev)
+{
+	rendevous_unregister_proxy(dev);
+	bus_generic_detach(dev);
+	return (0);
+}
+
+static int
+miiproxy_readreg(device_t dev, int phy, int reg)
+{
+	struct miiproxy_softc *sc = device_get_softc(dev);
+
+	if (sc->mdio != NULL)
+		return (MDIO_READREG(sc->mdio, phy, reg));
+	return (-1);
+}
+
+static int
+miiproxy_writereg(device_t dev, int phy, int reg, int val)
+{
+	struct miiproxy_softc *sc = device_get_softc(dev);
+
+	if (sc->mdio != NULL)
+		return (MDIO_WRITEREG(sc->mdio, phy, reg, val));
+	return (-1);
+}
+
+static void
+miiproxy_statchg(device_t dev)
+{
+	MIIBUS_STATCHG(device_get_parent(dev));
+}
+
+static void
+miiproxy_linkchg(device_t dev)
+{
+	MIIBUS_LINKCHG(device_get_parent(dev));
+}
+
+static void
+miiproxy_mediainit(device_t dev)
+{
+	MIIBUS_MEDIAINIT(device_get_parent(dev));
+}
+
+/*
+ * Functions for the MDIO target device driver.
+ */
+static int
+mdioproxy_rendevous_callback(enum rendevous_op op, struct rendevous_entry *rendevous)
+{
+	return (0);
+}
+
+static void
+mdioproxy_identify(driver_t *driver, device_t parent)
+{
+	device_t child;
+
+	if (device_find_child(parent, driver->name, -1) == NULL) {
+		child = BUS_ADD_CHILD(parent, 0, driver->name, -1);
+	}
+}
+
+static int
+mdioproxy_probe(device_t dev)
+{
+	device_set_desc(dev, "MII/MDIO proxy, MDIO side");
+
+	return (BUS_PROBE_SPECIFIC);
+}
+
+static int
+mdioproxy_attach(device_t dev)
+{
+	rendevous_register_target(dev, mdioproxy_rendevous_callback);
+	return (bus_generic_attach(dev));
+}
+
+static int
+mdioproxy_detach(device_t dev)
+{
+	rendevous_unregister_target(dev);
+	bus_generic_detach(dev);
+	return (0);
+}
+
+/*
+ * Attach this proxy in place of miibus.  The callback is called once all
+ * parts are in place, so that it can attach the miibus to the proxy device,
+ * and finish interface initialization.
+ */
+device_t
+mii_attach_proxy(device_t dev, miiproxy_attach_callback_t cb, void *aa)
+{
+	struct miiproxy_softc *sc;
+	int		error;
+	const char	*name;
+	device_t	miiproxy;
+	
+	if (resource_string_value(device_get_name(dev),
+	    device_get_unit(dev), "mdio", &name) != 0) {
+	    	if (bootverbose)
+			printf("mii_attach_proxy: not attaching, no mdio"
+			    " device hint for %s\n", device_get_nameunit(dev));
+		return (NULL);
+	}
+
+	miiproxy = device_add_child(dev, miiproxy_driver.name, -1);
+	error = bus_generic_attach(dev);
+	if (error != 0) {
+		device_printf(dev, "can't attach miiproxy\n");
+		return (NULL);
+	}
+	sc = device_get_softc(miiproxy);
+	sc->parent = dev;
+	sc->proxy = miiproxy;
+	sc->attach_callback = cb;
+	sc->attach_arg = aa;
+	rendevous_register_proxy(miiproxy, name, miiproxy_rendevous_callback);
+	return (miiproxy);
+}
+
+static device_method_t miiproxy_methods[] = {
+	/* device interface */
+	DEVMETHOD(device_probe,		miiproxy_probe),
+	DEVMETHOD(device_attach,	miiproxy_attach),
+	DEVMETHOD(device_detach,	miiproxy_detach),
+	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
+
+	/* MII interface */
+	DEVMETHOD(miibus_readreg,	miiproxy_readreg),
+	DEVMETHOD(miibus_writereg,	miiproxy_writereg),
+	DEVMETHOD(miibus_statchg,	miiproxy_statchg),
+	DEVMETHOD(miibus_linkchg,	miiproxy_linkchg),
+	DEVMETHOD(miibus_mediainit,	miiproxy_mediainit),
+
+	DEVMETHOD_END
+};
+
+static device_method_t mdioproxy_methods[] = {
+	/* device interface */
+	DEVMETHOD(device_identify,	mdioproxy_identify),
+	DEVMETHOD(device_probe,		mdioproxy_probe),
+	DEVMETHOD(device_attach,	mdioproxy_attach),
+	DEVMETHOD(device_detach,	mdioproxy_detach),
+	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
+
+	DEVMETHOD_END
+};
+
+DEFINE_CLASS_0(miiproxy, miiproxy_driver, miiproxy_methods,
+    sizeof(struct miiproxy_softc));
+DEFINE_CLASS_0(mdioproxy, mdioproxy_driver, mdioproxy_methods,
+    sizeof(struct mdioproxy_softc));
+
+devclass_t miiproxy_devclass;
+static devclass_t mdioproxy_devclass;
+
+DRIVER_MODULE(mdioproxy, mdio, mdioproxy_driver, mdioproxy_devclass, 0, 0);
+DRIVER_MODULE(miibus, miiproxy, miibus_driver, miibus_devclass, 0, 0);
+MODULE_VERSION(miiproxy, 1);
+MODULE_DEPEND(miiproxy, miibus, 1, 1, 1);
diff --git a/sys/dev/etherswitch/miiproxy.h b/sys/dev/etherswitch/miiproxy.h
new file mode 100644
index 0000000..5b8ee7c
--- /dev/null
+++ b/sys/dev/etherswitch/miiproxy.h
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 2011-2012 Stefan Bethke.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_ETHERSWITCH_MIIPROXY_H_
+#define	_DEV_ETHERSWITCH_MIIPROXY_H_
+
+typedef void (*miiproxy_attach_callback_t)(void *);
+
+extern devclass_t miiproxy_devclass;
+extern driver_t miiproxy_driver;
+
+device_t mii_attach_proxy(device_t dev, miiproxy_attach_callback_t cb, void *aa);
+
+#endif
diff --git a/sys/mips/atheros/if_arge.c b/sys/mips/atheros/if_arge.c
index 0154ae2..3dd2e15 100644
--- a/sys/mips/atheros/if_arge.c
+++ b/sys/mips/atheros/if_arge.c
@@ -72,8 +72,18 @@ __FBSDID("$FreeBSD$");
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>
 
+#include <opt_arge.h>
+
+#if defined(ARGE_MDIO)
+#include <dev/etherswitch/mdio.h>
+#include <dev/etherswitch/miiproxy.h>
+#include "mdio_if.h"
+#endif
+
+
 MODULE_DEPEND(arge, ether, 1, 1, 1);
 MODULE_DEPEND(arge, miibus, 1, 1, 1);
+MODULE_VERSION(arge, 1);
 
 #include "miibus_if.h"
 
@@ -102,6 +112,7 @@ typedef enum {
 #endif
 
 static int arge_attach(device_t);
+static int arge_attach_finish(struct arge_softc *sc);
 static int arge_detach(device_t);
 static void arge_flush_ddr(struct arge_softc *);
 static int arge_ifmedia_upd(struct ifnet *);
@@ -134,6 +145,8 @@ static void arge_intr(void *);
 static int arge_intr_filter(void *);
 static void arge_tick(void *);
 
+static void arge_hinted_child(device_t bus, const char *dname, int dunit);
+
 /*
  * ifmedia callbacks for multiPHY MAC
  */
@@ -160,6 +173,10 @@ static device_method_t arge_methods[] = {
 	DEVMETHOD(miibus_writereg,	arge_miibus_writereg),
 	DEVMETHOD(miibus_statchg,	arge_miibus_statchg),
 
+	/* bus interface */
+	DEVMETHOD(bus_add_child,	device_add_child_ordered),
+	DEVMETHOD(bus_hinted_child,	arge_hinted_child),
+
 	DEVMETHOD_END
 };
 
@@ -174,6 +191,37 @@ static devclass_t arge_devclass;
 DRIVER_MODULE(arge, nexus, arge_driver, arge_devclass, 0, 0);
 DRIVER_MODULE(miibus, arge, miibus_driver, miibus_devclass, 0, 0);
 
+#if defined(ARGE_MDIO)
+static int argemdio_probe(device_t);
+static int argemdio_attach(device_t);
+static int argemdio_detach(device_t);
+
+/*
+ * Declare an additional, separate driver for accessing the MDIO bus.
+ */
+static device_method_t argemdio_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		argemdio_probe),
+	DEVMETHOD(device_attach,	argemdio_attach),
+	DEVMETHOD(device_detach,	argemdio_detach),
+
+	/* bus interface */
+	DEVMETHOD(bus_add_child,	device_add_child_ordered),
+	
+	/* MDIO access */
+	DEVMETHOD(mdio_readreg,		arge_miibus_readreg),
+	DEVMETHOD(mdio_writereg,	arge_miibus_writereg),
+};
+
+DEFINE_CLASS_0(argemdio, argemdio_driver, argemdio_methods,
+    sizeof(struct arge_softc));
+static devclass_t argemdio_devclass;
+
+DRIVER_MODULE(miiproxy, arge, miiproxy_driver, miiproxy_devclass, 0, 0);
+DRIVER_MODULE(argemdio, nexus, argemdio_driver, argemdio_devclass, 0, 0);
+DRIVER_MODULE(mdio, argemdio, mdio_driver, mdio_devclass, 0, 0);
+#endif
+
 /*
  * RedBoot passes MAC address to entry point as environment 
  * variable. platfrom_start parses it and stores in this variable
@@ -234,15 +282,22 @@ arge_attach_sysctl(device_t dev)
 #endif
 }
 
+#if defined(ARGE_MDIO)
+static void
+arge_attach_proxy(void *aa)
+{
+	arge_attach_finish(aa);
+}
+#endif
+
 static int
 arge_attach(device_t dev)
 {
-	uint8_t			eaddr[ETHER_ADDR_LEN];
 	struct ifnet		*ifp;
 	struct arge_softc	*sc;
-	int			error = 0, rid, phymask;
+	int			error = 0, rid;
 	uint32_t		reg, rnd;
-	int			is_base_mac_empty, i, phys_total;
+	int			is_base_mac_empty, i;
 	uint32_t		hint;
 	long			eeprom_mac_addr = 0;
 
@@ -277,18 +332,18 @@ arge_attach(device_t dev)
 	 *  Get which PHY of 5 available we should use for this unit
 	 */
 	if (resource_int_value(device_get_name(dev), device_get_unit(dev), 
-	    "phymask", &phymask) != 0) {
+	    "phymask", &sc->arge_phymask) != 0) {
 		/*
 		 * Use port 4 (WAN) for GE0. For any other port use 
 		 * its PHY the same as its unit number 
 		 */
 		if (sc->arge_mac_unit == 0)
-			phymask = (1 << 4);
+			sc->arge_phymask = (1 << 4);
 		else
 			/* Use all phys up to 4 */
-			phymask = (1 << 4) - 1;
+			sc->arge_phymask = (1 << 4) - 1;
 
-		device_printf(dev, "No PHY specified, using mask %d\n", phymask);
+		device_printf(dev, "No PHY specified, using mask %d\n", sc->arge_phymask);
 	}
 
 	/*
@@ -313,8 +368,6 @@ arge_attach(device_t dev)
 	else
 		sc->arge_duplex_mode = 0;
 
-	sc->arge_phymask = phymask;
-
 	mtx_init(&sc->arge_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
 	    MTX_DEF);
 	callout_init_mtx(&sc->arge_stat_callout, &sc->arge_mtx, 0);
@@ -323,7 +376,7 @@ arge_attach(device_t dev)
 	/* Map control/status registers. */
 	sc->arge_rid = 0;
 	sc->arge_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 
-	    &sc->arge_rid, RF_ACTIVE);
+	    &sc->arge_rid, RF_ACTIVE | RF_SHAREABLE);
 
 	if (sc->arge_res == NULL) {
 		device_printf(dev, "couldn't map memory\n");
@@ -371,8 +424,8 @@ arge_attach(device_t dev)
 
 	is_base_mac_empty = 1;
 	for (i = 0; i < ETHER_ADDR_LEN; i++) {
-		eaddr[i] = ar711_base_mac[i] & 0xff;
-		if (eaddr[i] != 0)
+		sc->arge_eaddr[i] = ar711_base_mac[i] & 0xff;
+		if (sc->arge_eaddr[i] != 0)
 			is_base_mac_empty = 0;
 	}
 
@@ -385,16 +438,15 @@ arge_attach(device_t dev)
 			    "Generating random ethernet address.\n");
 
 		rnd = arc4random();
-		eaddr[0] = 'b';
-		eaddr[1] = 's';
-		eaddr[2] = 'd';
-		eaddr[3] = (rnd >> 24) & 0xff;
-		eaddr[4] = (rnd >> 16) & 0xff;
-		eaddr[5] = (rnd >> 8) & 0xff;
+		sc->arge_eaddr[0] = 'b';
+		sc->arge_eaddr[1] = 's';
+		sc->arge_eaddr[2] = 'd';
+		sc->arge_eaddr[3] = (rnd >> 24) & 0xff;
+		sc->arge_eaddr[4] = (rnd >> 16) & 0xff;
+		sc->arge_eaddr[5] = (rnd >> 8) & 0xff;
 	}
-
 	if (sc->arge_mac_unit != 0)
-		eaddr[5] +=  sc->arge_mac_unit;
+		sc->arge_eaddr[5] +=  sc->arge_mac_unit;
 
 	if (arge_dma_alloc(sc) != 0) {
 		error = ENXIO;
@@ -423,19 +475,23 @@ arge_attach(device_t dev)
 
 	ARGE_WRITE(sc, AR71XX_MAC_MAX_FRAME_LEN, 1536);
 
+#if !defined(ARGE_MDIO)
 	/* Reset MII bus */
 	ARGE_WRITE(sc, AR71XX_MAC_MII_CFG, MAC_MII_CFG_RESET);
 	DELAY(100);
 	ARGE_WRITE(sc, AR71XX_MAC_MII_CFG, MAC_MII_CFG_CLOCK_DIV_28);
 	DELAY(100);
+#endif
 
 	/* 
 	 * Set all Ethernet address registers to the same initial values
 	 * set all four addresses to 66-88-aa-cc-dd-ee 
 	 */
-	ARGE_WRITE(sc, AR71XX_MAC_STA_ADDR1, 
-	    (eaddr[2] << 24) | (eaddr[3] << 16) | (eaddr[4] << 8)  | eaddr[5]);
-	ARGE_WRITE(sc, AR71XX_MAC_STA_ADDR2, (eaddr[0] << 8) | eaddr[1]);
+	ARGE_WRITE(sc, AR71XX_MAC_STA_ADDR1, (sc->arge_eaddr[2] << 24)
+	    | (sc->arge_eaddr[3] << 16) | (sc->arge_eaddr[4] << 8)
+	    | sc->arge_eaddr[5]);
+	ARGE_WRITE(sc, AR71XX_MAC_STA_ADDR2, (sc->arge_eaddr[0] << 8)
+	    | sc->arge_eaddr[1]);
 
 	ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG0, 
 	    FIFO_CFG0_ALL << FIFO_CFG0_ENABLE_SHIFT);
@@ -458,30 +514,44 @@ arge_attach(device_t dev)
 	ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMASK, 
 	    FIFO_RX_FILTMASK_DEFAULT);
 
-	/* 
-	 * Check if we have single-PHY MAC or multi-PHY
-	 */
-	phys_total = 0;
-	for (i = 0; i < ARGE_NPHY; i++)
-		if (phymask & (1 << i))
-			phys_total ++;
+#if defined(ARGE_MDIO)
+	sc->arge_miiproxy = mii_attach_proxy(sc->arge_dev, arge_attach_proxy, sc);
+	if (sc->arge_miiproxy == NULL)
+		return (arge_attach_finish(sc));
+#else
+	return (arge_attach_finish(sc));
+#endif
+fail:
+	if (error) 
+		arge_detach(dev);
 
-	if (phys_total == 0) {
-		error = EINVAL;
-		goto fail;
-	}
+	return (error);
+}
 
-	if (phys_total == 1) {
-		/* Do MII setup. */
-		error = mii_attach(dev, &sc->arge_miibus, ifp,
-		    arge_ifmedia_upd, arge_ifmedia_sts, BMSR_DEFCAPMASK,
-		    MII_PHY_ANY, MII_OFFSET_ANY, 0);
-		if (error != 0) {
-			device_printf(dev, "attaching PHYs failed\n");
-			goto fail;
+static int
+arge_attach_finish(struct arge_softc *sc)
+{
+	int	error, phy;
+
+	device_printf(sc->arge_dev, "finishing attachment, phymask %04x"
+	    ", proxy %s \n", sc->arge_phymask, sc->arge_miiproxy == NULL ?
+	    "null" : "set");
+	for (phy = 0; phy < ARGE_NPHY; phy++) {
+		if (((1 << phy) & sc->arge_phymask) != 0) {
+			error = mii_attach(sc->arge_miiproxy != NULL ?
+			    sc->arge_miiproxy : sc->arge_dev,
+			    &sc->arge_miibus, sc->arge_ifp,
+			    arge_ifmedia_upd, arge_ifmedia_sts,
+			    BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0);
+			if (error != 0) {
+				device_printf(sc->arge_dev, "unable to attach"
+				    " PHY %d: %d\n", phy, error);
+				goto fail;
+			}
 		}
 	}
-	else {
+	if (sc->arge_miibus == NULL) {
+		/* no PHY, so use hard-coded values */
 		ifmedia_init(&sc->arge_ifmedia, 0, 
 		    arge_multiphy_mediachange,
 		    arge_multiphy_mediastatus);
@@ -494,24 +564,23 @@ arge_attach(device_t dev)
 	}
 
 	/* Call MI attach routine. */
-	ether_ifattach(ifp, eaddr);
+	ether_ifattach(sc->arge_ifp, sc->arge_eaddr);
 
 	/* Hook interrupt last to avoid having to lock softc */
-	error = bus_setup_intr(dev, sc->arge_irq, INTR_TYPE_NET | INTR_MPSAFE,
+	error = bus_setup_intr(sc->arge_dev, sc->arge_irq, INTR_TYPE_NET | INTR_MPSAFE,
 	    arge_intr_filter, arge_intr, sc, &sc->arge_intrhand);
 
 	if (error) {
-		device_printf(dev, "couldn't set up irq\n");
-		ether_ifdetach(ifp);
+		device_printf(sc->arge_dev, "couldn't set up irq\n");
+		ether_ifdetach(sc->arge_ifp);
 		goto fail;
 	}
 
 	/* setup sysctl variables */
-	arge_attach_sysctl(dev);
-
+	arge_attach_sysctl(sc->arge_dev);
 fail:
 	if (error) 
-		arge_detach(dev);
+		arge_detach(sc->arge_dev);
 
 	return (error);
 }
@@ -542,6 +611,9 @@ arge_detach(device_t dev)
 	if (sc->arge_miibus)
 		device_delete_child(dev, sc->arge_miibus);
 
+	if (sc->arge_miiproxy)
+		device_delete_child(dev, sc->arge_miiproxy);
+
 	bus_generic_detach(dev);
 
 	if (sc->arge_intrhand)
@@ -592,6 +664,13 @@ arge_shutdown(device_t dev)
 	return (0);
 }
 
+static void
+arge_hinted_child(device_t bus, const char *dname, int dunit)
+{
+	BUS_ADD_CHILD(bus, 0, dname, dunit);
+	device_printf(bus, "hinted child %s%d\n", dname, dunit);
+}
+
 static int
 arge_miibus_readreg(device_t dev, int phy, int reg)
 {
@@ -600,16 +679,13 @@ arge_miibus_readreg(device_t dev, int phy, int reg)
 	uint32_t addr = (phy << MAC_MII_PHY_ADDR_SHIFT) 
 	    | (reg & MAC_MII_REG_MASK);
 
-	if ((sc->arge_phymask  & (1 << phy)) == 0)
-		return (0);
-
 	mtx_lock(&miibus_mtx);
-	ARGE_MII_WRITE(AR71XX_MAC_MII_CMD, MAC_MII_CMD_WRITE);
-	ARGE_MII_WRITE(AR71XX_MAC_MII_ADDR, addr);
-	ARGE_MII_WRITE(AR71XX_MAC_MII_CMD, MAC_MII_CMD_READ);
+	ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_CMD, MAC_MII_CMD_WRITE);
+	ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_ADDR, addr);
+	ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_CMD, MAC_MII_CMD_READ);
 
 	i = ARGE_MII_TIMEOUT;
-	while ((ARGE_MII_READ(AR71XX_MAC_MII_INDICATOR) & 
+	while ((ARGE_MDIO_READ(sc, AR71XX_MAC_MII_INDICATOR) & 
 	    MAC_MII_INDICATOR_BUSY) && (i--))
 		DELAY(5);
 
@@ -620,8 +696,8 @@ arge_miibus_readreg(device_t dev, int phy, int reg)
 		return (-1);
 	}
 
-	result = ARGE_MII_READ(AR71XX_MAC_MII_STATUS) & MAC_MII_STATUS_MASK;
-	ARGE_MII_WRITE(AR71XX_MAC_MII_CMD, MAC_MII_CMD_WRITE);
+	result = ARGE_MDIO_READ(sc, AR71XX_MAC_MII_STATUS) & MAC_MII_STATUS_MASK;
+	ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_CMD, MAC_MII_CMD_WRITE);
 	mtx_unlock(&miibus_mtx);
 
 	ARGEDEBUG(sc, ARGE_DBG_MII, "%s: phy=%d, reg=%02x, value[%08x]=%04x\n", __func__, 
@@ -638,19 +714,15 @@ arge_miibus_writereg(device_t dev, int phy, int reg, int data)
 	uint32_t addr = 
 	    (phy << MAC_MII_PHY_ADDR_SHIFT) | (reg & MAC_MII_REG_MASK);
 
-
-	if ((sc->arge_phymask  & (1 << phy)) == 0)
-		return (-1);
-
 	ARGEDEBUG(sc, ARGE_DBG_MII, "%s: phy=%d, reg=%02x, value=%04x\n", __func__, 
 	    phy, reg, data);
 
 	mtx_lock(&miibus_mtx);
-	ARGE_MII_WRITE(AR71XX_MAC_MII_ADDR, addr);
-	ARGE_MII_WRITE(AR71XX_MAC_MII_CONTROL, data);
+	ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_ADDR, addr);
+	ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_CONTROL, data);
 
 	i = ARGE_MII_TIMEOUT;
-	while ((ARGE_MII_READ(AR71XX_MAC_MII_INDICATOR) & 
+	while ((ARGE_MDIO_READ(sc, AR71XX_MAC_MII_INDICATOR) & 
 	    MAC_MII_INDICATOR_BUSY) && (i--))
 		DELAY(5);
 
@@ -715,6 +787,8 @@ arge_set_pll(struct arge_softc *sc, int media, int duplex)
 	uint32_t		fifo_tx;
 	int if_speed;
 
+	ARGEDEBUG(sc, ARGE_DBG_MII, "set_pll(%04x, %s)\n", media,
+	    duplex == IFM_FDX ? "full" : "half");
 	cfg = ARGE_READ(sc, AR71XX_MAC_CFG2);
 	cfg &= ~(MAC_CFG2_IFACE_MODE_1000 
 	    | MAC_CFG2_IFACE_MODE_10_100 
@@ -1923,3 +1997,47 @@ arge_multiphy_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
 	    sc->arge_duplex_mode;
 }
 
+#if defined(ARGE_MDIO)
+static int
+argemdio_probe(device_t dev)
+{
+	device_set_desc(dev, "Atheros AR71xx built-in ethernet interface, MDIO controller");
+	return (0);
+}
+
+static int
+argemdio_attach(device_t dev)
+{
+	struct arge_softc	*sc;
+	int			error = 0;
+
+	sc = device_get_softc(dev);
+	sc->arge_dev = dev;
+	sc->arge_mac_unit = device_get_unit(dev);
+	sc->arge_rid = 0;
+	sc->arge_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 
+	    &sc->arge_rid, RF_ACTIVE | RF_SHAREABLE);
+	if (sc->arge_res == NULL) {
+		device_printf(dev, "couldn't map memory\n");
+		error = ENXIO;
+		goto fail;
+	}
+	/* Reset MII bus */
+	ARGE_WRITE(sc, AR71XX_MAC_MII_CFG, MAC_MII_CFG_RESET);
+	DELAY(100);
+	ARGE_WRITE(sc, AR71XX_MAC_MII_CFG, MAC_MII_CFG_CLOCK_DIV_28);
+	DELAY(100);
+	bus_generic_probe(dev);
+	bus_enumerate_hinted_children(dev);
+	error = bus_generic_attach(dev);
+fail:
+	return (error);
+}
+
+static int
+argemdio_detach(device_t dev)
+{
+	return (0);
+}
+
+#endif
diff --git a/sys/mips/atheros/if_argevar.h b/sys/mips/atheros/if_argevar.h
index c1df678..dc3d931 100644
--- a/sys/mips/atheros/if_argevar.h
+++ b/sys/mips/atheros/if_argevar.h
@@ -67,15 +67,10 @@
 #define ARGE_CLEAR_BITS(sc, reg, bits)	\
 	ARGE_WRITE(sc, reg, ARGE_READ(sc, (reg)) & ~(bits))
 
-/*
- * MII registers access macros
- */
-#define ARGE_MII_READ(reg) \
-        *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1((AR71XX_MII_BASE + reg)))
-
-#define ARGE_MII_WRITE(reg, val) \
-        *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1((AR71XX_MII_BASE + reg))) = (val)
-
+#define ARGE_MDIO_WRITE(_sc, _reg, _val)	\
+	ARGE_WRITE((_sc), (_reg), (_val))
+#define ARGE_MDIO_READ(_sc, _reg)	\
+	ARGE_READ((_sc), (_reg))
 
 #define ARGE_DESC_EMPTY		(1 << 31)
 #define ARGE_DESC_MORE		(1 << 24)
@@ -132,11 +127,14 @@ struct arge_softc {
 	 */
 	uint32_t		arge_media_type;
 	uint32_t		arge_duplex_mode;
+	uint32_t		arge_phymask;
+	uint8_t			arge_eaddr[ETHER_ADDR_LEN];
 	struct resource		*arge_res;
 	int			arge_rid;
 	struct resource		*arge_irq;
 	void			*arge_intrhand;
 	device_t		arge_miibus;
+	device_t		arge_miiproxy;
 	bus_dma_tag_t		arge_parent_tag;
 	bus_dma_tag_t		arge_tag;
 	struct mtx		arge_mtx;
@@ -148,7 +146,6 @@ struct arge_softc {
 	int			arge_detach;
 	uint32_t		arge_intr_status;
 	int			arge_mac_unit;
-	int			arge_phymask;
 	int			arge_if_flags;
 	uint32_t		arge_debug;
 	struct {

--Apple-Mail=_213E4B8A-6009-4FF8-A23A-C6A4E1D4CE37--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?66DDA0A2-F878-43FF-8824-54868F493B18>