summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/dev/mii/mii.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/dev/mii/mii.c')
-rw-r--r--freebsd/sys/dev/mii/mii.c174
1 files changed, 124 insertions, 50 deletions
diff --git a/freebsd/sys/dev/mii/mii.c b/freebsd/sys/dev/mii/mii.c
index 5b949156..2e2e6c79 100644
--- a/freebsd/sys/dev/mii/mii.c
+++ b/freebsd/sys/dev/mii/mii.c
@@ -46,11 +46,10 @@ __FBSDID("$FreeBSD$");
#include <sys/socket.h>
#include <sys/malloc.h>
#include <sys/module.h>
-#include <sys/bus.h>
+#include <sys/bus.h>
#include <net/if.h>
#include <net/if_media.h>
-#include <net/route.h>
#include <dev/mii/mii.h>
#include <dev/mii/miivar.h>
@@ -59,18 +58,20 @@ MODULE_VERSION(miibus, 1);
#include <rtems/bsd/local/miibus_if.h>
-static int miibus_print_child(device_t dev, device_t child);
-static int miibus_read_ivar(device_t dev, device_t child, int which,
- uintptr_t *result);
-static int miibus_child_location_str(device_t bus, device_t child, char *buf,
- size_t buflen);
-static int miibus_child_pnpinfo_str(device_t bus, device_t child, char *buf,
- size_t buflen);
-static int miibus_readreg(device_t, int, int);
-static int miibus_writereg(device_t, int, int, int);
-static void miibus_statchg(device_t);
-static void miibus_linkchg(device_t);
-static void miibus_mediainit(device_t);
+static device_attach_t miibus_attach;
+static bus_child_location_str_t miibus_child_location_str;
+static bus_child_pnpinfo_str_t miibus_child_pnpinfo_str;
+static device_detach_t miibus_detach;
+static bus_hinted_child_t miibus_hinted_child;
+static bus_print_child_t miibus_print_child;
+static device_probe_t miibus_probe;
+static bus_read_ivar_t miibus_read_ivar;
+static miibus_readreg_t miibus_readreg;
+static miibus_statchg_t miibus_statchg;
+static miibus_writereg_t miibus_writereg;
+static miibus_linkchg_t miibus_linkchg;
+static miibus_mediainit_t miibus_mediainit;
+
static device_method_t miibus_methods[] = {
/* device interface */
@@ -82,18 +83,18 @@ static device_method_t miibus_methods[] = {
/* bus interface */
DEVMETHOD(bus_print_child, miibus_print_child),
DEVMETHOD(bus_read_ivar, miibus_read_ivar),
- DEVMETHOD(bus_driver_added, bus_generic_driver_added),
DEVMETHOD(bus_child_pnpinfo_str, miibus_child_pnpinfo_str),
DEVMETHOD(bus_child_location_str, miibus_child_location_str),
+ DEVMETHOD(bus_hinted_child, miibus_hinted_child),
/* MII interface */
DEVMETHOD(miibus_readreg, miibus_readreg),
DEVMETHOD(miibus_writereg, miibus_writereg),
- DEVMETHOD(miibus_statchg, miibus_statchg),
- DEVMETHOD(miibus_linkchg, miibus_linkchg),
- DEVMETHOD(miibus_mediainit, miibus_mediainit),
+ DEVMETHOD(miibus_statchg, miibus_statchg),
+ DEVMETHOD(miibus_linkchg, miibus_linkchg),
+ DEVMETHOD(miibus_mediainit, miibus_mediainit),
- { 0, 0 }
+ DEVMETHOD_END
};
devclass_t miibus_devclass;
@@ -108,10 +109,11 @@ struct miibus_ivars {
struct ifnet *ifp;
ifm_change_cb_t ifmedia_upd;
ifm_stat_cb_t ifmedia_sts;
- int mii_flags;
+ u_int mii_flags;
+ u_int mii_offset;
};
-int
+static int
miibus_probe(device_t dev)
{
@@ -120,7 +122,7 @@ miibus_probe(device_t dev)
return (BUS_PROBE_SPECIFIC);
}
-int
+static int
miibus_attach(device_t dev)
{
struct miibus_ivars *ivars;
@@ -130,7 +132,6 @@ miibus_attach(device_t dev)
int i, nchildren;
mii = device_get_softc(dev);
- nchildren = 0;
if (device_get_children(dev, &children, &nchildren) == 0) {
for (i = 0; i < nchildren; i++) {
ma = device_get_ivars(children[i]);
@@ -153,7 +154,7 @@ miibus_attach(device_t dev)
return (bus_generic_attach(dev));
}
-int
+static int
miibus_detach(device_t dev)
{
struct mii_data *mii;
@@ -202,7 +203,7 @@ miibus_read_ivar(device_t dev, device_t child __unused, int which,
}
static int
-miibus_child_pnpinfo_str(device_t bus __unused, device_t child, char *buf,
+miibus_child_pnpinfo_str(device_t dev __unused, device_t child, char *buf,
size_t buflen)
{
struct mii_attach_args *ma;
@@ -215,7 +216,7 @@ miibus_child_pnpinfo_str(device_t bus __unused, device_t child, char *buf,
}
static int
-miibus_child_location_str(device_t bus __unused, device_t child, char *buf,
+miibus_child_location_str(device_t dev __unused, device_t child, char *buf,
size_t buflen)
{
struct mii_attach_args *ma;
@@ -225,6 +226,60 @@ miibus_child_location_str(device_t bus __unused, device_t child, char *buf,
return (0);
}
+static void
+miibus_hinted_child(device_t dev, const char *name, int unit)
+{
+ struct miibus_ivars *ivars;
+ struct mii_attach_args *args, *ma;
+ device_t *children, phy;
+ int i, nchildren;
+ u_int val;
+
+ if (resource_int_value(name, unit, "phyno", &val) != 0)
+ return;
+ if (device_get_children(dev, &children, &nchildren) != 0)
+ return;
+ ma = NULL;
+ for (i = 0; i < nchildren; i++) {
+ args = device_get_ivars(children[i]);
+ if (args->mii_phyno == val) {
+ ma = args;
+ break;
+ }
+ }
+ free(children, M_TEMP);
+
+ /*
+ * Don't add a PHY that was automatically identified by having media
+ * in its BMSR twice, only allow to alter its attach arguments.
+ */
+ if (ma == NULL) {
+ ma = malloc(sizeof(struct mii_attach_args), M_DEVBUF,
+ M_NOWAIT);
+ if (ma == NULL)
+ return;
+ phy = device_add_child(dev, name, unit);
+ if (phy == NULL) {
+ free(ma, M_DEVBUF);
+ return;
+ }
+ ivars = device_get_ivars(dev);
+ ma->mii_phyno = val;
+ ma->mii_offset = ivars->mii_offset++;
+ ma->mii_id1 = 0;
+ ma->mii_id2 = 0;
+ ma->mii_capmask = BMSR_DEFCAPMASK;
+ device_set_ivars(phy, ma);
+ }
+
+ if (resource_int_value(name, unit, "id1", &val) == 0)
+ ma->mii_id1 = val;
+ if (resource_int_value(name, unit, "id2", &val) == 0)
+ ma->mii_id2 = val;
+ if (resource_int_value(name, unit, "capmask", &val) == 0)
+ ma->mii_capmask = val;
+}
+
static int
miibus_readreg(device_t dev, int phy, int reg)
{
@@ -274,7 +329,7 @@ miibus_linkchg(device_t dev)
MIIBUS_LINKCHG(parent);
mii = device_get_softc(dev);
-
+
if (mii->mii_media_status & IFM_AVALID) {
if (mii->mii_media_status & IFM_ACTIVE)
link_state = LINK_STATE_UP;
@@ -319,9 +374,10 @@ mii_attach(device_t dev, device_t *miibus, struct ifnet *ifp,
int phyloc, int offloc, int flags)
{
struct miibus_ivars *ivars;
- struct mii_attach_args ma, *args;
+ struct mii_attach_args *args, ma;
device_t *children, phy;
- int bmsr, first, i, nchildren, offset, phymax, phymin, rv;
+ int bmsr, first, i, nchildren, phymax, phymin, rv;
+ uint32_t phymask;
if (phyloc != MII_PHY_ANY && offloc != MII_OFFSET_ANY) {
printf("%s: phyloc and offloc specified\n", __func__);
@@ -374,38 +430,41 @@ mii_attach(device_t dev, device_t *miibus, struct ifnet *ifp,
* has been allocated.
*/
ma.mii_data = device_get_softc(*miibus);
- }
+ }
ma.mii_capmask = capmask;
- phy = NULL;
- offset = 0;
+ if (resource_int_value(device_get_name(*miibus),
+ device_get_unit(*miibus), "phymask", &phymask) != 0)
+ phymask = 0xffffffff;
+
+ if (device_get_children(*miibus, &children, &nchildren) != 0) {
+ children = NULL;
+ nchildren = 0;
+ }
+ ivars->mii_offset = 0;
for (ma.mii_phyno = phymin; ma.mii_phyno <= phymax; ma.mii_phyno++) {
/*
* Make sure we haven't already configured a PHY at this
* address. This allows mii_attach() to be called
* multiple times.
*/
- if (device_get_children(*miibus, &children, &nchildren) == 0) {
- for (i = 0; i < nchildren; i++) {
- args = device_get_ivars(children[i]);
- if (args->mii_phyno == ma.mii_phyno) {
- /*
- * Yes, there is already something
- * configured at this address.
- */
- free(children, M_TEMP);
- goto skip;
- }
+ for (i = 0; i < nchildren; i++) {
+ args = device_get_ivars(children[i]);
+ if (args->mii_phyno == ma.mii_phyno) {
+ /*
+ * Yes, there is already something
+ * configured at this address.
+ */
+ goto skip;
}
- free(children, M_TEMP);
}
/*
* Check to see if there is a PHY at this address. Note,
* many braindead PHYs report 0/0 in their ID registers,
* so we test for media in the BMSR.
- */
+ */
bmsr = MIIBUS_READREG(dev, ma.mii_phyno, MII_BMSR);
if (bmsr == 0 || bmsr == 0xffff ||
(bmsr & (BMSR_EXTSTAT | BMSR_MEDIAMASK)) == 0) {
@@ -417,14 +476,20 @@ mii_attach(device_t dev, device_t *miibus, struct ifnet *ifp,
* There is a PHY at this address. If we were given an
* `offset' locator, skip this PHY if it doesn't match.
*/
- if (offloc != MII_OFFSET_ANY && offloc != offset)
+ if (offloc != MII_OFFSET_ANY && offloc != ivars->mii_offset)
+ goto skip;
+
+ /*
+ * Skip this PHY if it's not included in the phymask hint.
+ */
+ if ((phymask & (1 << ma.mii_phyno)) == 0)
goto skip;
/*
- * Extract the IDs. Braindead PHYs will be handled by
+ * Extract the IDs. Braindead PHYs will be handled by
* the `ukphy' driver, as we have no ID information to
* match on.
- */
+ */
ma.mii_id1 = MIIBUS_READREG(dev, ma.mii_phyno, MII_PHYIDR1);
ma.mii_id2 = MIIBUS_READREG(dev, ma.mii_phyno, MII_PHYIDR2);
@@ -440,11 +505,20 @@ mii_attach(device_t dev, device_t *miibus, struct ifnet *ifp,
}
device_set_ivars(phy, args);
skip:
- offset++;
+ ivars->mii_offset++;
}
+ free(children, M_TEMP);
if (first != 0) {
- if (phy == NULL) {
+ rv = device_set_driver(*miibus, &miibus_driver);
+ if (rv != 0)
+ goto fail;
+ bus_enumerate_hinted_children(*miibus);
+ rv = device_get_children(*miibus, &children, &nchildren);
+ if (rv != 0)
+ goto fail;
+ free(children, M_TEMP);
+ if (nchildren == 0) {
rv = ENXIO;
goto fail;
}