Subject: Overhaul device parent matching in config(8)/kernel
To: None <>
From: Jason R Thorpe <>
List: tech-kern
Date: 09/25/2002 09:49:42
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline


I have overhauled how device parent matching is done in the kernel in
order to better support:

	1. Drivers are loadable modules (no, this is no where near
	   complete yet).

	2. Some forthcoming changes to support attaching real devices
	   to pseudo-devices.

For those of you fortunate enough to not know how this currently works
in the kernel, here is a lesson:

	* For each entry in the cfdata[] table, config(8) emits a
	  "parent vector", which is an array of indices back into
	  the cfdata[] table.  These reference cfdata[] entries for
	  potential parents of the device.

	* When the kernel attaches a device, it scans the cfdata[]
	  table looking for un-attached entries who's parent vector
	  array references the device's cfdata[] entry, and when it
	  finds one, applies the match info in the child's cfdata[]
	  entry, attempting to attach the device.

This is sub-optimal for several reasons:

	* In the presence of multiple cfdata[] tables (i.e. which
	  would be the case with loadable driver modules), the parent
	  vector can't reference a parent from another cfdata[] table.

	* For devices which are spec'd to attach to an interface attribute
	  (e.g. "scsibus* at scsi?"), config(8) represents this internally
	  by expanding the vector to all device's which carry that interface
	  attribute.  I.e. if you say "acphy* at mii?", conifig(8) actually
	  generates a parent vector that looks like this:

		acphy* at url*|aue*|xi*|ste*|bge*|wm*|stge*|gsip*| \

	  This obviously doesn't work if you later load a "foo" device
	  which carries the "mii" interface attribute, and want to attach
	  an acphy to it ... you'd need to create another cfdata[] entry
	  for acphy with the correct parent vector.

What I have done to address this is:

	* Add a "const char **cd_attrs" member to the cfdriver structure.
	  If non-NULL, it is an array of interface attributes carried by
	  a device, e.g.:

static const char *ex_attrs[] = { "mii", NULL };
struct cfdriver ex_cd = {
	NULL, "ex", DV_IFNET, 0, ex_attrs

	  For devices which do not have interface attributes, you
	  have this instead:

struct cfdriver lc_cd = {
	NULL, "lc", DV_IFNET, 0, NULL

	  By recording the fact that something has an interface attribute,
	  this allows you to attach to that attribute at run-time, rather
	  than relying on a pre-expanded list of things that have the

	* Remove the parent vector array, in favor of a new "parent spec",
	  which looks like this:

struct cfparent {
	const char *cfp_iattr;		/* interface attribute */
	const char *cfp_parent;		/* optional specific parent */
	int cfp_unit;			/* optional specific unit
					   (-1 to wildcard) */

	  Since all devices attach to an interface attribute, the
	  parent spec records which one.  Additionally, if a device
	  instance wants to attach to a specific parent, that is also
	  recorded.  So, the new parent spec can preceisely describe
	  the following three cases:

		scsibus* at scsi?
			-> iattr = "scsi", parent = NULL, unit = -1

		scsibus* at ahc?
			-> iattr = "scsi", parent = "ahc", unit = -1

		scsibus* at ahc5
			-> iattr = "scsi", parent = "ahc", unit = 5

	* The kernel now uses the cd_attrs array and the parent specs
	  to identify potential children of a device (i.e. the device
	  matches the child's parent spec).  This works in the presence
	  of multiple cfdata tables, because no references back into
	  any cfdata table are made; everything is done with string

This exercise has also allowed me to garbage-collect vast amounts of
confusing code from config(8) :-)

Diffs for this are at:

They're actually not that large, and some of the changes were merely
to make the __BROKEN_CONFIG_UNIT_USAGE stuff a little more readable.

        -- Jason R. Thorpe <>

Content-Type: message/external-body; access-type=x-mutt-deleted;
	expiration="Wed, 25 Sep 2002 10:27:17 -0700"; length=38356

Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=config-diffs