115e32d5dSMike Smith /*- 215e32d5dSMike Smith * Copyright (c) 2000 Michael Smith 315e32d5dSMike Smith * Copyright (c) 2000 BSDi 415e32d5dSMike Smith * All rights reserved. 515e32d5dSMike Smith * 615e32d5dSMike Smith * Redistribution and use in source and binary forms, with or without 715e32d5dSMike Smith * modification, are permitted provided that the following conditions 815e32d5dSMike Smith * are met: 915e32d5dSMike Smith * 1. Redistributions of source code must retain the above copyright 1015e32d5dSMike Smith * notice, this list of conditions and the following disclaimer. 1115e32d5dSMike Smith * 2. Redistributions in binary form must reproduce the above copyright 1215e32d5dSMike Smith * notice, this list of conditions and the following disclaimer in the 1315e32d5dSMike Smith * documentation and/or other materials provided with the distribution. 1415e32d5dSMike Smith * 1515e32d5dSMike Smith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1615e32d5dSMike Smith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1715e32d5dSMike Smith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1815e32d5dSMike Smith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1915e32d5dSMike Smith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2015e32d5dSMike Smith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2115e32d5dSMike Smith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2215e32d5dSMike Smith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2315e32d5dSMike Smith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2415e32d5dSMike Smith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2515e32d5dSMike Smith * SUCH DAMAGE. 2615e32d5dSMike Smith */ 27aad970f1SDavid E. O'Brien 28aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 29aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 30aad970f1SDavid E. O'Brien 3115e32d5dSMike Smith #include "opt_acpi.h" 3215e32d5dSMike Smith #include <sys/param.h> 3315e32d5dSMike Smith #include <sys/bus.h> 344fa387b6SMike Smith #include <sys/malloc.h> 354fa387b6SMike Smith #include <sys/kernel.h> 3615e32d5dSMike Smith 3715e32d5dSMike Smith #include "acpi.h" 3815e32d5dSMike Smith #include <dev/acpica/acpivar.h> 392ccfc932SJohn Baldwin #include <dev/acpica/acpi_pcibvar.h> 4015e32d5dSMike Smith 41cace7a2aSWarner Losh #include <dev/pci/pcivar.h> 4215e32d5dSMike Smith #include "pcib_if.h" 4315e32d5dSMike Smith 443304735dSNate Lawson /* Hooks for the ACPI CA debugging infrastructure. */ 45e71b6381SMike Smith #define _COMPONENT ACPI_BUS 46c1b1f787SMike Smith ACPI_MODULE_NAME("PCI") 470ae55423SMike Smith 48bbf7c27aSNate Lawson ACPI_SERIAL_DECL(pcib, "ACPI PCI bus methods"); 49bbf7c27aSNate Lawson 50bbf7c27aSNate Lawson /* 51bbf7c27aSNate Lawson * For locking, we assume the caller is not concurrent since this is 52bbf7c27aSNate Lawson * triggered by newbus methods. 53bbf7c27aSNate Lawson */ 545e1ba6d4SJohn Baldwin 555e1ba6d4SJohn Baldwin struct prt_lookup_request { 565e1ba6d4SJohn Baldwin ACPI_PCI_ROUTING_TABLE *pr_entry; 575e1ba6d4SJohn Baldwin u_int pr_pin; 585e1ba6d4SJohn Baldwin u_int pr_slot; 595e1ba6d4SJohn Baldwin }; 605e1ba6d4SJohn Baldwin 615e1ba6d4SJohn Baldwin typedef void prt_entry_handler(ACPI_PCI_ROUTING_TABLE *entry, void *arg); 625e1ba6d4SJohn Baldwin 635e1ba6d4SJohn Baldwin static void prt_attach_devices(ACPI_PCI_ROUTING_TABLE *entry, void *arg); 645e1ba6d4SJohn Baldwin static void prt_lookup_device(ACPI_PCI_ROUTING_TABLE *entry, void *arg); 655e1ba6d4SJohn Baldwin static void prt_walk_table(ACPI_BUFFER *prt, prt_entry_handler *handler, 665e1ba6d4SJohn Baldwin void *arg); 675e1ba6d4SJohn Baldwin 685e1ba6d4SJohn Baldwin static void 695e1ba6d4SJohn Baldwin prt_walk_table(ACPI_BUFFER *prt, prt_entry_handler *handler, void *arg) 705e1ba6d4SJohn Baldwin { 715e1ba6d4SJohn Baldwin ACPI_PCI_ROUTING_TABLE *entry; 725e1ba6d4SJohn Baldwin char *prtptr; 735e1ba6d4SJohn Baldwin 745e1ba6d4SJohn Baldwin /* First check to see if there is a table to walk. */ 755e1ba6d4SJohn Baldwin if (prt == NULL || prt->Pointer == NULL) 765e1ba6d4SJohn Baldwin return; 775e1ba6d4SJohn Baldwin 785e1ba6d4SJohn Baldwin /* Walk the table executing the handler function for each entry. */ 795e1ba6d4SJohn Baldwin prtptr = prt->Pointer; 805e1ba6d4SJohn Baldwin entry = (ACPI_PCI_ROUTING_TABLE *)prtptr; 815e1ba6d4SJohn Baldwin while (entry->Length != 0) { 825e1ba6d4SJohn Baldwin handler(entry, arg); 835e1ba6d4SJohn Baldwin prtptr += entry->Length; 845e1ba6d4SJohn Baldwin entry = (ACPI_PCI_ROUTING_TABLE *)prtptr; 855e1ba6d4SJohn Baldwin } 865e1ba6d4SJohn Baldwin } 875e1ba6d4SJohn Baldwin 885e1ba6d4SJohn Baldwin static void 895e1ba6d4SJohn Baldwin prt_attach_devices(ACPI_PCI_ROUTING_TABLE *entry, void *arg) 905e1ba6d4SJohn Baldwin { 915e1ba6d4SJohn Baldwin ACPI_HANDLE handle; 925e1ba6d4SJohn Baldwin device_t child, pcib; 935e1ba6d4SJohn Baldwin int error; 945e1ba6d4SJohn Baldwin 955e1ba6d4SJohn Baldwin /* We only care about entries that reference a link device. */ 965e1ba6d4SJohn Baldwin if (entry->Source == NULL || entry->Source[0] == '\0') 975e1ba6d4SJohn Baldwin return; 985e1ba6d4SJohn Baldwin 995e1ba6d4SJohn Baldwin /* Lookup the associated handle and device. */ 1005e1ba6d4SJohn Baldwin pcib = (device_t)arg; 1015e1ba6d4SJohn Baldwin if (ACPI_FAILURE(AcpiGetHandle(acpi_get_handle(pcib), entry->Source, 1025e1ba6d4SJohn Baldwin &handle))) 1035e1ba6d4SJohn Baldwin return; 1045e1ba6d4SJohn Baldwin child = acpi_get_device(handle); 1055e1ba6d4SJohn Baldwin if (child == NULL) 1065e1ba6d4SJohn Baldwin return; 1075e1ba6d4SJohn Baldwin 1085e1ba6d4SJohn Baldwin /* If the device hasn't been probed yet, force it to do so. */ 1095e1ba6d4SJohn Baldwin error = device_probe_and_attach(child); 1105e1ba6d4SJohn Baldwin if (error != 0) { 1115e1ba6d4SJohn Baldwin device_printf((device_t)arg, "failed to force attach of %s\n", 1125e1ba6d4SJohn Baldwin acpi_name(handle)); 1135e1ba6d4SJohn Baldwin return; 1145e1ba6d4SJohn Baldwin } 1155e1ba6d4SJohn Baldwin 1165e1ba6d4SJohn Baldwin /* Add a reference for a specific bus/device/pin tuple. */ 1175e1ba6d4SJohn Baldwin acpi_pci_link_add_reference(child, entry->SourceIndex, pcib, 1185e1ba6d4SJohn Baldwin ACPI_ADR_PCI_SLOT(entry->Address), entry->Pin); 1195e1ba6d4SJohn Baldwin } 1205e1ba6d4SJohn Baldwin 1212ccfc932SJohn Baldwin int 1222ccfc932SJohn Baldwin acpi_pcib_attach(device_t dev, ACPI_BUFFER *prt, int busno) 12315e32d5dSMike Smith { 12415e32d5dSMike Smith device_t child; 12515e32d5dSMike Smith ACPI_STATUS status; 1260ae55423SMike Smith 127b4a05238SPeter Wemm ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 12815e32d5dSMike Smith 12915e32d5dSMike Smith /* 13015e32d5dSMike Smith * Don't attach if we're not really there. 13115e32d5dSMike Smith * 1322ccfc932SJohn Baldwin * XXX: This isn't entirely correct since we may be a PCI bus 13315e32d5dSMike Smith * on a hot-plug docking station, etc. 13415e32d5dSMike Smith */ 13515e32d5dSMike Smith if (!acpi_DeviceIsPresent(dev)) 1360ae55423SMike Smith return_VALUE(ENXIO); 13715e32d5dSMike Smith 13815e32d5dSMike Smith /* 1393304735dSNate Lawson * Get the PCI interrupt routing table for this bus. If we can't 14020447d54SJohn Baldwin * get it, this is not an error but may reduce functionality. There 14120447d54SJohn Baldwin * are several valid bridges in the field that do not have a _PRT, so 14220447d54SJohn Baldwin * only warn about missing tables if bootverbose is set. 1434fa387b6SMike Smith */ 1442ccfc932SJohn Baldwin prt->Length = ACPI_ALLOCATE_BUFFER; 1452ccfc932SJohn Baldwin status = AcpiGetIrqRoutingTable(acpi_get_handle(dev), prt); 14620447d54SJohn Baldwin if (ACPI_FAILURE(status) && (bootverbose || status != AE_NOT_FOUND)) 147f144391bSPeter Wemm device_printf(dev, 148f144391bSPeter Wemm "could not get PCI interrupt routing table for %s - %s\n", 149f144391bSPeter Wemm acpi_name(acpi_get_handle(dev)), AcpiFormatException(status)); 1504fa387b6SMike Smith 1514fa387b6SMike Smith /* 152042283a6SMike Smith * Attach the PCI bus proper. 15315e32d5dSMike Smith */ 1542ccfc932SJohn Baldwin if ((child = device_add_child(dev, "pci", busno)) == NULL) { 155ebc4ae3bSJohn Baldwin device_printf(device_get_parent(dev), "couldn't attach pci bus\n"); 1560ae55423SMike Smith return_VALUE(ENXIO); 15715e32d5dSMike Smith } 15815e32d5dSMike Smith 15915e32d5dSMike Smith /* 1603cd59d7bSScott Long * Now go scan the bus. 16115e32d5dSMike Smith */ 1625e1ba6d4SJohn Baldwin prt_walk_table(prt, prt_attach_devices, dev); 1633304735dSNate Lawson 1642ccfc932SJohn Baldwin return_VALUE (bus_generic_attach(dev)); 16515e32d5dSMike Smith } 16615e32d5dSMike Smith 167ba835e3fSMitsuru IWASAKI int 168e4116e93SNate Lawson acpi_pcib_resume(device_t dev) 169ba835e3fSMitsuru IWASAKI { 1705e1ba6d4SJohn Baldwin 171ba835e3fSMitsuru IWASAKI return (bus_generic_resume(dev)); 172ba835e3fSMitsuru IWASAKI } 173ba835e3fSMitsuru IWASAKI 1745e1ba6d4SJohn Baldwin static void 1755e1ba6d4SJohn Baldwin prt_lookup_device(ACPI_PCI_ROUTING_TABLE *entry, void *arg) 1765e1ba6d4SJohn Baldwin { 1775e1ba6d4SJohn Baldwin struct prt_lookup_request *pr; 1785e1ba6d4SJohn Baldwin 1795e1ba6d4SJohn Baldwin pr = (struct prt_lookup_request *)arg; 1805e1ba6d4SJohn Baldwin if (pr->pr_entry != NULL) 1815e1ba6d4SJohn Baldwin return; 1825e1ba6d4SJohn Baldwin 1835e1ba6d4SJohn Baldwin /* 1845e1ba6d4SJohn Baldwin * Compare the slot number (high word of Address) and pin number 1855e1ba6d4SJohn Baldwin * (note that ACPI uses 0 for INTA) to check for a match. 1865e1ba6d4SJohn Baldwin * 1875e1ba6d4SJohn Baldwin * Note that the low word of the Address field (function number) 1885e1ba6d4SJohn Baldwin * is required by the specification to be 0xffff. We don't risk 1895e1ba6d4SJohn Baldwin * checking it here. 1905e1ba6d4SJohn Baldwin */ 1915e1ba6d4SJohn Baldwin if (ACPI_ADR_PCI_SLOT(entry->Address) == pr->pr_slot && 1925e1ba6d4SJohn Baldwin entry->Pin == pr->pr_pin) 1935e1ba6d4SJohn Baldwin pr->pr_entry = entry; 1945e1ba6d4SJohn Baldwin } 1955e1ba6d4SJohn Baldwin 1964fa387b6SMike Smith /* 1974fa387b6SMike Smith * Route an interrupt for a child of the bridge. 1984fa387b6SMike Smith */ 1992ccfc932SJohn Baldwin int 2005e1ba6d4SJohn Baldwin acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin, 2015e1ba6d4SJohn Baldwin ACPI_BUFFER *prtbuf) 20215e32d5dSMike Smith { 203c1b1f787SMike Smith ACPI_PCI_ROUTING_TABLE *prt; 2045e1ba6d4SJohn Baldwin struct prt_lookup_request pr; 2055e1ba6d4SJohn Baldwin ACPI_HANDLE lnkdev; 2065e1ba6d4SJohn Baldwin int interrupt; 2074fa387b6SMike Smith 208b4a05238SPeter Wemm ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 2094c1cdee6SMike Smith 2104dc4ea26SJohn Baldwin interrupt = PCI_INVALID_IRQ; 2114fa387b6SMike Smith 2123304735dSNate Lawson /* ACPI numbers pins 0-3, not 1-4 like the BIOS. */ 2134fa387b6SMike Smith pin--; 2144fa387b6SMike Smith 215bbf7c27aSNate Lawson ACPI_SERIAL_BEGIN(pcib); 216bbf7c27aSNate Lawson 2175e1ba6d4SJohn Baldwin /* Search for a matching entry in the routing table. */ 2185e1ba6d4SJohn Baldwin pr.pr_entry = NULL; 2195e1ba6d4SJohn Baldwin pr.pr_pin = pin; 2205e1ba6d4SJohn Baldwin pr.pr_slot = pci_get_slot(dev); 2215e1ba6d4SJohn Baldwin prt_walk_table(prtbuf, prt_lookup_device, &pr); 2225e1ba6d4SJohn Baldwin if (pr.pr_entry == NULL) 2235e1ba6d4SJohn Baldwin return (PCI_INVALID_IRQ); 2245e1ba6d4SJohn Baldwin prt = pr.pr_entry; 2255e1ba6d4SJohn Baldwin 22612f57103SNate Lawson if (bootverbose) { 22712f57103SNate Lawson device_printf(pcib, "matched entry for %d.%d.INT%c", 22812f57103SNate Lawson pci_get_bus(dev), pci_get_slot(dev), 'A' + pin); 2295e1ba6d4SJohn Baldwin if (prt->Source != NULL && prt->Source[0] != '\0') 2305e1ba6d4SJohn Baldwin printf(" (src %s:%u)", prt->Source, prt->SourceIndex); 23112f57103SNate Lawson printf("\n"); 23212f57103SNate Lawson } 2334fa387b6SMike Smith 2344fa387b6SMike Smith /* 235e4116e93SNate Lawson * If source is empty/NULL, the source index is a global IRQ number 236e4116e93SNate Lawson * and it's hard-wired so we're done. 2374fa387b6SMike Smith */ 2383304735dSNate Lawson if (prt->Source == NULL || prt->Source[0] == '\0') { 239a067d210SDoug Rabson if (bootverbose) 240e4116e93SNate Lawson device_printf(pcib, "slot %d INT%c hardwired to IRQ %d\n", 241e4116e93SNate Lawson pci_get_slot(dev), 'A' + pin, prt->SourceIndex); 242e4116e93SNate Lawson if (prt->SourceIndex) 2434fa387b6SMike Smith interrupt = prt->SourceIndex; 244e4116e93SNate Lawson else 245e4116e93SNate Lawson device_printf(pcib, "error: invalid hard-wired IRQ of 0\n"); 2464fa387b6SMike Smith goto out; 2474fa387b6SMike Smith } 2484fa387b6SMike Smith 2495e1ba6d4SJohn Baldwin /* 2505e1ba6d4SJohn Baldwin * We have to find the source device (PCI interrupt link device). 2515e1ba6d4SJohn Baldwin */ 2525e1ba6d4SJohn Baldwin if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, prt->Source, &lnkdev))) { 2535e1ba6d4SJohn Baldwin device_printf(pcib, "couldn't find PCI interrupt link device %s\n", 2545e1ba6d4SJohn Baldwin prt->Source); 2555e1ba6d4SJohn Baldwin goto out; 2565e1ba6d4SJohn Baldwin } 2575e1ba6d4SJohn Baldwin interrupt = acpi_pci_link_route_interrupt(acpi_get_device(lnkdev), 258e4116e93SNate Lawson prt->SourceIndex); 2593304735dSNate Lawson 260e4116e93SNate Lawson if (bootverbose && PCI_INTERRUPT_VALID(interrupt)) 261c6a121abSJohn Baldwin device_printf(pcib, "slot %d INT%c routed to irq %d via %s\n", 2625e1ba6d4SJohn Baldwin pci_get_slot(dev), 'A' + pin, interrupt, acpi_name(lnkdev)); 2634fa387b6SMike Smith 2644fa387b6SMike Smith out: 265bbf7c27aSNate Lawson ACPI_SERIAL_END(pcib); 2664fa387b6SMike Smith 2674c1cdee6SMike Smith return_VALUE (interrupt); 2684fa387b6SMike Smith } 269