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>