Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 11 Jul 2006 00:56:39 -0600 (MDT)
From:      "M. Warner Losh" <imp@bsdimp.com>
To:        acpi@freebsd.org
Subject:   sio0 wiring to a resource patch
Message-ID:  <20060711.005639.-233674225.imp@bsdimp.com>

next in thread | raw e-mail | index | archive | help
----Next_Part(Tue_Jul_11_00_56_39_2006_144)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Please find enclosed an experimental patch.  It does two things.

First, it allows one to wire a unit number to a pci location.  For
example:

hint.rl.1.at="pci"
hint.rl.1.location="6:6:0"

If there's an rl device at pci bus 6, slot 6, funcion 0, then assign
it to rl1.  Otherwise, use the standard unit assignment numbers.

Second, it hours resources that are hinted for devices on the acpi bus
(not isapnp yet, alas).  If you had:

hint.sio.0.at="isa"
hint.sio.0.port="0x3F8"
hint.sio.0.flags="0x10"
hint.sio.0.irq="4"
hint.sio.1.at="isa"
hint.sio.1.port="0x2F8"
hint.sio.1.irq="3"

in your /boot/device.hints file, then COM1 would be sio0 and COM2
would be sio1.  If instead you had:

hint.sio.0.at="isa"
hint.sio.0.port="0x2F8"
hint.sio.0.flags="0x10"
hint.sio.0.irq="3"
hint.sio.1.at="isa"
hint.sio.1.port="0x3F8"
hint.sio.1.irq="4"

Then sio1 would be COM1 and sio0 would be COM2.  This is independent
of the order that you have them in your acpi bios' aml.  If, by
chance, you had a IrDA device on COM1, and there was a sir driver that
could detect it and returned a higher value than sio does for sio1,
then sir0 would attach instead of sio1.  The hint here also means "if
you are going to attach a sio device, make it unit 1, otherwise make
it the unit that would normally be assigned."  It also means that if
you don't load sio, but load uart instead, then uart will attach to
the devices none-the-less.

These patches are experimental, and will need some substantial
refinement as these techniques are applied to other busses.  John
Baldwin and I hashed out the interfaces used under the covers here on
irc today.  Ideally, for the isa unit numbering problem, we'd change
the isa layer somewhat.  There's three types of enumeration that we
need to support:
	(1) No pnpbios.  Hints rule the show here.  isahints.c is
	    perfect for this case.
	(2) Enumeration through pnpbios data, augmented by hints
	    for add-in nonPnP ISA cards.
	(3) Enumeration through ACPI data, augmented by hints
	    for add-in nonPnP ISA cards.
In all three cases, the ISA PNP code would also augment the lists
(since ISA PNP interregates the card directly, and pnpbios is just a
table in the BIOS with no knowledge of and add-in cards, PNP or no).
The nuances of these cases, as well as system specific code for things
like cbus on pc98 that use pnp as well need to be worked out.  None of
these issues are addressed by these patches.  They are a 'cheap hack'
to demonstrate a proof of concept.

These patches augment the other hinting work I just did, so you'll
need a fairly current current to apply them.  Busses can cope with
hinting in two ways.

With the first method, a bus can ask for all the hinted devices up
front, and get a callback for each hinted device.  This is aimed
primarily as those busses that have no shred of self-identifying
information.  The i2c bus falls into this category, for example, as
there's no way to ask for meta-data on each device on the bus in a
non-disruptive, non-intrusive portable way.  Spi bus would be another
example.  Busses that have some way to query their devices would also
benefit from this.  smi bus, for example, has ways to query devices on
the bus, but there's no standardized meta-data for chips on that bus,
so you need to rely on hints.  In this scenario, when the bus adds its
children, it does so with specific names and unit numbers.

With the second method, a bus will detect each of its children.  It
will add generic devices with -1 for the unit number.  Just before
newbus probes a device, it will ask the bus driver if this device node
might have hints that suggest a unit number for the driver we're about
to probe with.  This method is for those busses that can easily add
children, but need to have the children in place before they can parse
resources and the like.  Also, newbus needs to be involved to
implement the bidding for device functionality, as well as the
'fallback to something sane if a device of type foo isn't really at
the hinted location' functionality.

Having the two different methods allows us to easily code up wiring
code for different busses.  At least that's the theory.

Anyway, please test these patches out and let me know if you have
problems.

Warner

----Next_Part(Tue_Jul_11_00_56_39_2006_144)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="wiring.diff"

