From owner-svn-src-all@FreeBSD.ORG Fri Nov 18 22:39:46 2011 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 936BF10656E8; Fri, 18 Nov 2011 22:39:46 +0000 (UTC) (envelope-from marius@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 817C68FC18; Fri, 18 Nov 2011 22:39:46 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id pAIMdkrf003349; Fri, 18 Nov 2011 22:39:46 GMT (envelope-from marius@svn.freebsd.org) Received: (from marius@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id pAIMdkCr003347; Fri, 18 Nov 2011 22:39:46 GMT (envelope-from marius@svn.freebsd.org) Message-Id: <201111182239.pAIMdkCr003347@svn.freebsd.org> From: Marius Strobl Date: Fri, 18 Nov 2011 22:39:46 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r227687 - head/sys/dev/mii X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 18 Nov 2011 22:39:46 -0000 Author: marius Date: Fri Nov 18 22:39:46 2011 New Revision: 227687 URL: http://svn.freebsd.org/changeset/base/227687 Log: - Add a hint.miibus.X.phymask hint, allowing do individually exclude PHY addresses from being probed and attaching something including ukphy(4) to it. This is mainly necessarily for PHY switches that create duplicate or fake PHYs on the bus that can corrupt the PHY state when accessed or simply cause problems when ukphy(4) isolates the additional instances. - Change miibus(4) to be a hinted bus, allowing to add child devices via hints and to set their attach arguments (including for automatically probed PHYs). This is mainly needed for PHY switches that violate IEEE 802.3 and don't even implement the basic register set so we can't probe them automatically. However, the ability to alter the attach arguments for automatically probed PHYs is also useful as for example it allows to test (or tell a user to test) new variant of a PHY with a specific driver by letting an existing driver attach to it via manipulating the IDs without the need to touch the source code or to limit a Gigabit Ethernet PHY to only announce up to Fast Ethernet in order to save energy by limiting the capability mask. Generally, a driver has to be hinted via hint.phydrv.X.at="miibusY" and hint.phydrv.X.phyno="Z" (which already is sufficient to add phydrvX at miibusY at PHY address Z). Then optionally the following attach arguments additionally can be configured: hint.phydrv.X.id1 hint.phydrv.X.id2 hint.phydrv.X.capmask - Some minor cleanup. Reviewed by: adrian, ray Modified: head/sys/dev/mii/mii.c Modified: head/sys/dev/mii/mii.c ============================================================================== --- head/sys/dev/mii/mii.c Fri Nov 18 21:23:13 2011 (r227686) +++ head/sys/dev/mii/mii.c Fri Nov 18 22:39:46 2011 (r227687) @@ -48,7 +48,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include #include @@ -57,18 +56,17 @@ MODULE_VERSION(miibus, 1); #include "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 bus_child_location_str_t miibus_child_location_str; +static bus_child_pnpinfo_str_t miibus_child_pnpinfo_str; +static bus_hinted_child_t miibus_hinted_child; +static bus_print_child_t miibus_print_child; +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 unsigned char mii_bitreverse(unsigned char x); static device_method_t miibus_methods[] = { @@ -84,6 +82,7 @@ static device_method_t miibus_methods[] 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), @@ -107,7 +106,8 @@ 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 @@ -129,7 +129,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]); @@ -201,7 +200,7 @@ miibus_read_ivar(device_t dev, device_t } 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; @@ -214,7 +213,7 @@ miibus_child_pnpinfo_str(device_t bus __ } 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; @@ -224,6 +223,60 @@ miibus_child_location_str(device_t bus _ 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) { @@ -307,9 +360,10 @@ mii_attach(device_t dev, device_t *miibu 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__); @@ -366,27 +420,30 @@ mii_attach(device_t dev, device_t *miibu 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); } /* @@ -405,18 +462,24 @@ mii_attach(device_t dev, device_t *miibu * 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; /* - * Extract the IDs. Braindead PHYs will be handled by + * 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 * 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); - ma.mii_offset = offset; + ma.mii_offset = ivars->mii_offset; args = malloc(sizeof(struct mii_attach_args), M_DEVBUF, M_NOWAIT); if (args == NULL) @@ -429,15 +492,24 @@ mii_attach(device_t dev, device_t *miibu } device_set_ivars(phy, args); skip: - offset++; + ivars->mii_offset++; } + free(children, M_TEMP); if (first != 0) { - if (phy == NULL) { + rv = device_probe(*miibus); + 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; } - rv = bus_generic_attach(dev); + rv = device_attach(*miibus); if (rv != 0) goto fail;