1 /*- 2 * Copyright (c) 2000 Michael Smith 3 * Copyright (c) 2000 BSDi 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include "opt_acpi.h" 32 #include <sys/param.h> 33 #include <sys/bus.h> 34 #include <sys/malloc.h> 35 #include <sys/kernel.h> 36 37 #include "acpi.h" 38 #include <dev/acpica/acpivar.h> 39 #include <dev/acpica/acpi_pcibvar.h> 40 41 #include <dev/pci/pcivar.h> 42 #include "pcib_if.h" 43 44 /* Hooks for the ACPI CA debugging infrastructure. */ 45 #define _COMPONENT ACPI_BUS 46 ACPI_MODULE_NAME("PCI") 47 48 ACPI_SERIAL_DECL(pcib, "ACPI PCI bus methods"); 49 50 /* 51 * For locking, we assume the caller is not concurrent since this is 52 * triggered by newbus methods. 53 */ 54 int 55 acpi_pcib_attach(device_t dev, ACPI_BUFFER *prt, int busno) 56 { 57 device_t child; 58 ACPI_STATUS status; 59 60 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 61 62 /* 63 * Don't attach if we're not really there. 64 * 65 * XXX: This isn't entirely correct since we may be a PCI bus 66 * on a hot-plug docking station, etc. 67 */ 68 if (!acpi_DeviceIsPresent(dev)) 69 return_VALUE(ENXIO); 70 71 /* 72 * Get the PCI interrupt routing table for this bus. If we can't 73 * get it, this is not an error but may reduce functionality. 74 */ 75 prt->Length = ACPI_ALLOCATE_BUFFER; 76 status = AcpiGetIrqRoutingTable(acpi_get_handle(dev), prt); 77 if (ACPI_FAILURE(status)) 78 device_printf(dev, 79 "could not get PCI interrupt routing table for %s - %s\n", 80 acpi_name(acpi_get_handle(dev)), AcpiFormatException(status)); 81 82 /* 83 * Attach the PCI bus proper. 84 */ 85 if ((child = device_add_child(dev, "pci", busno)) == NULL) { 86 device_printf(device_get_parent(dev), "couldn't attach pci bus\n"); 87 return_VALUE(ENXIO); 88 } 89 90 /* 91 * Now go scan the bus. 92 */ 93 acpi_pci_link_config(dev, prt, busno); 94 95 return_VALUE (bus_generic_attach(dev)); 96 } 97 98 int 99 acpi_pcib_resume(device_t dev) 100 { 101 acpi_pci_link_resume(dev); 102 return (bus_generic_resume(dev)); 103 } 104 105 /* 106 * Route an interrupt for a child of the bridge. 107 */ 108 int 109 acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin) 110 { 111 struct acpi_prt_entry *entry; 112 int i, interrupt; 113 struct acpi_pci_link_entry *link; 114 ACPI_PCI_ROUTING_TABLE *prt; 115 116 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 117 118 interrupt = PCI_INVALID_IRQ; 119 120 /* ACPI numbers pins 0-3, not 1-4 like the BIOS. */ 121 pin--; 122 123 ACPI_SERIAL_BEGIN(pcib); 124 125 /* Look up the PRT entry for this device. */ 126 entry = acpi_pci_find_prt(pcib, dev, pin); 127 if (entry == NULL) { 128 device_printf(pcib, "no PRT entry for %d.%d.INT%c\n", pci_get_bus(dev), 129 pci_get_slot(dev), 'A' + pin); 130 goto out; 131 } 132 prt = &entry->prt; 133 link = entry->pci_link; 134 if (bootverbose) { 135 device_printf(pcib, "matched entry for %d.%d.INT%c", 136 pci_get_bus(dev), pci_get_slot(dev), 'A' + pin); 137 if (prt->Source[0] != '\0') 138 printf(" (src %s)", acpi_name(entry->prt_source)); 139 printf("\n"); 140 } 141 142 /* 143 * If source is empty/NULL, the source index is a global IRQ number 144 * and it's hard-wired so we're done. 145 */ 146 if (prt->Source == NULL || prt->Source[0] == '\0') { 147 if (bootverbose) 148 device_printf(pcib, "slot %d INT%c hardwired to IRQ %d\n", 149 pci_get_slot(dev), 'A' + pin, prt->SourceIndex); 150 if (prt->SourceIndex) 151 interrupt = prt->SourceIndex; 152 else 153 device_printf(pcib, "error: invalid hard-wired IRQ of 0\n"); 154 goto out; 155 } 156 157 /* XXX Support for multiple resources must be added to the link code. */ 158 if (prt->SourceIndex) { 159 device_printf(pcib, "src index %d not yet supported\n", 160 prt->SourceIndex); 161 goto out; 162 } 163 164 /* There has to be at least one interrupt available. */ 165 if (link->number_of_interrupts == 0) { 166 device_printf(pcib, "device has no interrupts\n"); 167 goto out; 168 } 169 170 /* 171 * If the current interrupt has been routed, we're done. This is the 172 * case when the BIOS initializes it and we didn't disable it. 173 */ 174 if (link->flags & ACPI_LINK_ROUTED) { 175 interrupt = link->current_irq; 176 if (bootverbose) 177 device_printf(pcib, "slot %d INT%c is already routed to irq %d\n", 178 pci_get_slot(dev), 'A' + pin, interrupt); 179 goto out; 180 } 181 182 if (bootverbose) { 183 device_printf(pcib, "possible interrupts:"); 184 for (i = 0; i < link->number_of_interrupts; i++) 185 printf("%3d", link->interrupts[i]); 186 printf("\n"); 187 } 188 189 /* 190 * Perform the link routing. The link code will pick the best IRQ 191 * for this pin and configure it. 192 */ 193 interrupt = acpi_pci_link_route(dev, entry); 194 195 if (bootverbose && PCI_INTERRUPT_VALID(interrupt)) 196 device_printf(pcib, "slot %d INT%c routed to irq %d via %s\n", 197 pci_get_slot(dev), 'A' + pin, interrupt, 198 acpi_name(entry->prt_source)); 199 200 out: 201 ACPI_SERIAL_END(pcib); 202 203 return_VALUE (interrupt); 204 } 205