--- FreeBSD/src/sys/kern/subr_bus.c	Sat Jul  8 11:06:14 2006
+++ p4/arm/src/sys/kern/subr_bus.c	Mon Jul 10 16:49:30 2006
@@ -1690,10 +1697,10 @@
 int
 device_probe_child(device_t dev, device_t child)
 {
-	devclass_t dc;
+	devclass_t dc, childdc;
 	driverlink_t best = 0;
 	driverlink_t dl;
-	int result, pri = 0;
+	int unit, result, pri = 0;
 	int hasclass = (child->devclass != 0);
 
 	GIANT_REQUIRED;
@@ -1717,7 +1724,18 @@
 			device_set_driver(child, dl->driver);
 			if (!hasclass)
 				device_set_devclass(child, dl->driver->name);
-
+			if (child->flags & DF_WILDCARD) {
+				unit = child->unit;
+				BUS_HINT_DEVICE_UNIT(dev, child, &unit);
+				if (unit != child->unit) {
+					childdc = child->devclass;
+					devclass_delete_device(childdc, child);
+					if (childdc->devices[unit] != NULL)
+						continue;
+					child->unit = unit;
+					devclass_add_device(childdc, child);
+				}
+			}
 			/* Fetch any flags for the device before probing. */
 			resource_int_value(dl->driver->name, child->unit,
 			    "flags", &child->devflags);
@@ -1797,6 +1815,16 @@
 		if (!child->devclass)
 			device_set_devclass(child, best->driver->name);
 		device_set_driver(child, best->driver);
+		if (child->flags & DF_WILDCARD) {
+			unit = child->unit;
+			BUS_HINT_DEVICE_UNIT(dev, child, &unit);
+			if (unit != child->unit) {
+				childdc = child->devclass;
+				devclass_delete_device(childdc, child);
+				child->unit = unit;
+				devclass_add_device(childdc, child);
+			}
+		}
 		resource_int_value(best->driver->name, child->unit,
 		    "flags", &child->devflags);
 
@@ -2480,33 +2508,6 @@
 	return (DEVICE_SHUTDOWN(dev));
 }
 
-/**
- * @brief Set the unit number of a device
- *
- * This function can be used to override the unit number used for a
- * device (e.g. to wire a device to a pre-configured unit number).
- */
-int
-device_set_unit(device_t dev, int unit)
-{
-	devclass_t dc;
-	int err;
-
-	dc = device_get_devclass(dev);
-	if (unit < dc->maxunit && dc->devices[unit])
-		return (EBUSY);
-	err = devclass_delete_device(dc, dev);
-	if (err)
-		return (err);
-	dev->unit = unit;
-	err = devclass_add_device(dc, dev);
-	if (err)
-		return (err);
-
-	bus_data_generation_update();
-	return (0);
-}
-
 /*======================================*/
 /*
  * Some useful method implementations to make life easier for bus drivers.
--- FreeBSD/src/sys/kern/bus_if.m	Sat Jul  8 11:06:14 2006
+++ p4/arm/src/sys/kern/bus_if.m	Mon Jul 10 15:37:30 2006
@@ -528,4 +528,21 @@
 	device_t	_dev;
 	const char *	_dname;
 	int		_dunit;
+};
+
+/**
+ * @brief Asks the bus to give us a hand hinting this device.
+ *
+ * Before we probe a child of a bus that's been wildcarded, we call the
+ * bus to see if there's any 'hints' as to unit number for the child
+ * presented for this kind of device.
+ *
+ * @param _dev		the bus device
+ * @param _child	child to hint
+ * @param _dunit	the unit number of the device
+ */
+METHOD void hint_device_unit {
+	device_t	_dev;
+	device_t	_child;
+	int		*_dunit;
 };
--- FreeBSD/src/sys/sys/bus.h	Sat Jul  8 11:06:15 2006
+++ p4/arm/src/sys/sys/bus.h	Sun Jul  9 02:14:59 2006
@@ -375,7 +375,6 @@
 int	device_set_driver(device_t dev, driver_t *driver);
 void	device_set_flags(device_t dev, u_int32_t flags);
 void	device_set_softc(device_t dev, void *softc);
-int	device_set_unit(device_t dev, int unit);	/* XXX DONT USE XXX */
 int	device_shutdown(device_t dev);
 void	device_unbusy(device_t dev);
 void	device_verbose(device_t dev);
