xref: /freebsd/sys/dev/acpica/acpi_pcib.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
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