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>
2915e32d5dSMike Smith #include "opt_acpi.h"
3015e32d5dSMike Smith #include <sys/param.h>
3115e32d5dSMike Smith #include <sys/bus.h>
324fa387b6SMike Smith #include <sys/malloc.h>
334fa387b6SMike Smith #include <sys/kernel.h>
3415e32d5dSMike Smith
35129d3046SJung-uk Kim #include <contrib/dev/acpica/include/acpi.h>
36129d3046SJung-uk Kim #include <contrib/dev/acpica/include/accommon.h>
37129d3046SJung-uk Kim
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
prt_walk_table(ACPI_BUFFER * prt,prt_entry_handler * handler,void * arg)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
prt_attach_devices(ACPI_PCI_ROUTING_TABLE * entry,void * arg)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. */
96d19b0f3eSKonstantin Belousov if (entry->Source[0] == '\0')
975e1ba6d4SJohn Baldwin return;
985e1ba6d4SJohn Baldwin
99f25bdd3bSJohn Baldwin /*
100f25bdd3bSJohn Baldwin * In practice, we only see SourceIndex's of 0 out in the wild.
101f25bdd3bSJohn Baldwin * When indices != 0 have been found, they've been bugs in the ASL.
102f25bdd3bSJohn Baldwin */
103f25bdd3bSJohn Baldwin if (entry->SourceIndex != 0)
104f25bdd3bSJohn Baldwin return;
105f25bdd3bSJohn Baldwin
1065e1ba6d4SJohn Baldwin /* Lookup the associated handle and device. */
1075e1ba6d4SJohn Baldwin pcib = (device_t)arg;
1085e15a081SJohn Baldwin if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, entry->Source, &handle)))
1095e1ba6d4SJohn Baldwin return;
1105e1ba6d4SJohn Baldwin child = acpi_get_device(handle);
1115e1ba6d4SJohn Baldwin if (child == NULL)
1125e1ba6d4SJohn Baldwin return;
1135e1ba6d4SJohn Baldwin
1145e1ba6d4SJohn Baldwin /* If the device hasn't been probed yet, force it to do so. */
1155e1ba6d4SJohn Baldwin error = device_probe_and_attach(child);
1165e1ba6d4SJohn Baldwin if (error != 0) {
117286fceb5SNate Lawson device_printf(pcib, "failed to force attach of %s\n",
1185e1ba6d4SJohn Baldwin acpi_name(handle));
1195e1ba6d4SJohn Baldwin return;
1205e1ba6d4SJohn Baldwin }
1215e1ba6d4SJohn Baldwin
1225e1ba6d4SJohn Baldwin /* Add a reference for a specific bus/device/pin tuple. */
1235e1ba6d4SJohn Baldwin acpi_pci_link_add_reference(child, entry->SourceIndex, pcib,
1245e1ba6d4SJohn Baldwin ACPI_ADR_PCI_SLOT(entry->Address), entry->Pin);
1255e1ba6d4SJohn Baldwin }
1265e1ba6d4SJohn Baldwin
12767e7d085SJohn Baldwin void
acpi_pcib_fetch_prt(device_t dev,ACPI_BUFFER * prt)12867e7d085SJohn Baldwin acpi_pcib_fetch_prt(device_t dev, ACPI_BUFFER *prt)
12915e32d5dSMike Smith {
13015e32d5dSMike Smith ACPI_STATUS status;
1310ae55423SMike Smith
132b4a05238SPeter Wemm ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
13315e32d5dSMike Smith
13415e32d5dSMike Smith /*
1353304735dSNate Lawson * Get the PCI interrupt routing table for this bus. If we can't
13620447d54SJohn Baldwin * get it, this is not an error but may reduce functionality. There
13720447d54SJohn Baldwin * are several valid bridges in the field that do not have a _PRT, so
13820447d54SJohn Baldwin * only warn about missing tables if bootverbose is set.
1394fa387b6SMike Smith */
1402ccfc932SJohn Baldwin prt->Length = ACPI_ALLOCATE_BUFFER;
1412ccfc932SJohn Baldwin status = AcpiGetIrqRoutingTable(acpi_get_handle(dev), prt);
14220447d54SJohn Baldwin if (ACPI_FAILURE(status) && (bootverbose || status != AE_NOT_FOUND))
143f144391bSPeter Wemm device_printf(dev,
144f144391bSPeter Wemm "could not get PCI interrupt routing table for %s - %s\n",
145f144391bSPeter Wemm acpi_name(acpi_get_handle(dev)), AcpiFormatException(status));
1464fa387b6SMike Smith
1474fa387b6SMike Smith /*
14867e7d085SJohn Baldwin * Ensure all the link devices are attached.
14915e32d5dSMike Smith */
1505e1ba6d4SJohn Baldwin prt_walk_table(prt, prt_attach_devices, dev);
15115e32d5dSMike Smith }
15215e32d5dSMike Smith
1535e1ba6d4SJohn Baldwin static void
prt_lookup_device(ACPI_PCI_ROUTING_TABLE * entry,void * arg)1545e1ba6d4SJohn Baldwin prt_lookup_device(ACPI_PCI_ROUTING_TABLE *entry, void *arg)
1555e1ba6d4SJohn Baldwin {
1565e1ba6d4SJohn Baldwin struct prt_lookup_request *pr;
1575e1ba6d4SJohn Baldwin
1585e1ba6d4SJohn Baldwin pr = (struct prt_lookup_request *)arg;
1595e1ba6d4SJohn Baldwin if (pr->pr_entry != NULL)
1605e1ba6d4SJohn Baldwin return;
1615e1ba6d4SJohn Baldwin
1625e1ba6d4SJohn Baldwin /*
1635e1ba6d4SJohn Baldwin * Compare the slot number (high word of Address) and pin number
1645e1ba6d4SJohn Baldwin * (note that ACPI uses 0 for INTA) to check for a match.
1655e1ba6d4SJohn Baldwin *
1665e1ba6d4SJohn Baldwin * Note that the low word of the Address field (function number)
1675e1ba6d4SJohn Baldwin * is required by the specification to be 0xffff. We don't risk
1685e1ba6d4SJohn Baldwin * checking it here.
1695e1ba6d4SJohn Baldwin */
1705e1ba6d4SJohn Baldwin if (ACPI_ADR_PCI_SLOT(entry->Address) == pr->pr_slot &&
1715e1ba6d4SJohn Baldwin entry->Pin == pr->pr_pin)
1725e1ba6d4SJohn Baldwin pr->pr_entry = entry;
1735e1ba6d4SJohn Baldwin }
1745e1ba6d4SJohn Baldwin
1754fa387b6SMike Smith /*
1764fa387b6SMike Smith * Route an interrupt for a child of the bridge.
1774fa387b6SMike Smith */
1782ccfc932SJohn Baldwin int
acpi_pcib_route_interrupt(device_t pcib,device_t dev,int pin,ACPI_BUFFER * prtbuf)1795e1ba6d4SJohn Baldwin acpi_pcib_route_interrupt(device_t pcib, device_t dev, int pin,
1805e1ba6d4SJohn Baldwin ACPI_BUFFER *prtbuf)
18115e32d5dSMike Smith {
182c1b1f787SMike Smith ACPI_PCI_ROUTING_TABLE *prt;
1835e1ba6d4SJohn Baldwin struct prt_lookup_request pr;
1845e1ba6d4SJohn Baldwin ACPI_HANDLE lnkdev;
1855e1ba6d4SJohn Baldwin int interrupt;
1864fa387b6SMike Smith
187b4a05238SPeter Wemm ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
1884c1cdee6SMike Smith
189*d4d6ad3fSJayachandran C. lnkdev = NULL;
1904dc4ea26SJohn Baldwin interrupt = PCI_INVALID_IRQ;
1914fa387b6SMike Smith
1923304735dSNate Lawson /* ACPI numbers pins 0-3, not 1-4 like the BIOS. */
1934fa387b6SMike Smith pin--;
1944fa387b6SMike Smith
195bbf7c27aSNate Lawson ACPI_SERIAL_BEGIN(pcib);
196bbf7c27aSNate Lawson
1975e1ba6d4SJohn Baldwin /* Search for a matching entry in the routing table. */
1985e1ba6d4SJohn Baldwin pr.pr_entry = NULL;
1995e1ba6d4SJohn Baldwin pr.pr_pin = pin;
2005e1ba6d4SJohn Baldwin pr.pr_slot = pci_get_slot(dev);
2015e1ba6d4SJohn Baldwin prt_walk_table(prtbuf, prt_lookup_device, &pr);
20218e6466bSJohn Baldwin if (pr.pr_entry == NULL) {
20380f049d3SJohn Baldwin device_printf(pcib, "no PRT entry for %d.%d.INT%c\n", pci_get_bus(dev),
20418e6466bSJohn Baldwin pci_get_slot(dev), 'A' + pin);
20518e6466bSJohn Baldwin goto out;
20618e6466bSJohn Baldwin }
2075e1ba6d4SJohn Baldwin prt = pr.pr_entry;
2085e1ba6d4SJohn Baldwin
20912f57103SNate Lawson if (bootverbose) {
21012f57103SNate Lawson device_printf(pcib, "matched entry for %d.%d.INT%c",
21112f57103SNate Lawson pci_get_bus(dev), pci_get_slot(dev), 'A' + pin);
212d19b0f3eSKonstantin Belousov if (prt->Source[0] != '\0')
2135e1ba6d4SJohn Baldwin printf(" (src %s:%u)", prt->Source, prt->SourceIndex);
21412f57103SNate Lawson printf("\n");
21512f57103SNate Lawson }
2164fa387b6SMike Smith
2174fa387b6SMike Smith /*
218e4116e93SNate Lawson * If source is empty/NULL, the source index is a global IRQ number
219e4116e93SNate Lawson * and it's hard-wired so we're done.
220f25bdd3bSJohn Baldwin *
221f25bdd3bSJohn Baldwin * XXX: If the source index is non-zero, ignore the source device and
222f25bdd3bSJohn Baldwin * assume that this is a hard-wired entry.
2234fa387b6SMike Smith */
224d19b0f3eSKonstantin Belousov if (prt->Source[0] == '\0' || prt->SourceIndex != 0) {
225a067d210SDoug Rabson if (bootverbose)
226e4116e93SNate Lawson device_printf(pcib, "slot %d INT%c hardwired to IRQ %d\n",
227e4116e93SNate Lawson pci_get_slot(dev), 'A' + pin, prt->SourceIndex);
228d37d99c4SJohn Baldwin if (prt->SourceIndex) {
2294fa387b6SMike Smith interrupt = prt->SourceIndex;
230d37d99c4SJohn Baldwin BUS_CONFIG_INTR(dev, interrupt, INTR_TRIGGER_LEVEL,
231d37d99c4SJohn Baldwin INTR_POLARITY_LOW);
232d37d99c4SJohn Baldwin } else
233e4116e93SNate Lawson device_printf(pcib, "error: invalid hard-wired IRQ of 0\n");
2344fa387b6SMike Smith goto out;
2354fa387b6SMike Smith }
2364fa387b6SMike Smith
2375e1ba6d4SJohn Baldwin /*
2385e1ba6d4SJohn Baldwin * We have to find the source device (PCI interrupt link device).
2395e1ba6d4SJohn Baldwin */
2405e1ba6d4SJohn Baldwin if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, prt->Source, &lnkdev))) {
2415e1ba6d4SJohn Baldwin device_printf(pcib, "couldn't find PCI interrupt link device %s\n",
2425e1ba6d4SJohn Baldwin prt->Source);
2435e1ba6d4SJohn Baldwin goto out;
2445e1ba6d4SJohn Baldwin }
2455e1ba6d4SJohn Baldwin interrupt = acpi_pci_link_route_interrupt(acpi_get_device(lnkdev),
246e4116e93SNate Lawson prt->SourceIndex);
2473304735dSNate Lawson
248e4116e93SNate Lawson if (bootverbose && PCI_INTERRUPT_VALID(interrupt))
249c6a121abSJohn Baldwin device_printf(pcib, "slot %d INT%c routed to irq %d via %s\n",
2505e1ba6d4SJohn Baldwin pci_get_slot(dev), 'A' + pin, interrupt, acpi_name(lnkdev));
2514fa387b6SMike Smith
2524fa387b6SMike Smith out:
253bbf7c27aSNate Lawson ACPI_SERIAL_END(pcib);
254*d4d6ad3fSJayachandran C. #ifdef INTRNG
255*d4d6ad3fSJayachandran C. if (PCI_INTERRUPT_VALID(interrupt)) {
256*d4d6ad3fSJayachandran C. interrupt = acpi_map_intr(dev, interrupt, lnkdev);
257*d4d6ad3fSJayachandran C. KASSERT(PCI_INTERRUPT_VALID(interrupt), ("mapping fail"));
258*d4d6ad3fSJayachandran C. }
259*d4d6ad3fSJayachandran C. #endif
2604c1cdee6SMike Smith return_VALUE(interrupt);
2614fa387b6SMike Smith }
26262508c53SJohn Baldwin
26362508c53SJohn Baldwin int
acpi_pcib_power_for_sleep(device_t pcib,device_t dev,int * pstate)26462508c53SJohn Baldwin acpi_pcib_power_for_sleep(device_t pcib, device_t dev, int *pstate)
26562508c53SJohn Baldwin {
26662508c53SJohn Baldwin device_t acpi_dev;
26762508c53SJohn Baldwin
26862508c53SJohn Baldwin acpi_dev = devclass_get_device(devclass_find("acpi"), 0);
26962508c53SJohn Baldwin acpi_device_pwr_for_sleep(acpi_dev, dev, pstate);
27062508c53SJohn Baldwin return (0);
27162508c53SJohn Baldwin }
2728d791e5aSJohn Baldwin
2738d791e5aSJohn Baldwin int
acpi_pcib_get_cpus(device_t pcib,device_t dev,enum cpu_sets op,size_t setsize,cpuset_t * cpuset)2748d791e5aSJohn Baldwin acpi_pcib_get_cpus(device_t pcib, device_t dev, enum cpu_sets op,
2758d791e5aSJohn Baldwin size_t setsize, cpuset_t *cpuset)
2768d791e5aSJohn Baldwin {
2778d791e5aSJohn Baldwin
2788d791e5aSJohn Baldwin return (bus_get_cpus(pcib, op, setsize, cpuset));
2798d791e5aSJohn Baldwin }
280