Only in FreeBSD/src/sys/dev/pci: CVS
diff -u FreeBSD/src/sys/dev/pci/pci.c p4/arm/src/sys/dev/pci/pci.c
--- FreeBSD/src/sys/dev/pci/pci.c	Thu May 11 16:13:21 2006
+++ p4/arm/src/sys/dev/pci/pci.c	Mon Jul 10 17:23:21 2006
@@ -119,6 +119,7 @@
 	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
 	DEVMETHOD(bus_child_pnpinfo_str, pci_child_pnpinfo_str_method),
 	DEVMETHOD(bus_child_location_str, pci_child_location_str_method),
+	DEVMETHOD(bus_hint_device_unit,	pci_hint_device_unit),
 
 	/* PCI interface */
 	DEVMETHOD(pci_read_config,	pci_read_config_method),
@@ -1997,6 +1998,21 @@
 	    cfg->subvendor, cfg->subdevice, cfg->baseclass, cfg->subclass,
 	    cfg->progif);
 	return (0);
+}
+
+void
+pci_hint_device_unit(device_t bus, device_t child, int *unit)
+{
+	struct pci_devinfo *dinfo = device_get_ivars(child);
+	int i;
+	char buf[10];
+
+	snprintf(buf, sizeof(buf), "%d:%d:%d", dinfo->cfg.bus, dinfo->cfg.slot,
+	    dinfo->cfg.func);
+	i = 0;
+	resource_find_dev(&i, device_get_name(child), unit, "location", buf);
+
+	return;
 }
 
 int
diff -u FreeBSD/src/sys/dev/pci/pci_private.h p4/arm/src/sys/dev/pci/pci_private.h
--- FreeBSD/src/sys/dev/pci/pci_private.h	Fri Jan 20 15:00:50 2006
+++ p4/arm/src/sys/dev/pci/pci_private.h	Mon Jul 10 17:23:54 2006
@@ -76,6 +76,8 @@
 		    char *buf, size_t buflen);
 int		pci_child_pnpinfo_str_method(device_t cbdev, device_t child,
 		    char *buf, size_t buflen);
+void		pci_hint_device_unit(device_t bus, device_t child,
+		    int *unit);
 int		pci_assign_interrupt_method(device_t dev, device_t child);
 int		pci_resume(device_t dev);
 int		pci_suspend(device_t dev);
diff -u FreeBSD/src/sys/dev/acpica/acpi.c p4/arm/src/sys/dev/acpica/acpi.c
--- FreeBSD/src/sys/dev/acpica/acpi.c	Sun Jun 11 21:35:29 2006
+++ p4/arm/src/sys/dev/acpica/acpi.c	Mon Jul 10 17:33:55 2006
@@ -149,9 +149,10 @@
 static int	acpi_sleep_state_sysctl(SYSCTL_HANDLER_ARGS);
 static int	acpi_pm_func(u_long cmd, void *arg, ...);
 static int	acpi_child_location_str_method(device_t acdev, device_t child,
-					       char *buf, size_t buflen);
+		    char *buf, size_t buflen);
 static int	acpi_child_pnpinfo_str_method(device_t acdev, device_t child,
-					      char *buf, size_t buflen);
+		    char *buf, size_t buflen);
+static void	acpi_hint_device_unit(device_t bus, device_t child, int *unit);
 
 static device_method_t acpi_methods[] = {
     /* Device interface */
@@ -182,6 +183,7 @@
     DEVMETHOD(bus_deactivate_resource,	bus_generic_deactivate_resource),
     DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
     DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
+    DEVMETHOD(bus_hint_device_unit,	acpi_hint_device_unit),
 
     /* ACPI bus */
     DEVMETHOD(acpi_id_probe,		acpi_device_id_probe),
@@ -810,6 +812,29 @@
 
     return (0);
 }
+
+static void
+acpi_hint_device_unit(device_t bus, device_t child, int *unit)
+{
+    int i;
+    char buf[10];
+    char *kind = NULL;
+    u_long start, len;
+
+    if (bus_get_resource(child, SYS_RES_IOPORT, 0, &start, &len) == 0)
+	kind = "port";
+    else if (bus_get_resource(child, SYS_RES_MEMORY, 0, &start, &len) == 0)
+	kind = "maddr";
+    if (kind == NULL)
+	return;
+    snprintf(buf, sizeof(buf), "0x%lx", start);
+    i = 0;
+    resource_find_dev(&i, device_get_name(child), unit, kind, buf);
+    // NOTE: We eat units on ANY bus, not just acpi because acpi
+    // should be a specialization of isa, but isn't atm.
+    return;
+}
+
 
 /*
  * Handle per-device ivars

----Next_Part(Tue_Jul_11_00_56_39_2006_144)----



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20060711.005639.-233674225.imp>