--- //depot/vendor/freebsd/src/sys/dev/acpica/acpi.c 2007/09/13 01:46:22 +++ //depot/user/jhb/acpipci/dev/acpica/acpi.c 2007/10/08 18:46:03 @@ -153,6 +153,8 @@ char *buf, size_t buflen); static int acpi_child_pnpinfo_str_method(device_t acdev, device_t child, char *buf, size_t buflen); +static void acpi_hint_device_unit(device_t acdev, device_t child, + const char *name, int *unitp); static device_method_t acpi_methods[] = { /* Device interface */ @@ -183,6 +185,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), @@ -936,6 +939,124 @@ return (&ad->ad_rl); } +static int +acpi_match_resource_hint(device_t dev, int type, long value) +{ + struct acpi_device *ad = device_get_ivars(dev); + struct resource_list *rl = &ad->ad_rl; + struct resource_list_entry *rle; + + STAILQ_FOREACH(rle, rl, link) { + if (rle->type != type) + continue; + if (rle->start <= value && rle->end >= value) + return (1); + } + return (0); +} + +//#define HINT_UID + +/* + * Wire device unit numbers based on resource matches in hints. + */ +static void +acpi_hint_device_unit(device_t acdev, device_t child, const char *name, + int *unitp) +{ +#ifdef HINT_UID + ACPI_BUFFER adbuf = {ACPI_ALLOCATE_BUFFER, NULL}; + ACPI_DEVICE_INFO *adinfo; + struct acpi_device *dinfo = device_get_ivars(child); +#endif + const char *s; + long value; + int line, matches, unit; + +#ifdef HINT_UID + /* + * If this object has a _UID, then check for a matching "uid" hint + * and use that in preference to resource matching. + */ + if (ACPI_SUCCESS(AcpiGetObjectInfo(dinfo->ad_handle, &adbuf))) { + adinfo = adbuf.Pointer; + if (adinfo->Valid & ACPI_VALID_UID) { + line = 0; + if (resource_find_dev(&line, name, &unit, "uid", + adinfo->UniqueId.Value) == 0) { + + /* Must have an "at" for acpi or isa. */ + if (resource_string_value(name, unit, "at", &s) == 0 && + (strcmp(s, "acpi0") == 0 || strcmp(s, "acpi") == 0 || + strcmp(s, "isa0") == 0 || strcmp(s, "isa") == 0)) { + + /* We have a winner! */ + *unitp = unit; + AcpiOsFree(adinfo); + return; + } + } + } + AcpiOsFree(adinfo); + } +#endif + + /* + * 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. + * + * XXX: We may want to revisit this to be more lenient and wire + * as long as it gets one match. + */ + matches = 0; + if (resource_long_value(name, unit, "port", &value) == 0) { + if (acpi_match_resource_hint(child, SYS_RES_IOPORT, value)) + matches++; + else + continue; + } + if (resource_long_value(name, unit, "maddr", &value) == 0) { + if (acpi_match_resource_hint(child, SYS_RES_MEMORY, value)) + matches++; + else + continue; + } + if (resource_long_value(name, unit, "irq", &value) == 0) { + if (acpi_match_resource_hint(child, SYS_RES_IRQ, value)) + matches++; + else + continue; + } + if (resource_long_value(name, unit, "drq", &value) == 0) { + if (acpi_match_resource_hint(child, SYS_RES_DRQ, value)) + matches++; + else + continue; + } + + if (matches > 0) { + /* We have a winner! */ + *unitp = unit; + break; + } + } +} + /* * Pre-allocate/manage all memory and IO resources. Since rman can't handle * duplicates, we merge any in the sysresource attach routine. --- //depot/vendor/freebsd/src/sys/dev/pci/pci.c 2007/09/30 11:08:30 +++ //depot/user/jhb/acpipci/dev/pci/pci.c 2007/10/08 18:46:03 @@ -140,6 +140,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), @@ -3531,6 +3532,100 @@ return (0); } +/* 3 different methods */ +#define HINT_AT +//#define HINT_LOC +//#define HINT_BSF +void +pci_hint_device_unit(device_t bus, device_t child, const char *name, int *unitp) +{ + struct pci_devinfo *dinfo = device_get_ivars(child); +#ifdef HINT_BSF + long value; +#endif +#ifdef HINT_LOC + const char *s; +#endif + char buf[32]; + int line, unit; + + line = 0; +#ifdef HINT_AT + /* + * We support three different "at" formats akin to the + * selectors supported by pciconf(8) where "D" is the domain, + * "B" is the bus, "S" is the slot (device), and "F" is the + * function. + * + * "pciD:B:S:F" + * "pciB:S:F" (assumes domain of 0) + * "pciB:S" (assumes domain and function of 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; + else if (dinfo->cfg.func == 0) { + snprintf(buf, sizeof(buf), "pci%d:%d", + dinfo->cfg.bus, dinfo->cfg.slot); + line = 0; + if (resource_find_dev(&line, name, &unit, "at", buf) == + 0) + *unitp = unit; + } + } +#else + /* Must have an "at" for this bus. */ + snprintf(buf, sizeof(buf), "pci%d", dinfo->cfg.bus); + for (;;) { + if (resource_find_dev(&line, name, &unit, "at", buf) != 0) + break; + +#ifdef HINT_LOC + /* XXX: How to handle domain? */ + /* Look for a location hint that specifies the "slot.func". */ + if (resource_string_value(name, unit, "location", &s) != 0) + continue; + snprintf(buf, sizeof(buf), "%d:%d", dinfo->cfg.slot, + dinfo->cfg.func); + if (strcmp(s, buf) != 0) + continue; +#endif +#ifdef HINT_BSF + /* Require a domain hint for non-zero domain. */ + if (resource_long_value(name, unit, "domain", &value) == 0) { + if (value != dinfo->cfg.domain) + continue; + } else if (dinfo->cfg.domain != 0) + continue; + + /* Look for slot and func hints. */ + if (resource_long_value(name, unit, "slot", &value) != 0 && + resource_long_value(name, unit, "device", &value) != 0) + continue; + if (dinfo->cfg.slot != value) + continue; + if (resource_long_value(name, unit, "func", &value) != 0 && + resource_long_value(name, unit, "function", &value) != 0) + continue; + if (dinfo->cfg.func != value) + continue; +#endif + + /* We have a winner! */ + *unitp = unit; + return; + } +#endif +} + int pci_assign_interrupt_method(device_t dev, device_t child) { --- //depot/vendor/freebsd/src/sys/dev/pci/pci_private.h 2007/09/30 11:08:30 +++ //depot/user/jhb/acpipci/dev/pci/pci_private.h 2007/10/08 16:52:09 @@ -93,6 +93,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, + const char *name, int *unitp); int pci_assign_interrupt_method(device_t dev, device_t child); int pci_resume(device_t dev); int pci_suspend(device_t dev); --- //depot/vendor/freebsd/src/sys/dev/sio/sio_pci.c 2007/03/29 04:32:10 +++ //depot/user/jhb/acpipci/dev/sio/sio_pci.c 2007/09/24 17:40:11 @@ -43,7 +43,6 @@ #include static int sio_pci_attach(device_t dev); -static void sio_pci_kludge_unit(device_t dev); static int sio_pci_probe(device_t dev); static device_method_t sio_pci_methods[] = { @@ -101,39 +100,9 @@ id++; if (id->desc == NULL) return (ENXIO); - sio_pci_kludge_unit(dev); return (sioattach(dev, id->rid, 0UL)); } -/* - * Don't cut and paste this to other drivers. It is a horrible kludge - * which will fail to work and also be unnecessary in future versions. - */ -static void -sio_pci_kludge_unit(dev) - device_t dev; -{ - devclass_t dc; - int err; - int start; - int unit; - - unit = 0; - start = 0; - while (resource_int_value("sio", unit, "port", &start) == 0 && - start > 0) - unit++; - if (device_get_unit(dev) < unit) { - dc = device_get_devclass(dev); - while (devclass_get_device(dc, unit)) - unit++; - device_printf(dev, "moving to sio%d\n", unit); - err = device_set_unit(dev, unit); /* EVIL DO NOT COPY */ - if (err) - device_printf(dev, "error moving device %d\n", err); - } -} - static int sio_pci_probe(dev) device_t dev; --- //depot/vendor/freebsd/src/sys/isa/isa_common.c 2007/04/17 15:17:27 +++ //depot/user/jhb/acpipci/isa/isa_common.c 2007/10/06 07:05:50 @@ -517,17 +517,40 @@ } /* + * Claim any unallocated resources to keep other devices from using + * them. + */ +static void +isa_claim_resources(device_t dev, device_t child) +{ + struct isa_device *idev = DEVTOISA(child); + struct resource_list *rl = &idev->id_resources; + struct resource_list_entry *rle; + int rid; + + STAILQ_FOREACH(rle, rl, link) { + if (!rle->res) { + rid = rle->rid; + resource_list_alloc(rl, dev, child, rle->type, &rid, + 0ul, ~0ul, 1, 0); + } + } +} + +/* * Called after other devices have initialised to probe for isa devices. */ void isa_probe_children(device_t dev) { - device_t *children; + struct isa_device *idev; + device_t *children, child; struct isa_config *cfg; int nchildren, i; /* - * Create all the children by calling driver's identify methods. + * Create all the non-hinted children by calling drivers' + * identify methods. */ bus_generic_probe(dev); @@ -548,8 +571,7 @@ } for (i = 0; i < nchildren; i++) { - device_t child = children[i]; - struct isa_device *idev = DEVTOISA(child); + idev = DEVTOISA(children[i]); bzero(cfg, sizeof(*cfg)); if (idev->id_config_cb) @@ -559,16 +581,39 @@ free(cfg, M_TEMP); /* - * Next probe all non-pnp devices so that they claim their - * resources first. + * Next, probe all the PnP BIOS devices so they can subsume any + * hints. + */ + for (i = 0; i < nchildren; i++) { + child = children[i]; + idev = DEVTOISA(child); + + if (idev->id_order > ISA_ORDER_PNPBIOS) + continue; + if (!TAILQ_EMPTY(&idev->id_configs) && + !isa_assign_resources(child)) + continue; + + if (device_probe_and_attach(child) == 0) + isa_claim_resources(dev, child); + } + free(children, M_TEMP); + + /* + * Next, enumerate hinted devices and probe all non-pnp devices so + * that they claim their resources first. */ + bus_enumerate_hinted_children(dev); + if (device_get_children(dev, &children, &nchildren)) + return; if (bootverbose) printf("isa_probe_children: probing non-PnP devices\n"); for (i = 0; i < nchildren; i++) { - device_t child = children[i]; - struct isa_device *idev = DEVTOISA(child); + child = children[i]; + idev = DEVTOISA(child); - if (TAILQ_FIRST(&idev->id_configs)) + if (device_is_attached(child) || + !TAILQ_EMPTY(&idev->id_configs)) continue; device_probe_and_attach(child); @@ -580,31 +625,15 @@ if (bootverbose) printf("isa_probe_children: probing PnP devices\n"); for (i = 0; i < nchildren; i++) { - device_t child = children[i]; - struct isa_device* idev = DEVTOISA(child); + child = children[i]; + idev = DEVTOISA(child); - if (!TAILQ_FIRST(&idev->id_configs)) + if (device_is_attached(child) || TAILQ_EMPTY(&idev->id_configs)) continue; if (isa_assign_resources(child)) { - struct resource_list *rl = &idev->id_resources; - struct resource_list_entry *rle; - device_probe_and_attach(child); - - /* - * Claim any unallocated resources to keep other - * devices from using them. - */ - STAILQ_FOREACH(rle, rl, link) { - if (!rle->res) { - int rid = rle->rid; - resource_list_alloc(rl, dev, child, - rle->type, - &rid, - 0, ~0, 1, 0); - } - } + isa_claim_resources(dev, child); } } @@ -632,6 +661,7 @@ resource_list_init(&idev->id_resources); TAILQ_INIT(&idev->id_configs); + idev->id_order = order; device_set_ivars(child, idev); @@ -873,23 +903,9 @@ isa_child_detached(device_t dev, device_t child) { struct isa_device* idev = DEVTOISA(child); - struct resource_list *rl = &idev->id_resources; - struct resource_list_entry *rle; - if (TAILQ_FIRST(&idev->id_configs)) { - /* - * Claim any unallocated resources to keep other - * devices from using them. - */ - STAILQ_FOREACH(rle, rl, link) { - if (!rle->res) { - int rid = rle->rid; - resource_list_alloc(rl, dev, child, - rle->type, - &rid, 0, ~0, 1, 0); - } - } - } + if (TAILQ_FIRST(&idev->id_configs)) + isa_claim_resources(dev, child); } static void @@ -940,20 +956,8 @@ device_probe_and_attach(child); - if (TAILQ_FIRST(&idev->id_configs)) { - /* - * Claim any unallocated resources to keep other - * devices from using them. - */ - STAILQ_FOREACH(rle, rl, link) { - if (!rle->res) { - int rid = rle->rid; - resource_list_alloc(rl, dev, child, - rle->type, - &rid, 0, ~0, 1, 0); - } - } - } + if (TAILQ_FIRST(&idev->id_configs)) + isa_claim_resources(dev, child); } free(children, M_TEMP); @@ -1115,6 +1119,8 @@ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_child_pnpinfo_str, isa_child_pnpinfo_str), DEVMETHOD(bus_child_location_str, isa_child_location_str), + DEVMETHOD(bus_hinted_child, isa_hinted_child), + DEVMETHOD(bus_hint_device_unit, isa_hint_device_unit), /* ISA interface */ DEVMETHOD(isa_add_config, isa_add_config), @@ -1124,11 +1130,7 @@ { 0, 0 } }; -driver_t isa_driver = { - "isa", - isa_methods, - 1, /* no softc */ -}; +DEFINE_CLASS_0(isa, isa_driver, isa_methods, 0); devclass_t isa_devclass; --- //depot/vendor/freebsd/src/sys/isa/isa_common.h 2007/02/23 12:24:01 +++ //depot/user/jhb/acpipci/isa/isa_common.h 2007/09/24 17:40:11 @@ -56,6 +56,7 @@ isa_config_cb *id_config_cb; /* callback function */ void *id_config_arg; /* callback argument */ int id_config_attr; /* pnp config attributes */ + int id_order; }; #define DEVTOISA(dev) ((struct isa_device *) device_get_ivars(dev)) --- //depot/vendor/freebsd/src/sys/isa/isahint.c 2006/07/08 16:52:07 +++ //depot/user/jhb/acpipci/isa/isahint.c 2007/10/03 16:06:25 @@ -33,10 +33,11 @@ #include #include #include +#include #include -static void -isahint_add_device(device_t parent, const char *name, int unit) +void +isa_hinted_child(device_t parent, const char *name, int unit) { device_t child; int sensitive, start, count; @@ -82,43 +83,79 @@ isa_set_configattr(child, (isa_get_configattr(child)|ISACFGATTR_HINTS)); } -static void -isahint_identify(driver_t *driver, device_t parent) +static int +isa_match_resource_hint(device_t dev, int type, long value) { - int i; - static char buf[] = "isaXXX"; - const char *dname; - int dunit; + struct isa_device* idev = DEVTOISA(dev); + struct resource_list *rl = &idev->id_resources; + struct resource_list_entry *rle; - /* - * Add all devices configured to be attached to parent. - */ - sprintf(buf, "isa%d", device_get_unit(parent)); - i = 0; - while (resource_find_match(&i, &dname, &dunit, "at", buf) == 0) - isahint_add_device(parent, dname, dunit); - - /* - * and isa? - */ - i = 0; - while (resource_find_match(&i, &dname, &dunit, "at", "isa") == 0) - isahint_add_device(parent, dname, dunit); + STAILQ_FOREACH(rle, rl, link) { + if (rle->type != type) + continue; + if (rle->start <= value && rle->end >= value) + return (1); + } + return (0); } -static device_method_t isahint_methods[] = { - /* Device interface */ - DEVMETHOD(device_identify, isahint_identify), +void +isa_hint_device_unit(device_t bus, device_t child, const char *name, int *unitp) +{ + const char *s; + long value; + int line, matches, unit; - { 0, 0 } -}; + line = 0; + for (;;) { + if (resource_find_dev(&line, name, &unit, "at", NULL) != 0) + break; -static driver_t isahint_driver = { - "hint", - isahint_methods, - 1, /* no softc */ -}; + /* Must have an "at" for isa. */ + resource_string_value(name, unit, "at", &s); + if (!(strcmp(s, device_get_nameunit(bus)) == 0 || + strcmp(s, device_get_name(bus)) == 0)) + continue; -static devclass_t hint_devclass; + /* + * Check for matching resources. We must have at least one, + * and all resources specified have to match. + * + * XXX: We may want to revisit this to be more lenient and wire + * as long as it gets one match. + */ + matches = 0; + if (resource_long_value(name, unit, "port", &value) == 0) { + if (isa_match_resource_hint(child, SYS_RES_IOPORT, + value)) + matches++; + else + continue; + } + if (resource_long_value(name, unit, "maddr", &value) == 0) { + if (isa_match_resource_hint(child, SYS_RES_MEMORY, + value)) + matches++; + else + continue; + } + if (resource_long_value(name, unit, "irq", &value) == 0) { + if (isa_match_resource_hint(child, SYS_RES_IRQ, value)) + matches++; + else + continue; + } + if (resource_long_value(name, unit, "drq", &value) == 0) { + if (isa_match_resource_hint(child, SYS_RES_DRQ, value)) + matches++; + else + continue; + } -DRIVER_MODULE(isahint, isa, isahint_driver, hint_devclass, 0, 0); + if (matches > 0) { + /* We have a winner! */ + *unitp = unit; + break; + } + } +} --- //depot/vendor/freebsd/src/sys/isa/isavar.h 2005/04/13 03:30:39 +++ //depot/user/jhb/acpipci/isa/isavar.h 2007/09/24 17:40:11 @@ -176,6 +176,9 @@ (int)(chan), (uintmax_t)(size)); \ } while (0) +void isa_hinted_child(device_t parent, const char *name, int unit); +void isa_hint_device_unit(device_t bus, device_t child, const char *name, + int *unitp); int isab_attach(device_t dev); #ifdef PC98 --- //depot/vendor/freebsd/src/sys/kern/bus_if.m 2007/02/23 12:24:01 +++ //depot/user/jhb/acpipci/kern/bus_if.m 2007/09/24 17:40:11 @@ -527,7 +527,7 @@ */ METHOD void hinted_child { device_t _dev; - const char * _dname; + const char *_dname; int _dunit; }; @@ -541,3 +541,19 @@ device_t _dev; device_t _child; } DEFAULT bus_generic_get_dma_tag; + +/** + * @brief Allow the bus to determine the unit number of a device. + * + * @param _dev the parent device of @p _child + * @param _child the device whose unit is to be wired + * @param _name the name of the device's new devclass + * @param _unitp a pointer to the device's new unit value + */ +METHOD void hint_device_unit { + device_t _dev; + device_t _child; + const char *_name; + int *_unitp; +}; + --- //depot/vendor/freebsd/src/sys/kern/subr_bus.c 2007/07/27 12:03:05 +++ //depot/user/jhb/acpipci/kern/subr_bus.c 2007/09/24 17:40:11 @@ -1293,12 +1293,18 @@ * @retval ENOMEM memory allocation failure */ static int -devclass_alloc_unit(devclass_t dc, int *unitp) +devclass_alloc_unit(devclass_t dc, device_t dev, int *unitp) { + const char *s; int unit = *unitp; PDEBUG(("unit %d in devclass %s", unit, DEVCLANAME(dc))); + /* Ask the parent bus if it wants to wire this device. */ + if (unit == -1) + BUS_HINT_DEVICE_UNIT(device_get_parent(dev), dev, dc->name, + &unit); + /* If we were given a wired unit number, check for existing device */ /* XXX imp XXX */ if (unit != -1) { @@ -1312,8 +1318,18 @@ } else { /* Unwired device, find the next available slot for it */ unit = 0; - while (unit < dc->maxunit && dc->devices[unit] != NULL) - unit++; + for (unit = 0;; unit++) { + /* If there is an "at" hint for a unit then skip it. */ + if (resource_string_value(dc->name, unit, "at", &s) == + 0) + continue; + + /* If this device slot is already in use, skip it. */ + if (unit < dc->maxunit && dc->devices[unit] != NULL) + continue; + + break; + } } /* @@ -1373,7 +1389,7 @@ if (!dev->nameunit) return (ENOMEM); - if ((error = devclass_alloc_unit(dc, &dev->unit)) != 0) { + if ((error = devclass_alloc_unit(dc, dev, &dev->unit)) != 0) { free(dev->nameunit, M_BUS); dev->nameunit = NULL; return (error);