1178172Simp/*- 2178172Simp * Copyright (c) 2000 Michael Smith 3178172Simp * Copyright (c) 2000 BSDi 4178172Simp * All rights reserved. 5178172Simp * 6178172Simp * Redistribution and use in source and binary forms, with or without 7178172Simp * modification, are permitted provided that the following conditions 8178172Simp * are met: 9178172Simp * 1. Redistributions of source code must retain the above copyright 10178172Simp * notice, this list of conditions and the following disclaimer. 11178172Simp * 2. Redistributions in binary form must reproduce the above copyright 12178172Simp * notice, this list of conditions and the following disclaimer in the 13178172Simp * documentation and/or other materials provided with the distribution. 14178172Simp * 15178172Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16178172Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17178172Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18178172Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19178172Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20178172Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21178172Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22178172Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23178172Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24178172Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25178172Simp * SUCH DAMAGE. 26178172Simp */ 27178172Simp 28178172Simp#include <sys/cdefs.h> 29178172Simp__FBSDID("$FreeBSD$"); 30178172Simp 31178172Simp#include "opt_acpi.h" 32178172Simp#include <sys/param.h> 33178172Simp#include <sys/bus.h> 34178172Simp#include <sys/malloc.h> 35178172Simp#include <sys/kernel.h> 36178172Simp 37178172Simp#include <contrib/dev/acpica/include/acpi.h> 38178172Simp#include <contrib/dev/acpica/include/accommon.h> 39178172Simp 40178172Simp#include <dev/acpica/acpivar.h> 41178172Simp#include <dev/acpica/acpi_pcibvar.h> 42178172Simp 43178172Simp#include <dev/pci/pcivar.h> 44178172Simp#include "pcib_if.h" 45178172Simp 46210403Smav/* Hooks for the ACPI CA debugging infrastructure. */ 47178172Simp#define _COMPONENT ACPI_BUS 48178172SimpACPI_MODULE_NAME("PCI") 49203746Sneel 50178172SimpACPI_SERIAL_DECL(pcib, "ACPI PCI bus methods"); 51178172Simp 52178172Simp/* 53178172Simp * For locking, we assume the caller is not concurrent since this is 54178172Simp * triggered by newbus methods. 55178172Simp */ 56205364Sneel 57205364Sneelstruct prt_lookup_request { 58215701Sdim ACPI_PCI_ROUTING_TABLE *pr_entry; 59210403Smav u_int pr_pin; 60178172Simp u_int pr_slot; 61215701Sdim}; 62215701Sdim 63215701Sdimtypedef void prt_entry_handler(ACPI_PCI_ROUTING_TABLE *entry, void *arg); 64215701Sdim 65178172Simpstatic void prt_attach_devices(ACPI_PCI_ROUTING_TABLE *entry, void *arg); 66210403Smavstatic void prt_lookup_device(ACPI_PCI_ROUTING_TABLE *entry, void *arg); 67210403Smavstatic void prt_walk_table(ACPI_BUFFER *prt, prt_entry_handler *handler, 68210403Smav void *arg); 69210403Smav 70210403Smavstatic void 71210403Smavprt_walk_table(ACPI_BUFFER *prt, prt_entry_handler *handler, void *arg) 72210403Smav{ 73210403Smav ACPI_PCI_ROUTING_TABLE *entry; 74210403Smav char *prtptr; 75178172Simp 76178172Simp /* First check to see if there is a table to walk. */ 77178172Simp if (prt == NULL || prt->Pointer == NULL) 78178172Simp return; 79178172Simp 80178172Simp /* Walk the table executing the handler function for each entry. */ 81178172Simp prtptr = prt->Pointer; 82178172Simp entry = (ACPI_PCI_ROUTING_TABLE *)prtptr; 83178172Simp while (entry->Length != 0) { 84178172Simp handler(entry, arg); 85178172Simp prtptr += entry->Length; 86178172Simp entry = (ACPI_PCI_ROUTING_TABLE *)prtptr; 87178172Simp } 88178172Simp} 89178172Simp 90178172Simpstatic void 91178172Simpprt_attach_devices(ACPI_PCI_ROUTING_TABLE *entry, void *arg) 92202046Simp{ 93178172Simp ACPI_HANDLE handle; 94203746Sneel device_t child, pcib; 95205364Sneel int error; 96205364Sneel 97178172Simp /* We only care about entries that reference a link device. */ 98178172Simp if (entry->Source == NULL || entry->Source[0] == '\0') 99178172Simp return; 100178172Simp 101178172Simp /* 102178172Simp * In practice, we only see SourceIndex's of 0 out in the wild. 103178172Simp * When indices != 0 have been found, they've been bugs in the ASL. 104210854Sneel */ 105178172Simp if (entry->SourceIndex != 0) 106178172Simp return; 107210854Sneel 108178172Simp /* Lookup the associated handle and device. */ 109210854Sneel pcib = (device_t)arg; 110210854Sneel if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, entry->Source, &handle))) 111210854Sneel return; 112210854Sneel child = acpi_get_device(handle); 113210854Sneel if (child == NULL) 114210854Sneel return; 115210854Sneel 116210854Sneel /* If the device hasn't been probed yet, force it to do so. */ 117210854Sneel error = device_probe_and_attach(child); 118210854Sneel if (error != 0) { 119210854Sneel device_printf(pcib, "failed to force attach of %s\n", 120210854Sneel acpi_name(handle)); 121210854Sneel return; 122210854Sneel } 123210854Sneel 124178172Simp /* Add a reference for a specific bus/device/pin tuple. */ 125210854Sneel acpi_pci_link_add_reference(child, entry->SourceIndex, pcib, 126178172Simp ACPI_ADR_PCI_SLOT(entry->Address), entry->Pin); 127178172Simp} 128210854Sneel 129210854Sneelint 130210854Sneelacpi_pcib_attach(device_t dev, ACPI_BUFFER *prt, int busno) 131210854Sneel{ 132210854Sneel ACPI_STATUS status; 133178172Simp 134178172Simp ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 135178172Simp 136178172Simp /* 137178172Simp * Get the PCI interrupt routing table for this bus. If we can't 138178172Simp * get it, this is not an error but may reduce functionality. There 139178172Simp * are several valid bridges in the field that do not have a _PRT, so 140178172Simp * only warn about missing tables if bootverbose is set. 141178172Simp */ 142178172Simp prt->Length = ACPI_ALLOCATE_BUFFER; 143178172Simp status = AcpiGetIrqRoutingTable(acpi_get_handle(dev), prt); 144178172Simp if (ACPI_FAILURE(status) && (bootverbose || status != AE_NOT_FOUND)) 145202046Simp device_printf(dev, 146202046Simp "could not get PCI interrupt routing table for %s - %s\n", 147202046Simp acpi_name(acpi_get_handle(dev)), AcpiFormatException(status)); 148202797Simp 149202046Simp /* 150202046Simp * Attach the PCI bus proper. 151202046Simp */ 152202046Simp if (device_add_child(dev, "pci", busno) == NULL) { 153178172Simp device_printf(device_get_parent(dev), "couldn't attach pci bus\n"); 154178172Simp return_VALUE(ENXIO); 155178172Simp } 156178172Simp 157178172Simp /* 158178172Simp * Now go scan the bus. 159178172Simp */ 160178172Simp prt_walk_table(prt, prt_attach_devices, dev); 161178172Simp 162178172Simp return_VALUE (bus_generic_attach(dev)); 163210403Smav} 164178172Simp 165178172Simpstatic void 166217616Smdfprt_lookup_device(ACPI_PCI_ROUTING_TABLE *entry, void *arg) 167178172Simp{ 168178172Simp struct prt_lookup_request *pr; 169210403Smav 170210403Smav pr = (struct prt_lookup_request *)arg; 171178172Simp if (pr->pr_entry != NULL) 172178172Simp return; 173178172Simp 174178172Simp /* 175217616Smdf * Compare the slot number (high word of Address) and pin number 176217616Smdf * (note that ACPI uses 0 for INTA) to check for a match. 177181236Strhodes * 178178172Simp * Note that the low word of the Address field (function number) 179178172Simp * is required by the specification to be 0xffff. We don't risk 180178172Simp * checking it here. 181178172Simp */ 182178172Simp if (ACPI_ADR_PCI_SLOT(entry->Address) == pr->pr_slot && 183178172Simp entry->Pin == pr->pr_pin) 184178172Simp pr->pr_entry = entry; 185178172Simp} 186178172Simp 187178172Simp/* 188178172Simp * Route an interrupt for a child of the bridge. 189178172Simp */ 190178172Simpint 191178172Simpacpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin, 192178172Simp ACPI_BUFFER *prtbuf) 193178172Simp{ 194178172Simp ACPI_PCI_ROUTING_TABLE *prt; 195178172Simp struct prt_lookup_request pr; 196178172Simp ACPI_HANDLE lnkdev; 197178172Simp int interrupt; 198178172Simp 199178172Simp ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 200178172Simp 201178172Simp interrupt = PCI_INVALID_IRQ; 202178172Simp 203178172Simp /* ACPI numbers pins 0-3, not 1-4 like the BIOS. */ 204178172Simp pin--; 205178172Simp 206202046Simp ACPI_SERIAL_BEGIN(pcib); 207178172Simp 208202046Simp /* Search for a matching entry in the routing table. */ 209178172Simp pr.pr_entry = NULL; 210178172Simp pr.pr_pin = pin; 211178172Simp pr.pr_slot = pci_get_slot(dev); 212178172Simp prt_walk_table(prtbuf, prt_lookup_device, &pr); 213178172Simp if (pr.pr_entry == NULL) { 214178172Simp device_printf(pcib, "no PRT entry for %d.%d.INT%c\n", pci_get_bus(dev), 215178172Simp pci_get_slot(dev), 'A' + pin); 216178172Simp goto out; 217178172Simp } 218178172Simp prt = pr.pr_entry; 219210403Smav 220247463Smav if (bootverbose) { 221210403Smav device_printf(pcib, "matched entry for %d.%d.INT%c", 222210403Smav pci_get_bus(dev), pci_get_slot(dev), 'A' + pin); 223210403Smav if (prt->Source != NULL && prt->Source[0] != '\0') 224247463Smav printf(" (src %s:%u)", prt->Source, prt->SourceIndex); 225247463Smav printf("\n"); 226210403Smav } 227210403Smav 228247463Smav /* 229247463Smav * If source is empty/NULL, the source index is a global IRQ number 230247463Smav * and it's hard-wired so we're done. 231210403Smav * 232210403Smav * XXX: If the source index is non-zero, ignore the source device and 233210403Smav * assume that this is a hard-wired entry. 234210403Smav */ 235210403Smav if (prt->Source == NULL || prt->Source[0] == '\0' || 236210403Smav prt->SourceIndex != 0) { 237210403Smav if (bootverbose) 238210403Smav device_printf(pcib, "slot %d INT%c hardwired to IRQ %d\n", 239210403Smav pci_get_slot(dev), 'A' + pin, prt->SourceIndex); 240210403Smav if (prt->SourceIndex) { 241210403Smav interrupt = prt->SourceIndex; 242210403Smav BUS_CONFIG_INTR(dev, interrupt, INTR_TRIGGER_LEVEL, 243210403Smav INTR_POLARITY_LOW); 244210403Smav } else 245210403Smav device_printf(pcib, "error: invalid hard-wired IRQ of 0\n"); 246210403Smav goto out; 247210403Smav } 248178172Simp 249178172Simp /* 250178172Simp * We have to find the source device (PCI interrupt link device). 251178172Simp */ 252178172Simp if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, prt->Source, &lnkdev))) { 253178172Simp device_printf(pcib, "couldn't find PCI interrupt link device %s\n", 254210403Smav prt->Source); 255210403Smav goto out; 256208585Sneel } 257205576Sneel interrupt = acpi_pci_link_route_interrupt(acpi_get_device(lnkdev), 258210403Smav prt->SourceIndex); 259178172Simp 260178172Simp if (bootverbose && PCI_INTERRUPT_VALID(interrupt)) 261178172Simp device_printf(pcib, "slot %d INT%c routed to irq %d via %s\n", 262205576Sneel pci_get_slot(dev), 'A' + pin, interrupt, acpi_name(lnkdev)); 263208585Sneel 264210403Smavout: 265210403Smav ACPI_SERIAL_END(pcib); 266210403Smav 267210403Smav return_VALUE (interrupt); 268210404Smav} 269210403Smav 270208585Sneelint 271210854Sneelacpi_pcib_power_for_sleep(device_t pcib, device_t dev, int *pstate) 272210854Sneel{ 273210854Sneel device_t acpi_dev; 274178172Simp 275210854Sneel acpi_dev = devclass_get_device(devclass_find("acpi"), 0); 276208585Sneel acpi_device_pwr_for_sleep(acpi_dev, dev, pstate); 277210403Smav return (0); 278178172Simp} 279210403Smav 280210403Smav