--- //depot/vendor/freebsd/src/sys/dev/acpica/acpi_pci.c 2004/08/13 06:25:41 +++ //depot/user/jhb/acpipci/dev/acpica/acpi_pci.c 2004/09/13 21:10:57 @@ -280,8 +280,8 @@ if (ACPI_FAILURE(acpi_GetInteger(handle, "_ADR", &address))) return_ACPI_STATUS (AE_OK); - slot = address >> 16; - func = address & 0xffff; + slot = ACPI_ADR_PCI_SLOT(address); + func = ACPI_ADR_PCI_FUNC(address); if (device_get_children((device_t)context, &devlist, &devcount) != 0) return_ACPI_STATUS (AE_OK); for (i = 0; i < devcount; i++) { --- //depot/vendor/freebsd/src/sys/dev/acpica/acpi_pci_link.c 2004/09/01 18:00:56 +++ //depot/user/jhb/acpipci/dev/acpica/acpi_pci_link.c 2004/09/14 22:01:39 @@ -31,22 +31,33 @@ #include #include #include +#include +#include #include "acpi.h" #include #include +#include +#include #include #include "pcib_if.h" +#ifdef NEW_STUFF +#define bootverbose 1 +#endif + /* Hooks for the ACPI CA debugging infrastructure. */ #define _COMPONENT ACPI_BUS ACPI_MODULE_NAME("PCI_LINK") +#ifndef NEW_STUFF TAILQ_HEAD(acpi_pci_link_entries, acpi_pci_link_entry); static struct acpi_pci_link_entries acpi_pci_link_entries; +#endif ACPI_SERIAL_DECL(pci_link, "ACPI PCI link"); +#ifndef NEW_STUFF TAILQ_HEAD(acpi_prt_entries, acpi_prt_entry); static struct acpi_prt_entries acpi_prt_entries; @@ -57,11 +68,13 @@ static void acpi_pci_link_update_irq_penalty(device_t dev, int busno); static void acpi_pci_link_set_bootdisabled_priority(void); static void acpi_pci_link_fixup_bootdisabled_link(void); +#endif /* * PCI link object management */ +#ifndef NEW_STUFF static void acpi_pci_link_dump_polarity(UINT32 ActiveHighLow) { @@ -151,7 +164,7 @@ } printf(" %d.%d.%d\n", entry->busno, - (int)((entry->prt.Address & 0xffff0000) >> 16), + (int)(ACPI_ADR_PCI_SLOT(entry->prt.Address)), (int)entry->prt.Pin); } @@ -976,7 +989,7 @@ snprintf(prthint, sizeof(prthint), "hw.acpi.pci.link.%d.%d.%d.irq", entry->busno, - (int)((entry->prt.Address & 0xffff0000) >> 16), + (int)(ACPI_ADR_PCI_SLOT(entry->prt.Address)), (int)entry->prt.Pin); if (getenv_int(prthint, &irq) == 0) @@ -1064,7 +1077,7 @@ TAILQ_FOREACH(entry, &acpi_prt_entries, links) { prt = &entry->prt; if (entry->busno == pci_get_bus(dev) && - (prt->Address & 0xffff0000) >> 16 == pci_get_slot(dev) && + ACPI_ADR_PCI_SLOT(prt->Address) == pci_get_slot(dev) && prt->Pin == pin) break; } @@ -1144,3 +1157,566 @@ ACPI_SERIAL_END(pci_link); return (irq); } +#else + +#define NUM_ISA_INTERRUPTS 16 +#define NUM_ACPI_INTERRUPTS 256 + +/* + * An ACPI PCI link device may contain multiple links. Each link has its + * own ACPI resource. _PRT entries specify which link is being used via + * the Source Index. + */ + +struct link; + +struct acpi_pci_link_softc { + int pl_num_links; + struct link *pl_links; +}; + +struct link { + struct acpi_pci_link_softc *l_sc; + uint8_t l_bios_irq; + uint8_t l_irq; + uint8_t l_initial_irq; + int l_res_index; + int l_num_irqs; + int *l_irqs; + int l_references; + int l_routed:1; + ACPI_RESOURCE l_crs; +}; + +struct link_res_request { + struct acpi_pci_link_softc *sc; + int count; +}; + +MALLOC_DEFINE(M_PCI_LINK, "PCI Link", "ACPI PCI Link structures"); + +#ifdef notyet +static int pci_link_interrupt_weights[NUM_ACPI_INTERRUPTS]; +#endif +static int pci_link_bios_isa_irqs; + +static char *pci_link_ids[] = { "PNP0C0F", NULL }; + +static int +acpi_pci_link_probe(device_t dev) +{ + ACPI_BUFFER buf; + char descr[64], name[10]; + + /* + * We explicitly do not check _STA since not all systems set it to + * sensible values. + */ + if (!acpi_disabled("pci_link") && + ACPI_ID_PROBE(device_get_parent(dev), dev, pci_link_ids) != NULL) { + buf.Length = sizeof(name); + buf.Pointer = &name; + if (ACPI_FAILURE(AcpiGetName(acpi_get_handle(dev), + ACPI_SINGLE_NAME, &buf))) + device_set_desc(dev, "ACPI PCI Link"); + else { + snprintf(descr, sizeof(descr), "ACPI PCI Link %s", + name); + device_set_desc_copy(dev, descr); + } + return (0); + } + return (ENXIO); +} + +static ACPI_STATUS +acpi_count_resources(ACPI_RESOURCE *res, void *context) +{ + int *count; + + count = (int *)context; + (*count)++; + return (AE_OK); +} + +static ACPI_STATUS +link_add_crs(ACPI_RESOURCE *res, void *context) +{ + struct link_res_request *req; + struct link *link; + + ACPI_SERIAL_ASSERT(pci_link); + req = (struct link_res_request *)context; + link = &req->sc->pl_links[req->count]; + req->count++; + switch (res->Id) { + case ACPI_RSTYPE_IRQ: + case ACPI_RSTYPE_EXT_IRQ: + + /* + * Stash a copy of the resource for later use when doing + * _SRS. + */ + bcopy(res, &link->l_crs, sizeof(ACPI_RESOURCE)); + if (res->Id == ACPI_RSTYPE_IRQ) { + if (res->Data.Irq.NumberOfInterrupts > 0) { + KASSERT(res->Data.Irq.NumberOfInterrupts == 1, + ("%s: too many interrupts", __func__)); + link->l_irq = res->Data.Irq.Interrupts[0]; + } + } else if (res->Data.ExtendedIrq.NumberOfInterrupts > 0) { + KASSERT(res->Data.ExtendedIrq.NumberOfInterrupts == 1, + ("%s: too many interrupts", __func__)); + link->l_irq = res->Data.ExtendedIrq.Interrupts[0]; + } + + /* + * An IRQ of zero means that the link isn't routed. + */ + if (link->l_irq == 0) + link->l_irq = PCI_INVALID_IRQ; + break; + } + return (AE_OK); +} + +/* + * Populate the set of possible IRQs for each device. + */ +static ACPI_STATUS +link_add_prs(ACPI_RESOURCE *res, void *context) +{ + struct link_res_request *req; + struct link *link; + UINT32 *irqs; + int i; + + ACPI_SERIAL_ASSERT(pci_link); + req = (struct link_res_request *)context; + link = &req->sc->pl_links[req->count]; + req->count++; + switch (res->Id) { + case ACPI_RSTYPE_IRQ: + case ACPI_RSTYPE_EXT_IRQ: + if (res->Id == ACPI_RSTYPE_IRQ) { + link->l_num_irqs = res->Data.Irq.NumberOfInterrupts; + irqs = res->Data.Irq.Interrupts; + } else { + link->l_num_irqs = + res->Data.ExtendedIrq.NumberOfInterrupts; + irqs = res->Data.ExtendedIrq.Interrupts; + } + if (link->l_num_irqs == 0) + break; + link->l_irqs = malloc(sizeof(int) * link->l_num_irqs, + M_PCI_LINK, M_WAITOK | M_ZERO); + for (i = 0; i < link->l_num_irqs; i++) + link->l_irqs[i] = irqs[i]; + break; + } + return (AE_OK); +} + +static int +link_valid_irq(struct link *link, int irq) +{ + int i; + + ACPI_SERIAL_ASSERT(pci_link); + if (!PCI_INTERRUPT_VALID(irq)) + return (0); + for (i = 0; i < link->l_num_irqs; i++) + if (link->l_irqs[i] == irq) + return (1); + return (0); +} + +static void +acpi_pci_link_dump(struct acpi_pci_link_softc *sc) +{ + struct link *link; + int i, j; + + ACPI_SERIAL_ASSERT(pci_link); + printf("Index IRQ Rtd Ref IRQs\n"); + for (i = 0; i < sc->pl_num_links; i++) { + link = &sc->pl_links[i]; + printf("%5d %3d %c %3d ", i, link->l_irq, + link->l_routed ? 'Y' : 'N', link->l_references); + if (link->l_num_irqs == 0) + printf(" none"); + else for (j = 0; j < link->l_num_irqs; j++) + printf(" %d", link->l_irqs[j]); + printf("\n"); + } +} + +static int +acpi_pci_link_attach(device_t dev) +{ + struct acpi_pci_link_softc *sc; + struct link_res_request req; + ACPI_STATUS status; + int i; + + sc = device_get_softc(dev); + ACPI_SERIAL_BEGIN(pci_link); + + /* + * Count the number of current resources so we know how big of + * a link array to allocate. + */ + status = AcpiWalkResources(acpi_get_handle(dev), "_CRS", + acpi_count_resources, &sc->pl_num_links); + if (ACPI_FAILURE(status)) + return (ENXIO); + if (sc->pl_num_links == 0) + return (0); + sc->pl_links = malloc(sizeof(struct link) * sc->pl_num_links, + M_PCI_LINK, M_WAITOK | M_ZERO); + + /* Initialize the child links. */ + for (i = 0; i < sc->pl_num_links; i++) { + sc->pl_links[i].l_irq = PCI_INVALID_IRQ; + sc->pl_links[i].l_bios_irq = PCI_INVALID_IRQ; + sc->pl_links[i].l_res_index = i; + sc->pl_links[i].l_sc = sc; + } + req.count = 0; + req.sc = sc; + status = AcpiWalkResources(acpi_get_handle(dev), "_CRS", + link_add_crs, &req); + if (ACPI_FAILURE(status)) + goto fail; + req.count = 0; + status = AcpiWalkResources(acpi_get_handle(dev), "_PRS", + link_add_prs, &req); + if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) + goto fail; + if (bootverbose) { + device_printf(dev, "Links after initial probe:\n"); + acpi_pci_link_dump(sc); + } + + /* Save initial IRQs. */ + for (i = 0; i < sc->pl_num_links; i++) + sc->pl_links[i].l_initial_irq = sc->pl_links[i].l_irq; + + /* Verify initial IRQs if we have _PRS. */ + if (status != AE_NOT_FOUND) + for (i = 0; i < sc->pl_num_links; i++) + if (!link_valid_irq(&sc->pl_links[i], + sc->pl_links[i].l_irq)) + sc->pl_links[i].l_irq = PCI_INVALID_IRQ; + if (bootverbose) { + device_printf(dev, "Links after initial validation:\n"); + acpi_pci_link_dump(sc); + } + + /* + * Try to disable this link. If successful, set the current IRQ to + * zero and flags to indicate this link is not routed. If we can't + * run _DIS (i.e., the method doesn't exist), assume the initial + * IRQ was routed by the BIOS. + */ + if (ACPI_SUCCESS(AcpiEvaluateObject(acpi_get_handle(dev), "_DIS", NULL, + NULL))) + for (i = 0; i < sc->pl_num_links; i++) + sc->pl_links[i].l_irq = PCI_INVALID_IRQ; + else + for (i = 0; i < sc->pl_num_links; i++) + sc->pl_links[i].l_routed = 1; + if (bootverbose) { + device_printf(dev, "Links after disable:\n"); + acpi_pci_link_dump(sc); + } + ACPI_SERIAL_END(pci_link); + return (0); +fail: + ACPI_SERIAL_END(pci_link); + for (i = 0; i < sc->pl_num_links; i++) + if (sc->pl_links[i].l_irqs != NULL) + free(sc->pl_links[i].l_irqs, M_PCI_LINK); + free(sc->pl_links, M_PCI_LINK); + return (ENXIO); +} + + +/* XXX: Note that this is identical to pci_pir_search_irq(). */ +static uint8_t +acpi_pci_link_search_irq(int bus, int device, int pin) +{ + uint32_t value; + uint8_t func, maxfunc; + + /* See if we have a valid device at function 0. */ + value = pci_cfgregread(bus, device, 0, PCIR_HDRTYPE, 1); + if ((value & PCIM_HDRTYPE) > PCI_MAXHDRTYPE) + return (PCI_INVALID_IRQ); + if (value & PCIM_MFDEV) + maxfunc = PCI_FUNCMAX; + else + maxfunc = 0; + + /* Scan all possible functions at this device. */ + for (func = 0; func <= maxfunc; func++) { + value = pci_cfgregread(bus, device, func, PCIR_DEVVENDOR, 4); + if (value == 0xffffffff) + continue; + value = pci_cfgregread(bus, device, func, PCIR_INTPIN, 1); + + /* + * See if it uses the pin in question. Note that the passed + * in pin uses 0 for A, .. 3 for D whereas the intpin + * register uses 0 for no interrupt, 1 for A, .. 4 for D. + */ + if (value != pin + 1) + continue; + value = pci_cfgregread(bus, device, func, PCIR_INTLINE, 1); + if (bootverbose) + printf( + "ACPI: Found matching pin for %d.%d.INT%c at func %d: %d\n", + bus, device, pin + 'A', func, value); + if (value != PCI_INVALID_IRQ) + return (value); + } + return (PCI_INVALID_IRQ); +} + +void +acpi_pci_link_add_reference(device_t dev, int index, device_t pcib, int slot, + int pin) +{ + struct acpi_pci_link_softc *sc; + struct link *link; + uint8_t bios_irq; + + /* Bump the reference count. */ + ACPI_SERIAL_BEGIN(pci_link); + sc = device_get_softc(dev); + KASSERT(index >= 0 && index < sc->pl_num_links, + ("%s: invalid index %d", __func__, index)); + link = &sc->pl_links[index]; + link->l_references++; + + /* Try to find a BIOS IRQ setting from any matching devices. */ + bios_irq = acpi_pci_link_search_irq(pcib_get_bus(pcib), slot, pin); + if (!PCI_INTERRUPT_VALID(bios_irq)) { + ACPI_SERIAL_END(pci_link); + return; + } + + /* Validate the BIOS IRQ. */ + if (!link_valid_irq(link, bios_irq)) { + device_printf(dev, "BIOS IRQ %u for %d.%d.INT%c is invalid\n", + bios_irq, pcib_get_bus(pcib), slot, pin + 'A'); + } else if (!PCI_INTERRUPT_VALID(link->l_bios_irq)) { + link->l_bios_irq = bios_irq; + if (bios_irq < NUM_ISA_INTERRUPTS) + pci_link_bios_isa_irqs |= (1 << bios_irq); + if (bios_irq != link->l_initial_irq && + PCI_INTERRUPT_VALID(link->l_initial_irq)) + device_printf(dev, + "BIOS IRQ %u does not match initial IRQ %u\n", + bios_irq, link->l_initial_irq); + } else if (bios_irq != link->l_bios_irq) + device_printf(dev, + "BIOS IRQ %u for %d.%d.INT%c does not match previous BIOS IRQ %u\n", + bios_irq, pcib_get_bus(pcib), slot, pin + 'A', + link->l_bios_irq); + ACPI_SERIAL_END(pci_link); +} + +static ACPI_STATUS +acpi_pci_link_route_irqs(device_t dev) +{ + struct acpi_pci_link_softc *sc; + ACPI_RESOURCE *resource, *end; + ACPI_BUFFER buf; + ACPI_STATUS status; + struct link *link; + int i; + + /* Fetch the _CRS. */ + ACPI_SERIAL_ASSERT(pci_link); + sc = device_get_softc(dev); + buf.Pointer = NULL; + buf.Length = ACPI_ALLOCATE_BUFFER; + status = AcpiGetCurrentResources(acpi_get_handle(dev), &buf); + if (ACPI_SUCCESS(status) && buf.Pointer == NULL) + status = AE_NO_MEMORY; + if (ACPI_FAILURE(status)) { + if (bootverbose) + device_printf(dev, + "Unable to fetch current resources: %s\n", + AcpiFormatException(status)); + return (status); + } + + /* Fill in IRQ resources via link structures. */ + link = sc->pl_links; + i = 0; + resource = (ACPI_RESOURCE *)buf.Pointer; + end = (ACPI_RESOURCE *)((char *)buf.Pointer + buf.Length); + for (;;) { + if (resource->Id == ACPI_RSTYPE_END_TAG) + break; + MPASS(i < sc->pl_num_links); + switch (resource->Id) { + case ACPI_RSTYPE_IRQ: + MPASS(resource->Data.Irq.NumberOfInterrupts == 1); + if (PCI_INTERRUPT_VALID(link->l_irq)) + resource->Data.Irq.Interrupts[0] = link->l_irq; + else + resource->Data.Irq.Interrupts[0] = 0; + break; + case ACPI_RSTYPE_EXT_IRQ: + MPASS(resource->Data.ExtendedIrq.NumberOfInterrupts == + 1); + if (PCI_INTERRUPT_VALID(link->l_irq)) + resource->Data.ExtendedIrq.Interrupts[0] = + link->l_irq; + else + resource->Data.ExtendedIrq.Interrupts[0] = 0; + break; + } + resource = ACPI_NEXT_RESOURCE(resource); + link++; + i++; + if (resource >= end) + break; + } + + /* Write out new resources via _SRS. */ + status = AcpiSetCurrentResources(acpi_get_handle(dev), &buf); + if (ACPI_FAILURE(status)) { + device_printf(dev, "Unable to route IRQs: %s\n", + AcpiFormatException(status)); + AcpiOsFree(buf.Pointer); + return (status); + } + + /* + * Perform acpi_config_intr() on each IRQ resource if it was just + * routed for the first time. + */ + link = sc->pl_links; + i = 0; + resource = (ACPI_RESOURCE *)buf.Pointer; + for (;;) { + if (resource->Id == ACPI_RSTYPE_END_TAG) + break; + MPASS(i < sc->pl_num_links); + if (link->l_routed) + continue; + switch (resource->Id) { + case ACPI_RSTYPE_IRQ: + case ACPI_RSTYPE_EXT_IRQ: + link->l_routed = 1; + acpi_config_intr(dev, resource); + break; + } + resource = ACPI_NEXT_RESOURCE(resource); + link++; + i++; + if (resource >= end) + break; + } + AcpiOsFree(buf.Pointer); + return (AE_OK); +} + +static int +acpi_pci_link_resume(device_t dev) +{ + ACPI_STATUS status; + + ACPI_SERIAL_BEGIN(pci_link); + status = acpi_pci_link_route_irqs(dev); + ACPI_SERIAL_END(pci_link); + if (ACPI_FAILURE(status)) + return (ENXIO); + else + return (0); +} + +int +acpi_pci_link_route_interrupt(device_t dev, int index) +{ + struct acpi_pci_link_softc *sc; + struct link *link; + + ACPI_SERIAL_BEGIN(pci_link); + sc = device_get_softc(dev); + KASSERT(index >= 0 && index < sc->pl_num_links, + ("%s: invalid index %d", __func__, index)); + link = &sc->pl_links[index]; + + /* + * If this link device is already routed to an interrupt, just return + * the interrupt it is routed to. + */ + if (link->l_routed) { + KASSERT(PCI_INTERRUPT_VALID(link->l_irq), + ("%s: link is routed but has an invalid IRQ", __func__)); + ACPI_SERIAL_END(pci_link); + return (link->l_irq); + } + + /* Choose an IRQ if we need one. */ + if (!PCI_INTERRUPT_VALID(link->l_irq)) { + + /* + * If our initial IRQ is ok and agrees with the BIOS IRQ, + * use it, otherwise fall back to the BIOS IRQ. If neither + * is valid then we have to pick an IRQ to use. + */ + if (PCI_INTERRUPT_VALID(link->l_initial_irq)) { + if (!PCI_INTERRUPT_VALID(link->l_bios_irq) || + link->l_bios_irq == link->l_initial_irq) + link->l_irq = link->l_initial_irq; + } else if (PCI_INTERRUPT_VALID(link->l_bios_irq)) { + link->l_irq = link->l_bios_irq; + } else + device_printf(dev, "Oof, not ready yet"); + + /* + * Try to route the interrupt we picked. If it fails, then + * assume the interrupt is not routed. + */ + if (PCI_INTERRUPT_VALID(link->l_irq)) { + acpi_pci_link_route_irqs(dev); + if (!link->l_routed) + link->l_irq = PCI_INVALID_IRQ; + } + } + ACPI_SERIAL_END(pci_link); + + return (link->l_irq); +} + +static device_method_t acpi_pci_link_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, acpi_pci_link_probe), + DEVMETHOD(device_attach, acpi_pci_link_attach), +#if 0 + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bus_generic_suspend), +#endif + DEVMETHOD(device_resume, acpi_pci_link_resume), + + {0, 0} +}; + +static driver_t acpi_pci_link_driver = { + "pci_link", + acpi_pci_link_methods, + sizeof(struct acpi_pci_link_softc), +}; + +static devclass_t pci_link_devclass; + +DRIVER_MODULE(acpi_pci_link, acpi, acpi_pci_link_driver, pci_link_devclass, 0, + 0); +MODULE_DEPEND(acpi_pci_link, acpi, 1, 1, 1); +#endif --- //depot/vendor/freebsd/src/sys/dev/acpica/acpi_pcib.c 2004/08/13 06:25:41 +++ //depot/user/jhb/acpipci/dev/acpica/acpi_pcib.c 2004/09/14 22:01:39 @@ -41,6 +41,10 @@ #include #include "pcib_if.h" +#ifdef NEW_STUFF +#define bootverbose 1 +#endif + /* Hooks for the ACPI CA debugging infrastructure. */ #define _COMPONENT ACPI_BUS ACPI_MODULE_NAME("PCI") @@ -51,8 +55,77 @@ * For locking, we assume the caller is not concurrent since this is * triggered by newbus methods. */ + +struct prt_lookup_request { + ACPI_PCI_ROUTING_TABLE *pr_entry; + u_int pr_pin; + u_int pr_slot; +}; + +typedef void prt_entry_handler(ACPI_PCI_ROUTING_TABLE *entry, void *arg); + +static void prt_attach_devices(ACPI_PCI_ROUTING_TABLE *entry, void *arg); +#ifdef NEW_STUFF +static void prt_lookup_device(ACPI_PCI_ROUTING_TABLE *entry, void *arg); +#endif +static void prt_walk_table(ACPI_BUFFER *prt, prt_entry_handler *handler, + void *arg); + +static void +prt_walk_table(ACPI_BUFFER *prt, prt_entry_handler *handler, void *arg) +{ + ACPI_PCI_ROUTING_TABLE *entry; + char *prtptr; + + /* First check to see if there is a table to walk. */ + if (prt == NULL || prt->Pointer == NULL) + return; + + /* Walk the table executing the handler function for each entry. */ + prtptr = prt->Pointer; + entry = (ACPI_PCI_ROUTING_TABLE *)prtptr; + while (entry->Length != 0) { + handler(entry, arg); + prtptr += entry->Length; + entry = (ACPI_PCI_ROUTING_TABLE *)prtptr; + } +} + +static void +prt_attach_devices(ACPI_PCI_ROUTING_TABLE *entry, void *arg) +{ + ACPI_HANDLE handle; + device_t child, pcib; + int error; + + /* We only care about entries that reference a link device. */ + if (entry->Source == NULL || entry->Source[0] == '\0') + return; + + /* Lookup the associated handle and device. */ + pcib = (device_t)arg; + if (ACPI_FAILURE(AcpiGetHandle(acpi_get_handle(pcib), entry->Source, + &handle))) + return; + child = acpi_get_device(handle); + if (child == NULL) + return; + + /* If the device hasn't been probed yet, force it to do so. */ + error = device_probe_and_attach(child); + if (error != 0) { + device_printf((device_t)arg, "failed to force attach of %s\n", + acpi_name(handle)); + return; + } + + /* Add a reference for a specific bus/device/pin tuple. */ + acpi_pci_link_add_reference(child, entry->SourceIndex, pcib, + ACPI_ADR_PCI_SLOT(entry->Address), entry->Pin); +} + int -acpi_pcib_attach(device_t dev, ACPI_BUFFER *prt, int busno) +acpi_pcib_attach(device_t dev, ACPI_BUFFER *prt, int busno, int hostbridge) { device_t child; ACPI_STATUS status; @@ -74,7 +147,7 @@ */ prt->Length = ACPI_ALLOCATE_BUFFER; status = AcpiGetIrqRoutingTable(acpi_get_handle(dev), prt); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status) && hostbridge) device_printf(dev, "could not get PCI interrupt routing table for %s - %s\n", acpi_name(acpi_get_handle(dev)), AcpiFormatException(status)); @@ -90,7 +163,11 @@ /* * Now go scan the bus. */ +#ifdef NEW_STUFF + prt_walk_table(prt, prt_attach_devices, dev); +#else acpi_pci_link_config(dev, prt, busno); +#endif return_VALUE (bus_generic_attach(dev)); } @@ -98,20 +175,54 @@ int acpi_pcib_resume(device_t dev) { + +#ifndef NEW_STUFF acpi_pci_link_resume(dev); +#endif return (bus_generic_resume(dev)); } +#ifdef NEW_STUFF +static void +prt_lookup_device(ACPI_PCI_ROUTING_TABLE *entry, void *arg) +{ + struct prt_lookup_request *pr; + + pr = (struct prt_lookup_request *)arg; + if (pr->pr_entry != NULL) + return; + + /* + * Compare the slot number (high word of Address) and pin number + * (note that ACPI uses 0 for INTA) to check for a match. + * + * Note that the low word of the Address field (function number) + * is required by the specification to be 0xffff. We don't risk + * checking it here. + */ + if (ACPI_ADR_PCI_SLOT(entry->Address) == pr->pr_slot && + entry->Pin == pr->pr_pin) + pr->pr_entry = entry; +} +#endif + /* * Route an interrupt for a child of the bridge. */ int -acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin) +acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin, + ACPI_BUFFER *prtbuf) { - struct acpi_prt_entry *entry; - int i, interrupt; - struct acpi_pci_link_entry *link; - ACPI_PCI_ROUTING_TABLE *prt; + ACPI_PCI_ROUTING_TABLE *prt; + int interrupt; +#ifdef NEW_STUFF + struct prt_lookup_request pr; + ACPI_HANDLE lnkdev; +#else + struct acpi_pci_link_entry *link; + struct acpi_prt_entry *entry; + int i; +#endif ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); @@ -122,6 +233,7 @@ ACPI_SERIAL_BEGIN(pcib); +#ifndef NEW_STUFF /* Look up the PRT entry for this device. */ entry = acpi_pci_find_prt(pcib, dev, pin); if (entry == NULL) { @@ -139,6 +251,25 @@ printf("\n"); } +#else + /* Search for a matching entry in the routing table. */ + pr.pr_entry = NULL; + pr.pr_pin = pin; + pr.pr_slot = pci_get_slot(dev); + prt_walk_table(prtbuf, prt_lookup_device, &pr); + if (pr.pr_entry == NULL) + return (PCI_INVALID_IRQ); + prt = pr.pr_entry; + + if (bootverbose) { + device_printf(pcib, "matched entry for %d.%d.INT%c", + pci_get_bus(dev), pci_get_slot(dev), 'A' + pin); + if (prt->Source != NULL && prt->Source[0] != '\0') + printf(" (src %s:%u)", prt->Source, prt->SourceIndex); + printf("\n"); + } +#endif + /* * If source is empty/NULL, the source index is a global IRQ number * and it's hard-wired so we're done. @@ -154,6 +285,22 @@ goto out; } +#ifdef NEW_STUFF + /* + * We have to find the source device (PCI interrupt link device). + */ + if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, prt->Source, &lnkdev))) { + device_printf(pcib, "couldn't find PCI interrupt link device %s\n", + prt->Source); + goto out; + } + interrupt = acpi_pci_link_route_interrupt(acpi_get_device(lnkdev), + prt->SourceIndex); + + if (bootverbose && PCI_INTERRUPT_VALID(interrupt)) + device_printf(pcib, "slot %d INT%c routed to irq %d via %s\n", + pci_get_slot(dev), 'A' + pin, interrupt, acpi_name(lnkdev)); +#else /* XXX Support for multiple resources must be added to the link code. */ if (prt->SourceIndex) { device_printf(pcib, "src index %d not yet supported\n", @@ -196,6 +343,7 @@ device_printf(pcib, "slot %d INT%c routed to irq %d via %s\n", pci_get_slot(dev), 'A' + pin, interrupt, acpi_name(entry->prt_source)); +#endif out: ACPI_SERIAL_END(pcib); --- //depot/vendor/freebsd/src/sys/dev/acpica/acpi_pcib_acpi.c 2004/08/11 14:55:31 +++ //depot/user/jhb/acpipci/dev/acpica/acpi_pcib_acpi.c 2004/09/14 21:24:45 @@ -188,8 +188,8 @@ device_printf(dev, "couldn't find _ADR\n"); } else { /* XXX: We assume bus 0. */ - slot = addr >> 16; - func = addr & 0xffff; + slot = ACPI_ADR_PCI_SLOT(addr); + func = ACPI_ADR_PCI_FUNC(addr); if (bootverbose) device_printf(dev, "reading config registers from 0:%d:%d\n", slot, func); @@ -228,7 +228,7 @@ sc->ap_segment = 0; } - return (acpi_pcib_attach(dev, &sc->ap_prt, sc->ap_bus)); + return (acpi_pcib_attach(dev, &sc->ap_prt, sc->ap_bus, 1)); } static int @@ -256,7 +256,7 @@ case ACPI_IVAR_FLAGS: *result = (uintptr_t)sc->ap_flags; return (0); - } + } return (ENOENT); } @@ -296,8 +296,9 @@ static int acpi_pcib_acpi_route_interrupt(device_t pcib, device_t dev, int pin) { + struct acpi_hpcib_softc *sc = device_get_softc(pcib); - return (acpi_pcib_route_interrupt(pcib, dev, pin)); + return (acpi_pcib_route_interrupt(pcib, dev, pin, &sc->ap_prt)); } struct resource * --- //depot/vendor/freebsd/src/sys/dev/acpica/acpi_pcib_pci.c 2004/08/11 14:55:31 +++ //depot/user/jhb/acpipci/dev/acpica/acpi_pcib_pci.c 2004/09/13 19:36:35 @@ -133,7 +133,7 @@ pcib_attach_common(dev); sc = device_get_softc(dev); sc->ap_handle = acpi_get_handle(dev); - return (acpi_pcib_attach(dev, &sc->ap_prt, sc->ap_pcibsc.secbus)); + return (acpi_pcib_attach(dev, &sc->ap_prt, sc->ap_pcibsc.secbus, 0)); } static int @@ -170,5 +170,5 @@ if (sc->ap_prt.Pointer == NULL) return (pcib_route_interrupt(pcib, dev, pin)); else - return (acpi_pcib_route_interrupt(pcib, dev, pin)); + return (acpi_pcib_route_interrupt(pcib, dev, pin, &sc->ap_prt)); } --- //depot/vendor/freebsd/src/sys/dev/acpica/acpi_pcibvar.h 2004/08/11 14:55:31 +++ //depot/user/jhb/acpipci/dev/acpica/acpi_pcibvar.h 2004/09/14 22:01:39 @@ -30,14 +30,19 @@ #ifndef _ACPI_PCIBVAR_H_ #define _ACPI_PCIBVAR_H_ -int acpi_pcib_attach(device_t bus, ACPI_BUFFER *prt, int busno); -int acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin); +#define NEW_STUFF + +int acpi_pcib_attach(device_t bus, ACPI_BUFFER *prt, int busno, + int hostbridge); +int acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin, + ACPI_BUFFER *prtbuf); int acpi_pcib_resume(device_t dev); #define MAX_POSSIBLE_INTERRUPTS 16 #define MAX_ISA_INTERRUPTS 16 #define MAX_ACPI_INTERRUPTS 255 +#ifndef NEW_STUFF struct acpi_pci_link_entry { TAILQ_ENTRY(acpi_pci_link_entry) links; ACPI_HANDLE handle; @@ -69,4 +74,14 @@ int pin); int acpi_pci_link_route(device_t dev, struct acpi_prt_entry *prt); +#else +/* + * XXX: Should this really be a KOBJ interface? + */ +void acpi_pci_link_add_reference(device_t dev, int index, device_t pcib, + int slot, int pin); +int acpi_pci_link_route_interrupt(device_t dev, int index); +#endif + + #endif --- //depot/vendor/freebsd/src/sys/dev/acpica/acpivar.h 2004/08/23 16:30:40 +++ //depot/user/jhb/acpipci/dev/acpica/acpivar.h 2004/09/13 21:10:57 @@ -98,6 +98,10 @@ /* Flags for each device defined in the AML namespace. */ #define ACPI_FLAG_WAKE_ENABLED 0x1 +/* Macros for extracting parts of a PCI address from an _ADR value. */ +#define ACPI_ADR_PCI_SLOT(adr) (((adr) & 0xffff0000) >> 16) +#define ACPI_ADR_PCI_FUNC(adr) ((adr) & 0xffff) + /* * Entry points to ACPI from above are global functions defined in this * file, sysctls, and I/O on the control device. Entry points from below