167761Smsmith/*- 267761Smsmith * Copyright (c) 2000 Michael Smith 367761Smsmith * Copyright (c) 2000 BSDi 467761Smsmith * All rights reserved. 567761Smsmith * 667761Smsmith * Redistribution and use in source and binary forms, with or without 767761Smsmith * modification, are permitted provided that the following conditions 867761Smsmith * are met: 967761Smsmith * 1. Redistributions of source code must retain the above copyright 1067761Smsmith * notice, this list of conditions and the following disclaimer. 1167761Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1267761Smsmith * notice, this list of conditions and the following disclaimer in the 1367761Smsmith * documentation and/or other materials provided with the distribution. 1467761Smsmith * 1567761Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1667761Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1767761Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1867761Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1967761Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2067761Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2167761Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2267761Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2367761Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2467761Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2567761Smsmith * SUCH DAMAGE. 2667761Smsmith */ 27119418Sobrien 28119418Sobrien#include <sys/cdefs.h> 29119418Sobrien__FBSDID("$FreeBSD$"); 30119418Sobrien 3167761Smsmith#include "opt_acpi.h" 3267761Smsmith#include <sys/param.h> 3379284Smsmith#include <sys/bus.h> 3479284Smsmith#include <sys/malloc.h> 3567761Smsmith#include <sys/kernel.h> 3667761Smsmith 37193530Sjkim#include <contrib/dev/acpica/include/acpi.h> 38193530Sjkim#include <contrib/dev/acpica/include/accommon.h> 39193530Sjkim 4067761Smsmith#include <dev/acpica/acpivar.h> 41102447Sjhb#include <dev/acpica/acpi_pcibvar.h> 4267761Smsmith 43119281Simp#include <dev/pci/pcivar.h> 4467761Smsmith#include "pcib_if.h" 4567761Smsmith 46127314Snjl/* Hooks for the ACPI CA debugging infrastructure. */ 4778993Smsmith#define _COMPONENT ACPI_BUS 4891124SmsmithACPI_MODULE_NAME("PCI") 4969744Smsmith 50133621SnjlACPI_SERIAL_DECL(pcib, "ACPI PCI bus methods"); 51133621Snjl 52133621Snjl/* 53133621Snjl * For locking, we assume the caller is not concurrent since this is 54133621Snjl * triggered by newbus methods. 55133621Snjl */ 56138033Sjhb 57138033Sjhbstruct prt_lookup_request { 58138033Sjhb ACPI_PCI_ROUTING_TABLE *pr_entry; 59138033Sjhb u_int pr_pin; 60138033Sjhb u_int pr_slot; 61138033Sjhb}; 62139339Snjl 63138033Sjhbtypedef void prt_entry_handler(ACPI_PCI_ROUTING_TABLE *entry, void *arg); 64138033Sjhb 65138033Sjhbstatic void prt_attach_devices(ACPI_PCI_ROUTING_TABLE *entry, void *arg); 66138033Sjhbstatic void prt_lookup_device(ACPI_PCI_ROUTING_TABLE *entry, void *arg); 67138033Sjhbstatic void prt_walk_table(ACPI_BUFFER *prt, prt_entry_handler *handler, 68138033Sjhb void *arg); 69138033Sjhb 70138033Sjhbstatic void 71138033Sjhbprt_walk_table(ACPI_BUFFER *prt, prt_entry_handler *handler, void *arg) 72138033Sjhb{ 73138033Sjhb ACPI_PCI_ROUTING_TABLE *entry; 74138033Sjhb char *prtptr; 75138033Sjhb 76138033Sjhb /* First check to see if there is a table to walk. */ 77138033Sjhb if (prt == NULL || prt->Pointer == NULL) 78138033Sjhb return; 79138033Sjhb 80138033Sjhb /* Walk the table executing the handler function for each entry. */ 81138033Sjhb prtptr = prt->Pointer; 82138033Sjhb entry = (ACPI_PCI_ROUTING_TABLE *)prtptr; 83138033Sjhb while (entry->Length != 0) { 84138033Sjhb handler(entry, arg); 85138033Sjhb prtptr += entry->Length; 86138033Sjhb entry = (ACPI_PCI_ROUTING_TABLE *)prtptr; 87138033Sjhb } 88138033Sjhb} 89138033Sjhb 90138033Sjhbstatic void 91138033Sjhbprt_attach_devices(ACPI_PCI_ROUTING_TABLE *entry, void *arg) 92138033Sjhb{ 93138033Sjhb ACPI_HANDLE handle; 94138033Sjhb device_t child, pcib; 95138033Sjhb int error; 96138033Sjhb 97138033Sjhb /* We only care about entries that reference a link device. */ 98138033Sjhb if (entry->Source == NULL || entry->Source[0] == '\0') 99138033Sjhb return; 100138033Sjhb 101152170Sjhb /* 102152170Sjhb * In practice, we only see SourceIndex's of 0 out in the wild. 103152170Sjhb * When indices != 0 have been found, they've been bugs in the ASL. 104152170Sjhb */ 105152170Sjhb if (entry->SourceIndex != 0) 106152170Sjhb return; 107152170Sjhb 108138033Sjhb /* Lookup the associated handle and device. */ 109138033Sjhb pcib = (device_t)arg; 110140447Sjhb if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, entry->Source, &handle))) 111138033Sjhb return; 112138033Sjhb child = acpi_get_device(handle); 113138033Sjhb if (child == NULL) 114138033Sjhb return; 115138033Sjhb 116138033Sjhb /* If the device hasn't been probed yet, force it to do so. */ 117138033Sjhb error = device_probe_and_attach(child); 118138033Sjhb if (error != 0) { 119140916Snjl device_printf(pcib, "failed to force attach of %s\n", 120138033Sjhb acpi_name(handle)); 121138033Sjhb return; 122138033Sjhb } 123138033Sjhb 124138033Sjhb /* Add a reference for a specific bus/device/pin tuple. */ 125138033Sjhb acpi_pci_link_add_reference(child, entry->SourceIndex, pcib, 126138033Sjhb ACPI_ADR_PCI_SLOT(entry->Address), entry->Pin); 127138033Sjhb} 128138033Sjhb 129102447Sjhbint 130102447Sjhbacpi_pcib_attach(device_t dev, ACPI_BUFFER *prt, int busno) 13167761Smsmith{ 132246041Sjkim ACPI_STATUS status; 133246042Sjkim int error; 13467761Smsmith 13596926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 13669744Smsmith 13767761Smsmith /* 138127314Snjl * Get the PCI interrupt routing table for this bus. If we can't 139137590Sjhb * get it, this is not an error but may reduce functionality. There 140137590Sjhb * are several valid bridges in the field that do not have a _PRT, so 141137590Sjhb * only warn about missing tables if bootverbose is set. 14279284Smsmith */ 143102447Sjhb prt->Length = ACPI_ALLOCATE_BUFFER; 144102447Sjhb status = AcpiGetIrqRoutingTable(acpi_get_handle(dev), prt); 145137590Sjhb if (ACPI_FAILURE(status) && (bootverbose || status != AE_NOT_FOUND)) 146104430Speter device_printf(dev, 147104430Speter "could not get PCI interrupt routing table for %s - %s\n", 148104430Speter acpi_name(acpi_get_handle(dev)), AcpiFormatException(status)); 14979284Smsmith 15079284Smsmith /* 15169458Smsmith * Attach the PCI bus proper. 15269458Smsmith */ 153185308Sganbold if (device_add_child(dev, "pci", busno) == NULL) { 154106158Sjhb device_printf(device_get_parent(dev), "couldn't attach pci bus\n"); 15569744Smsmith return_VALUE(ENXIO); 15667761Smsmith } 15767761Smsmith 15867761Smsmith /* 15969505Sscottl * Now go scan the bus. 16067761Smsmith */ 161138033Sjhb prt_walk_table(prt, prt_attach_devices, dev); 162127314Snjl 163246042Sjkim error = bus_generic_attach(dev); 164246042Sjkim return_VALUE(error); 16567761Smsmith} 16667761Smsmith 167138033Sjhbstatic void 168138033Sjhbprt_lookup_device(ACPI_PCI_ROUTING_TABLE *entry, void *arg) 169138033Sjhb{ 170138033Sjhb struct prt_lookup_request *pr; 171138033Sjhb 172138033Sjhb pr = (struct prt_lookup_request *)arg; 173138033Sjhb if (pr->pr_entry != NULL) 174138033Sjhb return; 175138033Sjhb 176138033Sjhb /* 177138033Sjhb * Compare the slot number (high word of Address) and pin number 178138033Sjhb * (note that ACPI uses 0 for INTA) to check for a match. 179138033Sjhb * 180138033Sjhb * Note that the low word of the Address field (function number) 181138033Sjhb * is required by the specification to be 0xffff. We don't risk 182138033Sjhb * checking it here. 183138033Sjhb */ 184138033Sjhb if (ACPI_ADR_PCI_SLOT(entry->Address) == pr->pr_slot && 185138033Sjhb entry->Pin == pr->pr_pin) 186138033Sjhb pr->pr_entry = entry; 187138033Sjhb} 188138033Sjhb 18979284Smsmith/* 19079284Smsmith * Route an interrupt for a child of the bridge. 19179284Smsmith */ 192102447Sjhbint 193138033Sjhbacpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin, 194138033Sjhb ACPI_BUFFER *prtbuf) 19567761Smsmith{ 196138033Sjhb ACPI_PCI_ROUTING_TABLE *prt; 197138033Sjhb struct prt_lookup_request pr; 198138033Sjhb ACPI_HANDLE lnkdev; 199138033Sjhb int interrupt; 20082372Smsmith 20196926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 202133500Snjl 203130196Sjhb interrupt = PCI_INVALID_IRQ; 20479284Smsmith 205127314Snjl /* ACPI numbers pins 0-3, not 1-4 like the BIOS. */ 20679284Smsmith pin--; 20779284Smsmith 208133621Snjl ACPI_SERIAL_BEGIN(pcib); 209133621Snjl 210138033Sjhb /* Search for a matching entry in the routing table. */ 211138033Sjhb pr.pr_entry = NULL; 212138033Sjhb pr.pr_pin = pin; 213138033Sjhb pr.pr_slot = pci_get_slot(dev); 214138033Sjhb prt_walk_table(prtbuf, prt_lookup_device, &pr); 215143301Sjhb if (pr.pr_entry == NULL) { 216153016Sjhb device_printf(pcib, "no PRT entry for %d.%d.INT%c\n", pci_get_bus(dev), 217143301Sjhb pci_get_slot(dev), 'A' + pin); 218143301Sjhb goto out; 219143301Sjhb } 220138033Sjhb prt = pr.pr_entry; 221143301Sjhb 222133585Snjl if (bootverbose) { 223133585Snjl device_printf(pcib, "matched entry for %d.%d.INT%c", 224133585Snjl pci_get_bus(dev), pci_get_slot(dev), 'A' + pin); 225138033Sjhb if (prt->Source != NULL && prt->Source[0] != '\0') 226138033Sjhb printf(" (src %s:%u)", prt->Source, prt->SourceIndex); 227133585Snjl printf("\n"); 228133585Snjl } 22979284Smsmith 23079284Smsmith /* 231133500Snjl * If source is empty/NULL, the source index is a global IRQ number 232133500Snjl * and it's hard-wired so we're done. 233152170Sjhb * 234152170Sjhb * XXX: If the source index is non-zero, ignore the source device and 235152170Sjhb * assume that this is a hard-wired entry. 23679284Smsmith */ 237152170Sjhb if (prt->Source == NULL || prt->Source[0] == '\0' || 238152170Sjhb prt->SourceIndex != 0) { 23984630Sdfr if (bootverbose) 240133500Snjl device_printf(pcib, "slot %d INT%c hardwired to IRQ %d\n", 241133500Snjl pci_get_slot(dev), 'A' + pin, prt->SourceIndex); 242153066Sjhb if (prt->SourceIndex) { 243133500Snjl interrupt = prt->SourceIndex; 244153066Sjhb BUS_CONFIG_INTR(dev, interrupt, INTR_TRIGGER_LEVEL, 245153066Sjhb INTR_POLARITY_LOW); 246153066Sjhb } else 247133500Snjl device_printf(pcib, "error: invalid hard-wired IRQ of 0\n"); 24879284Smsmith goto out; 24979284Smsmith } 25079284Smsmith 251138033Sjhb /* 252138033Sjhb * We have to find the source device (PCI interrupt link device). 25379284Smsmith */ 254138033Sjhb if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, prt->Source, &lnkdev))) { 255138033Sjhb device_printf(pcib, "couldn't find PCI interrupt link device %s\n", 256138033Sjhb prt->Source); 25779284Smsmith goto out; 25879284Smsmith } 259138033Sjhb interrupt = acpi_pci_link_route_interrupt(acpi_get_device(lnkdev), 260138033Sjhb prt->SourceIndex); 26179284Smsmith 262133500Snjl if (bootverbose && PCI_INTERRUPT_VALID(interrupt)) 263131398Sjhb device_printf(pcib, "slot %d INT%c routed to irq %d via %s\n", 264138033Sjhb pci_get_slot(dev), 'A' + pin, interrupt, acpi_name(lnkdev)); 26579284Smsmith 266127314Snjlout: 267133621Snjl ACPI_SERIAL_END(pcib); 26879284Smsmith 269246041Sjkim return_VALUE(interrupt); 27067761Smsmith} 271211430Sjhb 272211430Sjhbint 273211430Sjhbacpi_pcib_power_for_sleep(device_t pcib, device_t dev, int *pstate) 274211430Sjhb{ 275211430Sjhb device_t acpi_dev; 276211430Sjhb 277211430Sjhb acpi_dev = devclass_get_device(devclass_find("acpi"), 0); 278211430Sjhb acpi_device_pwr_for_sleep(acpi_dev, dev, pstate); 279211430Sjhb return (0); 280211430Sjhb} 281