From owner-svn-src-head@FreeBSD.ORG Mon Mar 9 13:20:24 2009 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 089DB106567A; Mon, 9 Mar 2009 13:20:24 +0000 (UTC) (envelope-from imp@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id EA0628FC1E; Mon, 9 Mar 2009 13:20:23 +0000 (UTC) (envelope-from imp@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n29DKNn8027312; Mon, 9 Mar 2009 13:20:23 GMT (envelope-from imp@svn.freebsd.org) Received: (from imp@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n29DKNT8027311; Mon, 9 Mar 2009 13:20:23 GMT (envelope-from imp@svn.freebsd.org) Message-Id: <200903091320.n29DKNT8027311@svn.freebsd.org> From: Warner Losh Date: Mon, 9 Mar 2009 13:20:23 +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: r189574 - head/sys/kern X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 09 Mar 2009 13:20:24 -0000 Author: imp Date: Mon Mar 9 13:20:23 2009 New Revision: 189574 URL: http://svn.freebsd.org/changeset/base/189574 Log: Fix a long-standing bug in newbus. It was introduced when subclassing was introduced. If you have a bus, say cardbus, that is derived from a base-bus (say PCI), then ordinarily all PCI drivers would attach to cardbus devices. However, there had been one exception: kldload wouldn't work. The problem is in devclass_add_driver. In this routine, all we did was call to the pci device's BUS_DRIVER_ADDED routine. However, since cardbus bus instances had a different devclass, none of them were called. The solution is to call all subclass devclasses, recursively down the tree, of the class that was loaded. Since we don't have a 'children class' pointer, we search the whole list of devclasses for a class whose parent matches. Since just done a kldload time, this isn't as bad as it sounds. In addition, we short-circuit the whole process by marking those classes with subclasses with a flag. We'll likely have to reevaluate this method the number of devclasses with subclasses gets large. This means we can remove the "cardbus" lines from all the PCI drivers since we have no cardbus specific attach device attachments in the tree. # Also: minor tweak to an error message Modified: head/sys/kern/subr_bus.c Modified: head/sys/kern/subr_bus.c ============================================================================== --- head/sys/kern/subr_bus.c Mon Mar 9 13:12:48 2009 (r189573) +++ head/sys/kern/subr_bus.c Mon Mar 9 13:20:23 2009 (r189574) @@ -82,6 +82,8 @@ struct devclass { char *name; device_t *devices; /* array of devices indexed by unit */ int maxunit; /* size of devices array */ + int flags; +#define DC_HAS_CHILDREN 1 struct sysctl_ctx_list sysctl_ctx; struct sysctl_oid *sysctl_tree; @@ -813,6 +815,7 @@ devclass_find_internal(const char *class if (parentname && dc && !dc->parent && strcmp(classname, parentname) != 0) { dc->parent = devclass_find_internal(parentname, NULL, FALSE); + dc->parent->flags |= DC_HAS_CHILDREN; } return (dc); @@ -846,6 +849,52 @@ devclass_find(const char *classname) return (devclass_find_internal(classname, NULL, FALSE)); } + +/** + * @brief Register that a device driver has been added to a devclass + * + * Register that a device driver has been added to a devclass. This + * is called by devclass_add_driver to accomplish the recursive + * notification of all the children classes of dc, as well as dc. + * Each layer will have BUS_DRIVER_ADDED() called for all instances of + * the devclass. We do a full search here of the devclass list at + * each iteration level to save storing children-lists in the devclass + * structure. If we ever move beyond a few dozen devices doing this, + * we may need to reevaluate... + * + * @param dc the devclass to edit + * @param driver the driver that was just added + */ +static void +devclass_driver_added(devclass_t dc, driver_t *driver) +{ + int i; + devclass_t parent; + + /* + * Call BUS_DRIVER_ADDED for any existing busses in this class. + */ + for (i = 0; i < dc->maxunit; i++) + if (dc->devices[i]) + BUS_DRIVER_ADDED(dc->devices[i], driver); + + /* + * Walk through the children classes. Since we only keep a + * single parent pointer around, we walk the entire list of + * devclasses looking for children. We set the + * DC_HAS_CHILDREN flag when a child devclass is created on + * the parent, so we only walk thoe list for those devclasses + * that have children. + */ + if (!(dc->flags & DC_HAS_CHILDREN)) + return; + parent = dc; + TAILQ_FOREACH(dc, &devclasses, link) { + if (dc->parent == parent) + devclass_driver_added(dc, driver); + } +} + /** * @brief Add a device driver to a device class * @@ -861,7 +910,6 @@ int devclass_add_driver(devclass_t dc, driver_t *driver) { driverlink_t dl; - int i; PDEBUG(("%s", DRIVERNAME(driver))); @@ -886,13 +934,7 @@ devclass_add_driver(devclass_t dc, drive TAILQ_INSERT_TAIL(&dc->drivers, dl, link); driver->refs++; /* XXX: kobj_mtx */ - /* - * Call BUS_DRIVER_ADDED for any existing busses in this class. - */ - for (i = 0; i < dc->maxunit; i++) - if (dc->devices[i]) - BUS_DRIVER_ADDED(dc->devices[i], driver); - + devclass_driver_added(dc, driver); bus_data_generation_update(); return (0); } @@ -1758,7 +1800,9 @@ device_probe_child(device_t dev, device_ device_set_driver(child, dl->driver); if (!hasclass) { if (device_set_devclass(child, dl->driver->name)) { - PDEBUG(("Unable to set device class")); + printf("driver bug: Unable to set devclass (devname: %s)\n", + (child ? device_get_name(child) : + "no device")); device_set_driver(child, NULL); continue; }