So one of the things I've wanted to get working for a while is to make ACPI or PNP BIOS devices that are also enumerated by hints "claim" the hints device (assuming that ACPI/PNP BIOS has a more accurate resource list) and use the unit number of the hint it claims. For the non-ACPI case this would get rid of many of the boot messages about PNP devices not probing b/c they couldn't get resources. For the ACPI case allowing devices to be wired to units based on hints will fix the COM port switching problem where a BIOS lists COM2 before COM1 in the ACPI namespace and so the FreeBSD kernel ends up calling COM1 sio1 and COM2 sio0. The idea then, is that ideally a bus driver (like acpi0 for ACPI, or isa0 for PNP BIOS) would be able to hint to new-bus what a potential device's unit number should be by comparing properties of the device about to be probed with the list of hints. It should also not trample on the existing method of enumerating devices from hints using bus_enumerate_hinted_children() / BUS_HINTED_CHILD(). There are some assumptions about hints that do have to change slightly: 1) For a device to count as a "hint" it has to have an "at" hint. (hint.foo.0.at="blah"). 2) An "at" hint for a given (name, unit) _reserves_ that unit number. New-bus will no longer use that unit for a device with a wildcard unit unless the bus specifies that it should use this unit. Note that if you add a device with a specific unit it will still use that unit regardless of any hints that may exist. The way I've done this is to add a new bus callout that is invoked by new-bus when it is going to assign a unit number to a device prior to probing the device. New-bus will now invoke a BUS_HINT_DEVICE_UNIT() method for any devices with a wildcard unit to ask the parent bus driver if it wants to specify a unit for this device. BUS_HINT_DEVICE_UNIT() gets a reference to the new device and the name of the devclass it is being added to. The bus driver can then employ whatever matching scheme it wants. So one simple example I have is that this can be used to wire PCI devices. For example, one impl I have of PCI unit wiring is to make the "at" hint be a selector similar to the argument you give to pciconf(8). Thus, you could do: hint.em.0.at="pci4:3:0" and this will bind em0 to the PCI device at bus 4, slot 3, function 0. (And yes, it is domain aware, but supports the same "shortcut" notations for domain 0 that pciconf(8) does.) Note that if there isn't an em(4) device at pci4:3:0, then em0 is simply reserved, and any other em(4) devices in the system will use em1, em2, etc. The code for the PCI routine to handle this wiring looks something like this: void pci_hint_device_unit(device_t bus, device_t child, const char *name, int *unitp) { struct pci_devinfo *dinfo = device_get_ivars(child); char buf[32]; int line, unit; line = 0; snprintf(buf, sizeof(buf), "pci%d:%d:%d:%d", dinfo->cfg.domain, dinfo->cfg.bus, dinfo->cfg.slot, dinfo->cfg.func); line = 0; if (resource_find_dev(&line, name, &unit, "at", buf) == 0) *unitp = unit; else if (dinfo->cfg.domain == 0) { snprintf(buf, sizeof(buf), "pci%d:%d:%d", dinfo->cfg.bus, dinfo->cfg.slot, dinfo->cfg.func); line = 0; if (resource_find_dev(&line, name, &unit, "at", buf) == 0) *unitp = unit; ... } } Alternatively, if a bus wants to do matching based on resources specified in the hints (like acpi(4) or isa(4)) the BUS_HINT_DEVICE_UNIT() method can use a loop to iterate over all the "foo" devices and perform more detailed checks on each unit: static void acpi_hint_device_unit(device_t acdev, device_t child, const char *name, int *unitp) { ... /* * Iterate over all the hints for the devices with the specified * name to see if one's resources are a subset of this device. */ line = 0; for (;;) { if (resource_find_dev(&line, name, &unit, "at", NULL) != 0) break; /* Must have an "at" for acpi or isa. */ resource_string_value(name, unit, "at", &s); if (!(strcmp(s, "acpi0") == 0 || strcmp(s, "acpi") == 0 || strcmp(s, "isa0") == 0 || strcmp(s, "isa") == 0)) continue; /* * Check for matching resources. We must have at least one, * and all resources specified have to match. * */ matches = 0; /* ... here it compares "port", "mem", "irq", etc. resources with the resources ACPI specified for this device via _CRS */ if (matches > 0) { /* We have a winner! */ *unitp = unit; break; } } } The full patch of what I have so far is at http://www.FreeBSD.org/~jhb/patches/hint_wire.patch and it includes the new-bus changes as well as adding unit-wiring to ACPI, ISA, and PCI. However, what I would like to commit first is a simpler version that just includes the new-bus changes and the ACPI unit-wiring. The ACPI changes have to be included because: 1) ACPI doesn't currently respect hints, so it uses sio0 for the first serial port it encounters. Without a BUS_HINT_DEVICE_UNIT() method, new-bus would reserve sio0 and sio1 via the default hints and would assign the first serial port in ACPI to sio2. The current ISA bus doesn't suffer from this as it statically adds devices based on hints before probing any children devices. 2) One of the things this fixes that is visible to users is that if your machine gets the COM ports backwards when using ACPI it should now get them correct (COM1 as sio0) assuming your COM ports use the default hints and you have the default sio hints in your /boot/device.hints file. The simple patch is at http://www.FreeBSD.org/~jhb/patches/hint_wire_acpi.patch Testing and feedback welcome. -- John BaldwinReceived on Thu Oct 11 2007 - 19:42:55 UTC
This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:39:19 UTC