xref: /dragonfly/sys/dev/acpica/acpi_pci_link.c (revision 5025fc65)
15db2f26eSSascha Wildner /*
25db2f26eSSascha Wildner  * Copyright (c) 2002 Mitsuru IWASAKI <iwasaki@jp.kfreebsd.org>
35db2f26eSSascha Wildner  * All rights reserved.
45db2f26eSSascha Wildner  *
55db2f26eSSascha Wildner  * Redistribution and use in source and binary forms, with or without
65db2f26eSSascha Wildner  * modification, are permitted provided that the following conditions
75db2f26eSSascha Wildner  * are met:
85db2f26eSSascha Wildner  * 1. Redistributions of source code must retain the above copyright
95db2f26eSSascha Wildner  *    notice, this list of conditions and the following disclaimer.
105db2f26eSSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
115db2f26eSSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
125db2f26eSSascha Wildner  *    documentation and/or other materials provided with the distribution.
135db2f26eSSascha Wildner  *
145db2f26eSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
155db2f26eSSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
165db2f26eSSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
175db2f26eSSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
185db2f26eSSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
195db2f26eSSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
205db2f26eSSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
215db2f26eSSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
225db2f26eSSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
235db2f26eSSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
245db2f26eSSascha Wildner  * SUCH DAMAGE.
255db2f26eSSascha Wildner  *
2606871c60SSascha Wildner  * $FreeBSD: src/sys/dev/acpica/acpi_pci_link.c,v 1.65 2013/04/23 00:40:24 svnexp Exp $
275db2f26eSSascha Wildner  */
285db2f26eSSascha Wildner 
295db2f26eSSascha Wildner #include "opt_acpi.h"
305db2f26eSSascha Wildner #include <sys/param.h>
315db2f26eSSascha Wildner #include <sys/bus.h>
325db2f26eSSascha Wildner #include <sys/kernel.h>
335db2f26eSSascha Wildner #include <sys/limits.h>
345db2f26eSSascha Wildner #include <sys/malloc.h>
355db2f26eSSascha Wildner #include <sys/module.h>
365db2f26eSSascha Wildner 
375db2f26eSSascha Wildner #include "acpi.h"
385db2f26eSSascha Wildner #include <dev/acpica/acpivar.h>
395db2f26eSSascha Wildner #include <dev/acpica/acpi_pcibvar.h>
405db2f26eSSascha Wildner #include <dev/acpica/acpi_sci_var.h>
415db2f26eSSascha Wildner 
427fdff911SSascha Wildner #include <bus/pci/pci_cfgreg.h>
435db2f26eSSascha Wildner #include <bus/pci/pcireg.h>
445db2f26eSSascha Wildner #include <bus/pci/pcivar.h>
455db2f26eSSascha Wildner #include "pcib_if.h"
465db2f26eSSascha Wildner 
475db2f26eSSascha Wildner /* Hooks for the ACPICA debugging infrastructure. */
485db2f26eSSascha Wildner #define _COMPONENT	ACPI_BUS
495db2f26eSSascha Wildner ACPI_MODULE_NAME("PCI_LINK")
505db2f26eSSascha Wildner 
515db2f26eSSascha Wildner ACPI_SERIAL_DECL(pci_link, "ACPI PCI link");
525db2f26eSSascha Wildner 
535db2f26eSSascha Wildner #define NUM_ISA_INTERRUPTS	16
545db2f26eSSascha Wildner #define NUM_ACPI_INTERRUPTS	256
555db2f26eSSascha Wildner 
565db2f26eSSascha Wildner /*
575db2f26eSSascha Wildner  * An ACPI PCI link device may contain multiple links.  Each link has its
585db2f26eSSascha Wildner  * own ACPI resource.  _PRT entries specify which link is being used via
595db2f26eSSascha Wildner  * the Source Index.
605db2f26eSSascha Wildner  *
615db2f26eSSascha Wildner  * XXX: A note about Source Indices and DPFs:  Currently we assume that
625db2f26eSSascha Wildner  * the DPF start and end tags are not counted towards the index that
635db2f26eSSascha Wildner  * Source Index corresponds to.  Also, we assume that when DPFs are in use
645db2f26eSSascha Wildner  * they various sets overlap in terms of Indices.  Here's an example
655db2f26eSSascha Wildner  * resource list indicating these assumptions:
665db2f26eSSascha Wildner  *
675db2f26eSSascha Wildner  * Resource		Index
685db2f26eSSascha Wildner  * --------		-----
695db2f26eSSascha Wildner  * I/O Port		0
705db2f26eSSascha Wildner  * Start DPF		-
715db2f26eSSascha Wildner  * IRQ			1
725db2f26eSSascha Wildner  * MemIO		2
735db2f26eSSascha Wildner  * Start DPF		-
745db2f26eSSascha Wildner  * IRQ			1
755db2f26eSSascha Wildner  * MemIO		2
765db2f26eSSascha Wildner  * End DPF		-
775db2f26eSSascha Wildner  * DMA Channel		3
785db2f26eSSascha Wildner  *
795db2f26eSSascha Wildner  * The XXX is because I'm not sure if this is a valid assumption to make.
805db2f26eSSascha Wildner  */
815db2f26eSSascha Wildner 
825db2f26eSSascha Wildner /* States during DPF processing. */
835db2f26eSSascha Wildner #define	DPF_OUTSIDE	0
845db2f26eSSascha Wildner #define	DPF_FIRST	1
855db2f26eSSascha Wildner #define	DPF_IGNORE	2
865db2f26eSSascha Wildner 
875db2f26eSSascha Wildner struct link;
885db2f26eSSascha Wildner 
895db2f26eSSascha Wildner struct acpi_pci_link_softc {
905db2f26eSSascha Wildner 	int	pl_num_links;
915db2f26eSSascha Wildner 	int	pl_crs_bad;
925db2f26eSSascha Wildner 	struct link *pl_links;
935db2f26eSSascha Wildner 	device_t pl_dev;
945db2f26eSSascha Wildner };
955db2f26eSSascha Wildner 
965db2f26eSSascha Wildner struct link {
975db2f26eSSascha Wildner 	struct acpi_pci_link_softc *l_sc;
985db2f26eSSascha Wildner 	uint8_t	l_bios_irq;
995db2f26eSSascha Wildner 	uint8_t	l_irq;
1005db2f26eSSascha Wildner 	uint8_t	l_initial_irq;
10106871c60SSascha Wildner 	UINT32	l_crs_type;
1025db2f26eSSascha Wildner 	int	l_res_index;
1035db2f26eSSascha Wildner 	int	l_num_irqs;
1045db2f26eSSascha Wildner 	int	*l_irqs;
1055db2f26eSSascha Wildner 	int	l_references;
1065db2f26eSSascha Wildner 	int	l_routed:1;
1075db2f26eSSascha Wildner 	int	l_isa_irq:1;
1085db2f26eSSascha Wildner 	ACPI_RESOURCE l_prs_template;
1095db2f26eSSascha Wildner };
1105db2f26eSSascha Wildner 
1115db2f26eSSascha Wildner struct link_count_request {
1125db2f26eSSascha Wildner 	int	in_dpf;
1135db2f26eSSascha Wildner 	int	count;
1145db2f26eSSascha Wildner };
1155db2f26eSSascha Wildner 
1165db2f26eSSascha Wildner struct link_res_request {
1175db2f26eSSascha Wildner 	struct acpi_pci_link_softc *sc;
1185db2f26eSSascha Wildner 	int	in_dpf;
1195db2f26eSSascha Wildner 	int	res_index;
1205db2f26eSSascha Wildner 	int	link_index;
1215db2f26eSSascha Wildner };
1225db2f26eSSascha Wildner 
12306871c60SSascha Wildner static MALLOC_DEFINE(M_PCI_LINK, "pci_link", "ACPI PCI Link structures");
1245db2f26eSSascha Wildner 
1255db2f26eSSascha Wildner static int pci_link_interrupt_weights[NUM_ACPI_INTERRUPTS];
1265db2f26eSSascha Wildner static int pci_link_bios_isa_irqs;
1275db2f26eSSascha Wildner 
1285db2f26eSSascha Wildner static char *pci_link_ids[] = { "PNP0C0F", NULL };
1295db2f26eSSascha Wildner 
1305db2f26eSSascha Wildner /*
1315db2f26eSSascha Wildner  * Fetch the short name associated with an ACPI handle and save it in the
1325db2f26eSSascha Wildner  * passed in buffer.
1335db2f26eSSascha Wildner  */
1345db2f26eSSascha Wildner static ACPI_STATUS
acpi_short_name(ACPI_HANDLE handle,char * buffer,size_t buflen)1355db2f26eSSascha Wildner acpi_short_name(ACPI_HANDLE handle, char *buffer, size_t buflen)
1365db2f26eSSascha Wildner {
1375db2f26eSSascha Wildner 	ACPI_BUFFER buf;
1385db2f26eSSascha Wildner 
1395db2f26eSSascha Wildner 	buf.Length = buflen;
1405db2f26eSSascha Wildner 	buf.Pointer = buffer;
1415db2f26eSSascha Wildner 	return (AcpiGetName(handle, ACPI_SINGLE_NAME, &buf));
1425db2f26eSSascha Wildner }
1435db2f26eSSascha Wildner 
1445db2f26eSSascha Wildner static int
acpi_pci_link_probe(device_t dev)1455db2f26eSSascha Wildner acpi_pci_link_probe(device_t dev)
1465db2f26eSSascha Wildner {
1475db2f26eSSascha Wildner 	char descr[28], name[12];
1485db2f26eSSascha Wildner 
1495db2f26eSSascha Wildner 	/*
1505db2f26eSSascha Wildner 	 * We explicitly do not check _STA since not all systems set it to
1515db2f26eSSascha Wildner 	 * sensible values.
1525db2f26eSSascha Wildner 	 */
1535db2f26eSSascha Wildner 	if (acpi_disabled("pci_link") ||
1545db2f26eSSascha Wildner 	    ACPI_ID_PROBE(device_get_parent(dev), dev, pci_link_ids) == NULL)
1555db2f26eSSascha Wildner 		return (ENXIO);
1565db2f26eSSascha Wildner 
1575db2f26eSSascha Wildner 	if (ACPI_SUCCESS(acpi_short_name(acpi_get_handle(dev), name,
1585db2f26eSSascha Wildner 	    sizeof(name)))) {
1595db2f26eSSascha Wildner 		ksnprintf(descr, sizeof(descr), "ACPI PCI Link %s", name);
1605db2f26eSSascha Wildner 		device_set_desc_copy(dev, descr);
1615db2f26eSSascha Wildner 	} else
1625db2f26eSSascha Wildner 		device_set_desc(dev, "ACPI PCI Link");
1635db2f26eSSascha Wildner 	device_quiet(dev);
1645db2f26eSSascha Wildner 	return (0);
1655db2f26eSSascha Wildner }
1665db2f26eSSascha Wildner 
1675db2f26eSSascha Wildner static ACPI_STATUS
acpi_count_irq_resources(ACPI_RESOURCE * res,void * context)1685db2f26eSSascha Wildner acpi_count_irq_resources(ACPI_RESOURCE *res, void *context)
1695db2f26eSSascha Wildner {
1705db2f26eSSascha Wildner 	struct link_count_request *req;
1715db2f26eSSascha Wildner 
1725db2f26eSSascha Wildner 	req = (struct link_count_request *)context;
1735db2f26eSSascha Wildner 	switch (res->Type) {
1745db2f26eSSascha Wildner 	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
1755db2f26eSSascha Wildner 		switch (req->in_dpf) {
1765db2f26eSSascha Wildner 		case DPF_OUTSIDE:
1775db2f26eSSascha Wildner 			/* We've started the first DPF. */
1785db2f26eSSascha Wildner 			req->in_dpf = DPF_FIRST;
1795db2f26eSSascha Wildner 			break;
1805db2f26eSSascha Wildner 		case DPF_FIRST:
1815db2f26eSSascha Wildner 			/* We've started the second DPF. */
1825db2f26eSSascha Wildner 			req->in_dpf = DPF_IGNORE;
1835db2f26eSSascha Wildner 			break;
1845db2f26eSSascha Wildner 		}
1855db2f26eSSascha Wildner 		break;
1865db2f26eSSascha Wildner 	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
1875db2f26eSSascha Wildner 		/* We are finished with DPF parsing. */
1885db2f26eSSascha Wildner 		KASSERT(req->in_dpf != DPF_OUTSIDE,
1895db2f26eSSascha Wildner 		    ("%s: end dpf when not parsing a dpf", __func__));
1905db2f26eSSascha Wildner 		req->in_dpf = DPF_OUTSIDE;
1915db2f26eSSascha Wildner 		break;
1925db2f26eSSascha Wildner 	case ACPI_RESOURCE_TYPE_IRQ:
1935db2f26eSSascha Wildner 	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
1945db2f26eSSascha Wildner 		/*
1955db2f26eSSascha Wildner 		 * Don't count resources if we are in a DPF set that we are
1965db2f26eSSascha Wildner 		 * ignoring.
1975db2f26eSSascha Wildner 		 */
1985db2f26eSSascha Wildner 		if (req->in_dpf != DPF_IGNORE)
1995db2f26eSSascha Wildner 			req->count++;
2005db2f26eSSascha Wildner 	}
2015db2f26eSSascha Wildner 	return (AE_OK);
2025db2f26eSSascha Wildner }
2035db2f26eSSascha Wildner 
2045db2f26eSSascha Wildner static ACPI_STATUS
link_add_crs(ACPI_RESOURCE * res,void * context)2055db2f26eSSascha Wildner link_add_crs(ACPI_RESOURCE *res, void *context)
2065db2f26eSSascha Wildner {
2075db2f26eSSascha Wildner 	struct link_res_request *req;
2085db2f26eSSascha Wildner 	struct link *link;
2095db2f26eSSascha Wildner 
2105db2f26eSSascha Wildner 	ACPI_SERIAL_ASSERT(pci_link);
2115db2f26eSSascha Wildner 	req = (struct link_res_request *)context;
2125db2f26eSSascha Wildner 	switch (res->Type) {
2135db2f26eSSascha Wildner 	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
2145db2f26eSSascha Wildner 		switch (req->in_dpf) {
2155db2f26eSSascha Wildner 		case DPF_OUTSIDE:
2165db2f26eSSascha Wildner 			/* We've started the first DPF. */
2175db2f26eSSascha Wildner 			req->in_dpf = DPF_FIRST;
2185db2f26eSSascha Wildner 			break;
2195db2f26eSSascha Wildner 		case DPF_FIRST:
2205db2f26eSSascha Wildner 			/* We've started the second DPF. */
2215db2f26eSSascha Wildner 			panic(
2225db2f26eSSascha Wildner 		"%s: Multiple dependent functions within a current resource",
2235db2f26eSSascha Wildner 			    __func__);
2245db2f26eSSascha Wildner 			break;
2255db2f26eSSascha Wildner 		}
2265db2f26eSSascha Wildner 		break;
2275db2f26eSSascha Wildner 	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
2285db2f26eSSascha Wildner 		/* We are finished with DPF parsing. */
2295db2f26eSSascha Wildner 		KASSERT(req->in_dpf != DPF_OUTSIDE,
2305db2f26eSSascha Wildner 		    ("%s: end dpf when not parsing a dpf", __func__));
2315db2f26eSSascha Wildner 		req->in_dpf = DPF_OUTSIDE;
2325db2f26eSSascha Wildner 		break;
2335db2f26eSSascha Wildner 	case ACPI_RESOURCE_TYPE_IRQ:
2345db2f26eSSascha Wildner 	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
2355db2f26eSSascha Wildner 		KASSERT(req->link_index < req->sc->pl_num_links,
2365db2f26eSSascha Wildner 		    ("%s: array boundary violation", __func__));
2375db2f26eSSascha Wildner 		link = &req->sc->pl_links[req->link_index];
2385db2f26eSSascha Wildner 		link->l_res_index = req->res_index;
23906871c60SSascha Wildner 		link->l_crs_type = res->Type;
2405db2f26eSSascha Wildner 		req->link_index++;
2415db2f26eSSascha Wildner 		req->res_index++;
2425db2f26eSSascha Wildner 
2435db2f26eSSascha Wildner 		/*
2445db2f26eSSascha Wildner 		 * Only use the current value if there's one IRQ.  Some
2455db2f26eSSascha Wildner 		 * systems return multiple IRQs (which is nonsense for _CRS)
2465db2f26eSSascha Wildner 		 * when the link hasn't been programmed.
2475db2f26eSSascha Wildner 		 */
2485db2f26eSSascha Wildner 		if (res->Type == ACPI_RESOURCE_TYPE_IRQ) {
2495db2f26eSSascha Wildner 			if (res->Data.Irq.InterruptCount == 1)
2505db2f26eSSascha Wildner 				link->l_irq = res->Data.Irq.Interrupts[0];
2515db2f26eSSascha Wildner 		} else if (res->Data.ExtendedIrq.InterruptCount == 1)
2525db2f26eSSascha Wildner 			link->l_irq = res->Data.ExtendedIrq.Interrupts[0];
2535db2f26eSSascha Wildner 
2545db2f26eSSascha Wildner 		/*
2555db2f26eSSascha Wildner 		 * An IRQ of zero means that the link isn't routed.
2565db2f26eSSascha Wildner 		 */
2575db2f26eSSascha Wildner 		if (link->l_irq == 0)
2585db2f26eSSascha Wildner 			link->l_irq = PCI_INVALID_IRQ;
2595db2f26eSSascha Wildner 		break;
2605db2f26eSSascha Wildner 	default:
2615db2f26eSSascha Wildner 		req->res_index++;
2625db2f26eSSascha Wildner 	}
2635db2f26eSSascha Wildner 	return (AE_OK);
2645db2f26eSSascha Wildner }
2655db2f26eSSascha Wildner 
2665db2f26eSSascha Wildner /*
2675db2f26eSSascha Wildner  * Populate the set of possible IRQs for each device.
2685db2f26eSSascha Wildner  */
2695db2f26eSSascha Wildner static ACPI_STATUS
link_add_prs(ACPI_RESOURCE * res,void * context)2705db2f26eSSascha Wildner link_add_prs(ACPI_RESOURCE *res, void *context)
2715db2f26eSSascha Wildner {
27206871c60SSascha Wildner 	ACPI_RESOURCE *tmp;
2735db2f26eSSascha Wildner 	struct link_res_request *req;
2745db2f26eSSascha Wildner 	struct link *link;
2755db2f26eSSascha Wildner 	UINT8 *irqs = NULL;
2765db2f26eSSascha Wildner 	UINT32 *ext_irqs = NULL;
2775db2f26eSSascha Wildner 	int i, is_ext_irq = 1;
2785db2f26eSSascha Wildner 
2795db2f26eSSascha Wildner 	ACPI_SERIAL_ASSERT(pci_link);
2805db2f26eSSascha Wildner 	req = (struct link_res_request *)context;
2815db2f26eSSascha Wildner 	switch (res->Type) {
2825db2f26eSSascha Wildner 	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
2835db2f26eSSascha Wildner 		switch (req->in_dpf) {
2845db2f26eSSascha Wildner 		case DPF_OUTSIDE:
2855db2f26eSSascha Wildner 			/* We've started the first DPF. */
2865db2f26eSSascha Wildner 			req->in_dpf = DPF_FIRST;
2875db2f26eSSascha Wildner 			break;
2885db2f26eSSascha Wildner 		case DPF_FIRST:
2895db2f26eSSascha Wildner 			/* We've started the second DPF. */
2905db2f26eSSascha Wildner 			req->in_dpf = DPF_IGNORE;
2915db2f26eSSascha Wildner 			break;
2925db2f26eSSascha Wildner 		}
2935db2f26eSSascha Wildner 		break;
2945db2f26eSSascha Wildner 	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
2955db2f26eSSascha Wildner 		/* We are finished with DPF parsing. */
2965db2f26eSSascha Wildner 		KASSERT(req->in_dpf != DPF_OUTSIDE,
2975db2f26eSSascha Wildner 		    ("%s: end dpf when not parsing a dpf", __func__));
2985db2f26eSSascha Wildner 		req->in_dpf = DPF_OUTSIDE;
2995db2f26eSSascha Wildner 		break;
3005db2f26eSSascha Wildner 	case ACPI_RESOURCE_TYPE_IRQ:
3015db2f26eSSascha Wildner 		is_ext_irq = 0;
3025db2f26eSSascha Wildner 		/* fall through */
3035db2f26eSSascha Wildner 	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
3045db2f26eSSascha Wildner 		/*
3055db2f26eSSascha Wildner 		 * Don't parse resources if we are in a DPF set that we are
3065db2f26eSSascha Wildner 		 * ignoring.
3075db2f26eSSascha Wildner 		 */
3085db2f26eSSascha Wildner 		if (req->in_dpf == DPF_IGNORE)
3095db2f26eSSascha Wildner 			break;
3105db2f26eSSascha Wildner 
3115db2f26eSSascha Wildner 		KASSERT(req->link_index < req->sc->pl_num_links,
3125db2f26eSSascha Wildner 		    ("%s: array boundary violation", __func__));
3135db2f26eSSascha Wildner 		link = &req->sc->pl_links[req->link_index];
3145db2f26eSSascha Wildner 		if (link->l_res_index == -1) {
3155db2f26eSSascha Wildner 			KASSERT(req->sc->pl_crs_bad,
3165db2f26eSSascha Wildner 			    ("res_index should be set"));
3175db2f26eSSascha Wildner 			link->l_res_index = req->res_index;
3185db2f26eSSascha Wildner 		}
3195db2f26eSSascha Wildner 		req->link_index++;
3205db2f26eSSascha Wildner 		req->res_index++;
3215db2f26eSSascha Wildner 
3225db2f26eSSascha Wildner 		/*
3235db2f26eSSascha Wildner 		 * Stash a copy of the resource for later use when doing
3245db2f26eSSascha Wildner 		 * _SRS.
3255db2f26eSSascha Wildner 		 */
32606871c60SSascha Wildner 		tmp = &link->l_prs_template;
3275db2f26eSSascha Wildner 		if (is_ext_irq) {
32806871c60SSascha Wildner 			bcopy(res, tmp, ACPI_RS_SIZE(tmp->Data.ExtendedIrq));
32906871c60SSascha Wildner 
33006871c60SSascha Wildner 			/*
33106871c60SSascha Wildner 			 * XXX acpi_AppendBufferResource() cannot handle
33206871c60SSascha Wildner 			 * optional data.
33306871c60SSascha Wildner 			 */
33406871c60SSascha Wildner 			bzero(&tmp->Data.ExtendedIrq.ResourceSource,
33506871c60SSascha Wildner 			    sizeof(tmp->Data.ExtendedIrq.ResourceSource));
33606871c60SSascha Wildner 			tmp->Length = ACPI_RS_SIZE(tmp->Data.ExtendedIrq);
33706871c60SSascha Wildner 
3385db2f26eSSascha Wildner 			link->l_num_irqs =
3395db2f26eSSascha Wildner 			    res->Data.ExtendedIrq.InterruptCount;
3405db2f26eSSascha Wildner 			ext_irqs = res->Data.ExtendedIrq.Interrupts;
3415db2f26eSSascha Wildner 		} else {
34206871c60SSascha Wildner 			bcopy(res, tmp, ACPI_RS_SIZE(tmp->Data.Irq));
3435db2f26eSSascha Wildner 			link->l_num_irqs = res->Data.Irq.InterruptCount;
3445db2f26eSSascha Wildner 			irqs = res->Data.Irq.Interrupts;
3455db2f26eSSascha Wildner 		}
3465db2f26eSSascha Wildner 		if (link->l_num_irqs == 0)
3475db2f26eSSascha Wildner 			break;
3485db2f26eSSascha Wildner 
3495db2f26eSSascha Wildner 		/*
3505db2f26eSSascha Wildner 		 * Save a list of the valid IRQs.  Also, if all of the
3515db2f26eSSascha Wildner 		 * valid IRQs are ISA IRQs, then mark this link as
3525db2f26eSSascha Wildner 		 * routed via an ISA interrupt.
3535db2f26eSSascha Wildner 		 */
3545db2f26eSSascha Wildner 		link->l_isa_irq = TRUE;
3555db2f26eSSascha Wildner 
3565db2f26eSSascha Wildner 		link->l_irqs = kmalloc(sizeof(int) * link->l_num_irqs,
3575db2f26eSSascha Wildner 		    M_PCI_LINK, M_WAITOK | M_ZERO);
3585db2f26eSSascha Wildner 		for (i = 0; i < link->l_num_irqs; i++) {
3595db2f26eSSascha Wildner 			if (is_ext_irq) {
3605db2f26eSSascha Wildner 				link->l_irqs[i] = ext_irqs[i];
3615db2f26eSSascha Wildner 				if (ext_irqs[i] >= NUM_ISA_INTERRUPTS)
3625db2f26eSSascha Wildner 					link->l_isa_irq = FALSE;
3635db2f26eSSascha Wildner 			} else {
3645db2f26eSSascha Wildner 				link->l_irqs[i] = irqs[i];
3655db2f26eSSascha Wildner 				if (irqs[i] >= NUM_ISA_INTERRUPTS)
3665db2f26eSSascha Wildner 					link->l_isa_irq = FALSE;
3675db2f26eSSascha Wildner 			}
3685db2f26eSSascha Wildner 		}
36906871c60SSascha Wildner 
37006871c60SSascha Wildner 		/*
37106871c60SSascha Wildner 		 * If this is not an ISA IRQ but _CRS used a non-extended
37206871c60SSascha Wildner 		 * IRQ descriptor, don't use _CRS as a template for _SRS.
37306871c60SSascha Wildner 		 */
37406871c60SSascha Wildner 		if (!req->sc->pl_crs_bad && !link->l_isa_irq &&
37506871c60SSascha Wildner 		    link->l_crs_type == ACPI_RESOURCE_TYPE_IRQ)
37606871c60SSascha Wildner 			req->sc->pl_crs_bad = TRUE;
3775db2f26eSSascha Wildner 		break;
3785db2f26eSSascha Wildner 	default:
3795db2f26eSSascha Wildner 		if (req->in_dpf == DPF_IGNORE)
3805db2f26eSSascha Wildner 			break;
3815db2f26eSSascha Wildner 		if (req->sc->pl_crs_bad)
3825db2f26eSSascha Wildner 			device_printf(req->sc->pl_dev,
3835db2f26eSSascha Wildner 		    "Warning: possible resource %d will be lost during _SRS\n",
3845db2f26eSSascha Wildner 			    req->res_index);
3855db2f26eSSascha Wildner 		req->res_index++;
3865db2f26eSSascha Wildner 	}
3875db2f26eSSascha Wildner 	return (AE_OK);
3885db2f26eSSascha Wildner }
3895db2f26eSSascha Wildner 
3905db2f26eSSascha Wildner static int
link_valid_irq(struct link * link,int irq)3915db2f26eSSascha Wildner link_valid_irq(struct link *link, int irq)
3925db2f26eSSascha Wildner {
3935db2f26eSSascha Wildner 	int i;
3945db2f26eSSascha Wildner 
3955db2f26eSSascha Wildner 	ACPI_SERIAL_ASSERT(pci_link);
3965db2f26eSSascha Wildner 
3975db2f26eSSascha Wildner 	/* Invalid interrupts are never valid. */
3985db2f26eSSascha Wildner 	if (!PCI_INTERRUPT_VALID(irq))
3995db2f26eSSascha Wildner 		return (FALSE);
4005db2f26eSSascha Wildner 
4015db2f26eSSascha Wildner 	/* Any interrupt in the list of possible interrupts is valid. */
4025db2f26eSSascha Wildner 	for (i = 0; i < link->l_num_irqs; i++)
4035db2f26eSSascha Wildner 		if (link->l_irqs[i] == irq)
4045db2f26eSSascha Wildner 			 return (TRUE);
4055db2f26eSSascha Wildner 
4065db2f26eSSascha Wildner 	/*
4075db2f26eSSascha Wildner 	 * For links routed via an ISA interrupt, if the SCI is routed via
4085db2f26eSSascha Wildner 	 * an ISA interrupt, the SCI is always treated as a valid IRQ.
4095db2f26eSSascha Wildner 	 */
4105db2f26eSSascha Wildner 	if (link->l_isa_irq && AcpiGbl_FADT.SciInterrupt == irq &&
4115db2f26eSSascha Wildner 	    irq < NUM_ISA_INTERRUPTS)
4125db2f26eSSascha Wildner 		return (TRUE);
4135db2f26eSSascha Wildner 
4145db2f26eSSascha Wildner 	/* If the interrupt wasn't found in the list it is not valid. */
4155db2f26eSSascha Wildner 	return (FALSE);
4165db2f26eSSascha Wildner }
4175db2f26eSSascha Wildner 
4185db2f26eSSascha Wildner static void
acpi_pci_link_dump(struct acpi_pci_link_softc * sc,int header,const char * tag)4195db2f26eSSascha Wildner acpi_pci_link_dump(struct acpi_pci_link_softc *sc, int header, const char *tag)
4205db2f26eSSascha Wildner {
4215db2f26eSSascha Wildner 	struct link *link;
4225db2f26eSSascha Wildner 	char buf[16];
4235db2f26eSSascha Wildner 	int i, j;
4245db2f26eSSascha Wildner 
4255db2f26eSSascha Wildner 	ACPI_SERIAL_ASSERT(pci_link);
4265db2f26eSSascha Wildner 	if (header) {
4275db2f26eSSascha Wildner 		ksnprintf(buf, sizeof(buf), "%s:",
4285db2f26eSSascha Wildner 		    device_get_nameunit(sc->pl_dev));
4295db2f26eSSascha Wildner 		kprintf("%-16.16s  Index  IRQ  Rtd  Ref  IRQs\n", buf);
4305db2f26eSSascha Wildner 	}
4315db2f26eSSascha Wildner 	for (i = 0; i < sc->pl_num_links; i++) {
4325db2f26eSSascha Wildner 		link = &sc->pl_links[i];
4335db2f26eSSascha Wildner 		kprintf("  %-14.14s  %5d  %3d   %c   %3d ", i == 0 ? tag : "", i,
4345db2f26eSSascha Wildner 		    link->l_irq, link->l_routed ? 'Y' : 'N',
4355db2f26eSSascha Wildner 		    link->l_references);
4365db2f26eSSascha Wildner 		if (link->l_num_irqs == 0)
4375db2f26eSSascha Wildner 			kprintf(" none");
4385db2f26eSSascha Wildner 		else for (j = 0; j < link->l_num_irqs; j++)
4395db2f26eSSascha Wildner 			kprintf(" %d", link->l_irqs[j]);
4405db2f26eSSascha Wildner 		kprintf("\n");
4415db2f26eSSascha Wildner 	}
4425db2f26eSSascha Wildner }
4435db2f26eSSascha Wildner 
4445db2f26eSSascha Wildner static int
acpi_pci_link_attach(device_t dev)4455db2f26eSSascha Wildner acpi_pci_link_attach(device_t dev)
4465db2f26eSSascha Wildner {
4475db2f26eSSascha Wildner 	struct acpi_pci_link_softc *sc;
4485db2f26eSSascha Wildner 	struct link_count_request creq;
4495db2f26eSSascha Wildner 	struct link_res_request rreq;
4505db2f26eSSascha Wildner 	ACPI_STATUS status;
4515db2f26eSSascha Wildner 	int i;
4525db2f26eSSascha Wildner 
4535db2f26eSSascha Wildner 	sc = device_get_softc(dev);
4545db2f26eSSascha Wildner 	sc->pl_dev = dev;
4555db2f26eSSascha Wildner 	ACPI_SERIAL_INIT(pci_link);
4565db2f26eSSascha Wildner 	ACPI_SERIAL_BEGIN(pci_link);
4575db2f26eSSascha Wildner 
4585db2f26eSSascha Wildner 	/*
4595db2f26eSSascha Wildner 	 * Count the number of current resources so we know how big of
4605db2f26eSSascha Wildner 	 * a link array to allocate.  On some systems, _CRS is broken,
4615db2f26eSSascha Wildner 	 * so for those systems try to derive the count from _PRS instead.
4625db2f26eSSascha Wildner 	 */
4635db2f26eSSascha Wildner 	creq.in_dpf = DPF_OUTSIDE;
4645db2f26eSSascha Wildner 	creq.count = 0;
4655db2f26eSSascha Wildner 	status = AcpiWalkResources(acpi_get_handle(dev), "_CRS",
4665db2f26eSSascha Wildner 	    acpi_count_irq_resources, &creq);
4675db2f26eSSascha Wildner 	sc->pl_crs_bad = ACPI_FAILURE(status);
4685db2f26eSSascha Wildner 	if (sc->pl_crs_bad) {
4695db2f26eSSascha Wildner 		creq.in_dpf = DPF_OUTSIDE;
4705db2f26eSSascha Wildner 		creq.count = 0;
4715db2f26eSSascha Wildner 		status = AcpiWalkResources(acpi_get_handle(dev), "_PRS",
4725db2f26eSSascha Wildner 		    acpi_count_irq_resources, &creq);
4735db2f26eSSascha Wildner 		if (ACPI_FAILURE(status)) {
4745db2f26eSSascha Wildner 			device_printf(dev,
4755db2f26eSSascha Wildner 			    "Unable to parse _CRS or _PRS: %s\n",
4765db2f26eSSascha Wildner 			    AcpiFormatException(status));
4775db2f26eSSascha Wildner 			ACPI_SERIAL_END(pci_link);
4785db2f26eSSascha Wildner 			return (ENXIO);
4795db2f26eSSascha Wildner 		}
4805db2f26eSSascha Wildner 	}
4815db2f26eSSascha Wildner 	sc->pl_num_links = creq.count;
4825db2f26eSSascha Wildner 	if (creq.count == 0) {
4835db2f26eSSascha Wildner 		ACPI_SERIAL_END(pci_link);
4845db2f26eSSascha Wildner 		return (0);
4855db2f26eSSascha Wildner 	}
4865db2f26eSSascha Wildner 	sc->pl_links = kmalloc(sizeof(struct link) * sc->pl_num_links,
4875db2f26eSSascha Wildner 	    M_PCI_LINK, M_WAITOK | M_ZERO);
4885db2f26eSSascha Wildner 
4895db2f26eSSascha Wildner 	/* Initialize the child links. */
4905db2f26eSSascha Wildner 	for (i = 0; i < sc->pl_num_links; i++) {
4915db2f26eSSascha Wildner 		sc->pl_links[i].l_irq = PCI_INVALID_IRQ;
4925db2f26eSSascha Wildner 		sc->pl_links[i].l_bios_irq = PCI_INVALID_IRQ;
4935db2f26eSSascha Wildner 		sc->pl_links[i].l_sc = sc;
4945db2f26eSSascha Wildner 		sc->pl_links[i].l_isa_irq = FALSE;
4955db2f26eSSascha Wildner 		sc->pl_links[i].l_res_index = -1;
4965db2f26eSSascha Wildner 	}
4975db2f26eSSascha Wildner 
4985db2f26eSSascha Wildner 	/* Try to read the current settings from _CRS if it is valid. */
4995db2f26eSSascha Wildner 	if (!sc->pl_crs_bad) {
5005db2f26eSSascha Wildner 		rreq.in_dpf = DPF_OUTSIDE;
5015db2f26eSSascha Wildner 		rreq.link_index = 0;
5025db2f26eSSascha Wildner 		rreq.res_index = 0;
5035db2f26eSSascha Wildner 		rreq.sc = sc;
5045db2f26eSSascha Wildner 		status = AcpiWalkResources(acpi_get_handle(dev), "_CRS",
5055db2f26eSSascha Wildner 		    link_add_crs, &rreq);
5065db2f26eSSascha Wildner 		if (ACPI_FAILURE(status)) {
5075db2f26eSSascha Wildner 			device_printf(dev, "Unable to parse _CRS: %s\n",
5085db2f26eSSascha Wildner 			    AcpiFormatException(status));
5095db2f26eSSascha Wildner 			goto fail;
5105db2f26eSSascha Wildner 		}
5115db2f26eSSascha Wildner 	}
5125db2f26eSSascha Wildner 
5135db2f26eSSascha Wildner 	/*
5145db2f26eSSascha Wildner 	 * Try to read the possible settings from _PRS.  Note that if the
5155db2f26eSSascha Wildner 	 * _CRS is toast, we depend on having a working _PRS.  However, if
5165db2f26eSSascha Wildner 	 * _CRS works, then it is ok for _PRS to be missing.
5175db2f26eSSascha Wildner 	 */
5185db2f26eSSascha Wildner 	rreq.in_dpf = DPF_OUTSIDE;
5195db2f26eSSascha Wildner 	rreq.link_index = 0;
5205db2f26eSSascha Wildner 	rreq.res_index = 0;
5215db2f26eSSascha Wildner 	rreq.sc = sc;
5225db2f26eSSascha Wildner 	status = AcpiWalkResources(acpi_get_handle(dev), "_PRS",
5235db2f26eSSascha Wildner 	    link_add_prs, &rreq);
5245db2f26eSSascha Wildner 	if (ACPI_FAILURE(status) &&
5255db2f26eSSascha Wildner 	    (status != AE_NOT_FOUND || sc->pl_crs_bad)) {
5265db2f26eSSascha Wildner 		device_printf(dev, "Unable to parse _PRS: %s\n",
5275db2f26eSSascha Wildner 		    AcpiFormatException(status));
5285db2f26eSSascha Wildner 		goto fail;
5295db2f26eSSascha Wildner 	}
5305db2f26eSSascha Wildner 	if (bootverbose)
5315db2f26eSSascha Wildner 		acpi_pci_link_dump(sc, 1, "Initial Probe");
5325db2f26eSSascha Wildner 
5335db2f26eSSascha Wildner 	/* Verify initial IRQs if we have _PRS. */
5345db2f26eSSascha Wildner 	if (status != AE_NOT_FOUND)
5355db2f26eSSascha Wildner 		for (i = 0; i < sc->pl_num_links; i++)
5365db2f26eSSascha Wildner 			if (!link_valid_irq(&sc->pl_links[i],
5375db2f26eSSascha Wildner 			    sc->pl_links[i].l_irq))
5385db2f26eSSascha Wildner 				sc->pl_links[i].l_irq = PCI_INVALID_IRQ;
5395db2f26eSSascha Wildner 	if (bootverbose)
5405db2f26eSSascha Wildner 		acpi_pci_link_dump(sc, 0, "Validation");
5415db2f26eSSascha Wildner 
5425db2f26eSSascha Wildner 	/* Save initial IRQs. */
5435db2f26eSSascha Wildner 	for (i = 0; i < sc->pl_num_links; i++)
5445db2f26eSSascha Wildner 		sc->pl_links[i].l_initial_irq = sc->pl_links[i].l_irq;
5455db2f26eSSascha Wildner 
5465db2f26eSSascha Wildner 	/*
5475db2f26eSSascha Wildner 	 * Try to disable this link.  If successful, set the current IRQ to
5485db2f26eSSascha Wildner 	 * zero and flags to indicate this link is not routed.  If we can't
5495db2f26eSSascha Wildner 	 * run _DIS (i.e., the method doesn't exist), assume the initial
5505db2f26eSSascha Wildner 	 * IRQ was routed by the BIOS.
5515db2f26eSSascha Wildner 	 */
5525db2f26eSSascha Wildner 	if (ACPI_SUCCESS(AcpiEvaluateObject(acpi_get_handle(dev), "_DIS", NULL,
5535db2f26eSSascha Wildner 	    NULL)))
5545db2f26eSSascha Wildner 		for (i = 0; i < sc->pl_num_links; i++)
5555db2f26eSSascha Wildner 			sc->pl_links[i].l_irq = PCI_INVALID_IRQ;
5565db2f26eSSascha Wildner 	else
5575db2f26eSSascha Wildner 		for (i = 0; i < sc->pl_num_links; i++)
5585db2f26eSSascha Wildner 			if (PCI_INTERRUPT_VALID(sc->pl_links[i].l_irq))
5595db2f26eSSascha Wildner 				sc->pl_links[i].l_routed = TRUE;
5605db2f26eSSascha Wildner 	if (bootverbose)
5615db2f26eSSascha Wildner 		acpi_pci_link_dump(sc, 0, "After Disable");
5625db2f26eSSascha Wildner 	ACPI_SERIAL_END(pci_link);
5635db2f26eSSascha Wildner 	return (0);
5645db2f26eSSascha Wildner fail:
5655db2f26eSSascha Wildner 	ACPI_SERIAL_END(pci_link);
5665db2f26eSSascha Wildner 	for (i = 0; i < sc->pl_num_links; i++)
5675db2f26eSSascha Wildner 		if (sc->pl_links[i].l_irqs != NULL)
5685db2f26eSSascha Wildner 			kfree(sc->pl_links[i].l_irqs, M_PCI_LINK);
5695db2f26eSSascha Wildner 	kfree(sc->pl_links, M_PCI_LINK);
5705db2f26eSSascha Wildner 	return (ENXIO);
5715db2f26eSSascha Wildner }
5725db2f26eSSascha Wildner 
5735db2f26eSSascha Wildner /* XXX: Note that this is identical to pci_pir_search_irq(). */
5745db2f26eSSascha Wildner static uint8_t
acpi_pci_link_search_irq(int bus,int device,int pin)5755db2f26eSSascha Wildner acpi_pci_link_search_irq(int bus, int device, int pin)
5765db2f26eSSascha Wildner {
5775db2f26eSSascha Wildner 	uint32_t value;
5785db2f26eSSascha Wildner 	uint8_t func, maxfunc;
5795db2f26eSSascha Wildner 
5805db2f26eSSascha Wildner 	/* See if we have a valid device at function 0. */
5815db2f26eSSascha Wildner 	value = pci_cfgregread(bus, device, 0, PCIR_HDRTYPE, 1);
5825db2f26eSSascha Wildner 	if ((value & PCIM_HDRTYPE) > PCI_MAXHDRTYPE)
5835db2f26eSSascha Wildner 		return (PCI_INVALID_IRQ);
5845db2f26eSSascha Wildner 	if (value & PCIM_MFDEV)
5855db2f26eSSascha Wildner 		maxfunc = PCI_FUNCMAX;
5865db2f26eSSascha Wildner 	else
5875db2f26eSSascha Wildner 		maxfunc = 0;
5885db2f26eSSascha Wildner 
5895db2f26eSSascha Wildner 	/* Scan all possible functions at this device. */
5905db2f26eSSascha Wildner 	for (func = 0; func <= maxfunc; func++) {
5915db2f26eSSascha Wildner 		value = pci_cfgregread(bus, device, func, PCIR_DEVVENDOR, 4);
5925db2f26eSSascha Wildner 		if (value == 0xffffffff)
5935db2f26eSSascha Wildner 			continue;
5945db2f26eSSascha Wildner 		value = pci_cfgregread(bus, device, func, PCIR_INTPIN, 1);
5955db2f26eSSascha Wildner 
5965db2f26eSSascha Wildner 		/*
5975db2f26eSSascha Wildner 		 * See if it uses the pin in question.  Note that the passed
5985db2f26eSSascha Wildner 		 * in pin uses 0 for A, .. 3 for D whereas the intpin
5995db2f26eSSascha Wildner 		 * register uses 0 for no interrupt, 1 for A, .. 4 for D.
6005db2f26eSSascha Wildner 		 */
6015db2f26eSSascha Wildner 		if (value != pin + 1)
6025db2f26eSSascha Wildner 			continue;
6035db2f26eSSascha Wildner 		value = pci_cfgregread(bus, device, func, PCIR_INTLINE, 1);
6045db2f26eSSascha Wildner 		if (bootverbose)
6055db2f26eSSascha Wildner 			kprintf(
6065db2f26eSSascha Wildner 		"ACPI: Found matching pin for %d.%d.INT%c at func %d: %d\n",
6075db2f26eSSascha Wildner 			    bus, device, pin + 'A', func, value);
6085db2f26eSSascha Wildner 		if (value != PCI_INVALID_IRQ)
6095db2f26eSSascha Wildner 			return (value);
6105db2f26eSSascha Wildner 	}
6115db2f26eSSascha Wildner 	return (PCI_INVALID_IRQ);
6125db2f26eSSascha Wildner }
6135db2f26eSSascha Wildner 
6145db2f26eSSascha Wildner /*
6155db2f26eSSascha Wildner  * Find the link structure that corresponds to the resource index passed in
6165db2f26eSSascha Wildner  * via 'source_index'.
6175db2f26eSSascha Wildner  */
6185db2f26eSSascha Wildner static struct link *
acpi_pci_link_lookup(device_t dev,int source_index)6195db2f26eSSascha Wildner acpi_pci_link_lookup(device_t dev, int source_index)
6205db2f26eSSascha Wildner {
6215db2f26eSSascha Wildner 	struct acpi_pci_link_softc *sc;
6225db2f26eSSascha Wildner 	int i;
6235db2f26eSSascha Wildner 
6245db2f26eSSascha Wildner 	ACPI_SERIAL_ASSERT(pci_link);
6255db2f26eSSascha Wildner 	sc = device_get_softc(dev);
6265db2f26eSSascha Wildner 	for (i = 0; i < sc->pl_num_links; i++)
6275db2f26eSSascha Wildner 		if (sc->pl_links[i].l_res_index == source_index)
6285db2f26eSSascha Wildner 			return (&sc->pl_links[i]);
6295db2f26eSSascha Wildner 	return (NULL);
6305db2f26eSSascha Wildner }
6315db2f26eSSascha Wildner 
6325db2f26eSSascha Wildner void
acpi_pci_link_add_reference(device_t dev,int index,device_t pcib,int slot,int pin)6335db2f26eSSascha Wildner acpi_pci_link_add_reference(device_t dev, int index, device_t pcib, int slot,
6345db2f26eSSascha Wildner     int pin)
6355db2f26eSSascha Wildner {
6365db2f26eSSascha Wildner 	struct link *link;
6375db2f26eSSascha Wildner 	uint8_t bios_irq;
6385db2f26eSSascha Wildner 	uintptr_t bus;
6395db2f26eSSascha Wildner 
6405db2f26eSSascha Wildner 	/*
6415db2f26eSSascha Wildner 	 * Look up the PCI bus for the specified PCI bridge device.  Note
6425db2f26eSSascha Wildner 	 * that the PCI bridge device might not have any children yet.
6435db2f26eSSascha Wildner 	 * However, looking up its bus number doesn't require a valid child
6445db2f26eSSascha Wildner 	 * device, so we just pass NULL.
6455db2f26eSSascha Wildner 	 */
6465db2f26eSSascha Wildner 	if (BUS_READ_IVAR(pcib, NULL, PCIB_IVAR_BUS, &bus) != 0) {
6475db2f26eSSascha Wildner 		device_printf(pcib, "Unable to read PCI bus number");
6485db2f26eSSascha Wildner 		panic("PCI bridge without a bus number");
6495db2f26eSSascha Wildner 	}
6505db2f26eSSascha Wildner 
6515db2f26eSSascha Wildner 	/* Bump the reference count. */
6525db2f26eSSascha Wildner 	ACPI_SERIAL_BEGIN(pci_link);
6535db2f26eSSascha Wildner 	link = acpi_pci_link_lookup(dev, index);
6545db2f26eSSascha Wildner 	if (link == NULL) {
6555db2f26eSSascha Wildner 		device_printf(dev, "apparently invalid index %d\n", index);
6565db2f26eSSascha Wildner 		ACPI_SERIAL_END(pci_link);
6575db2f26eSSascha Wildner 		return;
6585db2f26eSSascha Wildner 	}
6595db2f26eSSascha Wildner 	link->l_references++;
6605db2f26eSSascha Wildner 	if (link->l_routed)
6615db2f26eSSascha Wildner 		pci_link_interrupt_weights[link->l_irq]++;
6625db2f26eSSascha Wildner 
6635db2f26eSSascha Wildner 	/*
6645db2f26eSSascha Wildner 	 * The BIOS only routes interrupts via ISA IRQs using the ATPICs
6655db2f26eSSascha Wildner 	 * (8259As).  Thus, if this link is routed via an ISA IRQ, go
6665db2f26eSSascha Wildner 	 * look to see if the BIOS routed an IRQ for this link at the
6675db2f26eSSascha Wildner 	 * indicated (bus, slot, pin).  If so, we prefer that IRQ for
6685db2f26eSSascha Wildner 	 * this link and add that IRQ to our list of known-good IRQs.
6695db2f26eSSascha Wildner 	 * This provides a good work-around for link devices whose _CRS
6705db2f26eSSascha Wildner 	 * method is either broken or bogus.  We only use the value
6715db2f26eSSascha Wildner 	 * returned by _CRS if we can't find a valid IRQ via this method
6725db2f26eSSascha Wildner 	 * in fact.
6735db2f26eSSascha Wildner 	 *
6745db2f26eSSascha Wildner 	 * If this link is not routed via an ISA IRQ (because we are using
6755db2f26eSSascha Wildner 	 * APIC for example), then don't bother looking up the BIOS IRQ
6765db2f26eSSascha Wildner 	 * as if we find one it won't be valid anyway.
6775db2f26eSSascha Wildner 	 */
6785db2f26eSSascha Wildner 	if (!link->l_isa_irq) {
6795db2f26eSSascha Wildner 		ACPI_SERIAL_END(pci_link);
6805db2f26eSSascha Wildner 		return;
6815db2f26eSSascha Wildner 	}
6825db2f26eSSascha Wildner 
6835db2f26eSSascha Wildner 	/* Try to find a BIOS IRQ setting from any matching devices. */
6845db2f26eSSascha Wildner 	bios_irq = acpi_pci_link_search_irq(bus, slot, pin);
6855db2f26eSSascha Wildner 	if (!PCI_INTERRUPT_VALID(bios_irq)) {
6865db2f26eSSascha Wildner 		ACPI_SERIAL_END(pci_link);
6875db2f26eSSascha Wildner 		return;
6885db2f26eSSascha Wildner 	}
6895db2f26eSSascha Wildner 
6905db2f26eSSascha Wildner 	/* Validate the BIOS IRQ. */
6915db2f26eSSascha Wildner 	if (!link_valid_irq(link, bios_irq)) {
6925db2f26eSSascha Wildner 		device_printf(dev, "BIOS IRQ %u for %d.%d.INT%c is invalid\n",
6935db2f26eSSascha Wildner 		    bios_irq, (int)bus, slot, pin + 'A');
6945db2f26eSSascha Wildner 	} else if (!PCI_INTERRUPT_VALID(link->l_bios_irq)) {
6955db2f26eSSascha Wildner 		link->l_bios_irq = bios_irq;
6965db2f26eSSascha Wildner 		/*
6975db2f26eSSascha Wildner 		 * SCI setting is handled by acpi_pci_link_identify()
6985db2f26eSSascha Wildner 		 */
6995db2f26eSSascha Wildner 		if (bios_irq < NUM_ISA_INTERRUPTS &&
7005db2f26eSSascha Wildner 		    AcpiGbl_FADT.SciInterrupt != bios_irq)
7015db2f26eSSascha Wildner 			pci_link_bios_isa_irqs |= (1 << bios_irq);
7025db2f26eSSascha Wildner 		if (bios_irq != link->l_initial_irq &&
7035db2f26eSSascha Wildner 		    PCI_INTERRUPT_VALID(link->l_initial_irq))
7045db2f26eSSascha Wildner 			device_printf(dev,
7055db2f26eSSascha Wildner 			    "BIOS IRQ %u does not match initial IRQ %u\n",
7065db2f26eSSascha Wildner 			    bios_irq, link->l_initial_irq);
7075db2f26eSSascha Wildner 	} else if (bios_irq != link->l_bios_irq)
7085db2f26eSSascha Wildner 		device_printf(dev,
7095db2f26eSSascha Wildner 	    "BIOS IRQ %u for %d.%d.INT%c does not match previous BIOS IRQ %u\n",
7105db2f26eSSascha Wildner 		    bios_irq, (int)bus, slot, pin + 'A',
7115db2f26eSSascha Wildner 		    link->l_bios_irq);
7125db2f26eSSascha Wildner 	ACPI_SERIAL_END(pci_link);
7135db2f26eSSascha Wildner }
7145db2f26eSSascha Wildner 
7155db2f26eSSascha Wildner static ACPI_STATUS
acpi_pci_link_srs_from_crs(struct acpi_pci_link_softc * sc,ACPI_BUFFER * srsbuf)7165db2f26eSSascha Wildner acpi_pci_link_srs_from_crs(struct acpi_pci_link_softc *sc, ACPI_BUFFER *srsbuf)
7175db2f26eSSascha Wildner {
71806871c60SSascha Wildner 	ACPI_RESOURCE *end, *res;
7195db2f26eSSascha Wildner 	ACPI_STATUS status;
7205db2f26eSSascha Wildner 	struct link *link;
7215db2f26eSSascha Wildner 	int i, in_dpf;
7225db2f26eSSascha Wildner 
7235db2f26eSSascha Wildner 	/* Fetch the _CRS. */
7245db2f26eSSascha Wildner 	ACPI_SERIAL_ASSERT(pci_link);
72506871c60SSascha Wildner 	srsbuf->Pointer = NULL;
72606871c60SSascha Wildner 	srsbuf->Length = ACPI_ALLOCATE_BUFFER;
72706871c60SSascha Wildner 	status = AcpiGetCurrentResources(acpi_get_handle(sc->pl_dev), srsbuf);
72806871c60SSascha Wildner 	if (ACPI_SUCCESS(status) && srsbuf->Pointer == NULL)
7295db2f26eSSascha Wildner 		status = AE_NO_MEMORY;
7305db2f26eSSascha Wildner 	if (ACPI_FAILURE(status)) {
7315db2f26eSSascha Wildner 		if (bootverbose)
7325db2f26eSSascha Wildner 			device_printf(sc->pl_dev,
7335db2f26eSSascha Wildner 			    "Unable to fetch current resources: %s\n",
7345db2f26eSSascha Wildner 			    AcpiFormatException(status));
7355db2f26eSSascha Wildner 		return (status);
7365db2f26eSSascha Wildner 	}
7375db2f26eSSascha Wildner 
7385db2f26eSSascha Wildner 	/* Fill in IRQ resources via link structures. */
7395db2f26eSSascha Wildner 	link = sc->pl_links;
7405db2f26eSSascha Wildner 	i = 0;
7415db2f26eSSascha Wildner 	in_dpf = DPF_OUTSIDE;
74206871c60SSascha Wildner 	res = (ACPI_RESOURCE *)srsbuf->Pointer;
74306871c60SSascha Wildner 	end = (ACPI_RESOURCE *)((char *)srsbuf->Pointer + srsbuf->Length);
7445db2f26eSSascha Wildner 	for (;;) {
74506871c60SSascha Wildner 		switch (res->Type) {
7465db2f26eSSascha Wildner 		case ACPI_RESOURCE_TYPE_START_DEPENDENT:
7475db2f26eSSascha Wildner 			switch (in_dpf) {
7485db2f26eSSascha Wildner 			case DPF_OUTSIDE:
7495db2f26eSSascha Wildner 				/* We've started the first DPF. */
7505db2f26eSSascha Wildner 				in_dpf = DPF_FIRST;
7515db2f26eSSascha Wildner 				break;
7525db2f26eSSascha Wildner 			case DPF_FIRST:
7535db2f26eSSascha Wildner 				/* We've started the second DPF. */
7545db2f26eSSascha Wildner 				panic(
7555db2f26eSSascha Wildner 		"%s: Multiple dependent functions within a current resource",
7565db2f26eSSascha Wildner 				    __func__);
7575db2f26eSSascha Wildner 				break;
7585db2f26eSSascha Wildner 			}
7595db2f26eSSascha Wildner 			break;
7605db2f26eSSascha Wildner 		case ACPI_RESOURCE_TYPE_END_DEPENDENT:
7615db2f26eSSascha Wildner 			/* We are finished with DPF parsing. */
7625db2f26eSSascha Wildner 			KASSERT(in_dpf != DPF_OUTSIDE,
7635db2f26eSSascha Wildner 			    ("%s: end dpf when not parsing a dpf", __func__));
7645db2f26eSSascha Wildner 			in_dpf = DPF_OUTSIDE;
7655db2f26eSSascha Wildner 			break;
7665db2f26eSSascha Wildner 		case ACPI_RESOURCE_TYPE_IRQ:
7675db2f26eSSascha Wildner 			KKASSERT(i < sc->pl_num_links);
76806871c60SSascha Wildner 			res->Data.Irq.InterruptCount = 1;
7695db2f26eSSascha Wildner 			if (PCI_INTERRUPT_VALID(link->l_irq)) {
7705db2f26eSSascha Wildner 				KASSERT(link->l_irq < NUM_ISA_INTERRUPTS,
7715db2f26eSSascha Wildner 		("%s: can't put non-ISA IRQ %d in legacy IRQ resource type",
7725db2f26eSSascha Wildner 				    __func__, link->l_irq));
77306871c60SSascha Wildner 				res->Data.Irq.Interrupts[0] = link->l_irq;
7745db2f26eSSascha Wildner 			} else
77506871c60SSascha Wildner 				res->Data.Irq.Interrupts[0] = 0;
7765db2f26eSSascha Wildner 			link++;
7775db2f26eSSascha Wildner 			i++;
7785db2f26eSSascha Wildner 			break;
7795db2f26eSSascha Wildner 		case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
7805db2f26eSSascha Wildner 			KKASSERT(i < sc->pl_num_links);
78106871c60SSascha Wildner 			res->Data.ExtendedIrq.InterruptCount = 1;
7825db2f26eSSascha Wildner 			if (PCI_INTERRUPT_VALID(link->l_irq))
78306871c60SSascha Wildner 				res->Data.ExtendedIrq.Interrupts[0] =
7845db2f26eSSascha Wildner 				    link->l_irq;
7855db2f26eSSascha Wildner 			else
78606871c60SSascha Wildner 				res->Data.ExtendedIrq.Interrupts[0] = 0;
7875db2f26eSSascha Wildner 			link++;
7885db2f26eSSascha Wildner 			i++;
7895db2f26eSSascha Wildner 			break;
7905db2f26eSSascha Wildner 		}
79106871c60SSascha Wildner 		if (res->Type == ACPI_RESOURCE_TYPE_END_TAG)
7925db2f26eSSascha Wildner 			break;
79306871c60SSascha Wildner 		res = ACPI_NEXT_RESOURCE(res);
79406871c60SSascha Wildner 		if (res >= end)
7955db2f26eSSascha Wildner 			break;
7965db2f26eSSascha Wildner 	}
7975db2f26eSSascha Wildner 	return (AE_OK);
7985db2f26eSSascha Wildner }
7995db2f26eSSascha Wildner 
8005db2f26eSSascha Wildner static ACPI_STATUS
acpi_pci_link_srs_from_links(struct acpi_pci_link_softc * sc,ACPI_BUFFER * srsbuf)8015db2f26eSSascha Wildner acpi_pci_link_srs_from_links(struct acpi_pci_link_softc *sc,
8025db2f26eSSascha Wildner     ACPI_BUFFER *srsbuf)
8035db2f26eSSascha Wildner {
8045db2f26eSSascha Wildner 	ACPI_RESOURCE newres;
8055db2f26eSSascha Wildner 	ACPI_STATUS status;
8065db2f26eSSascha Wildner 	struct link *link;
8075db2f26eSSascha Wildner 	int i;
8085db2f26eSSascha Wildner 
8095db2f26eSSascha Wildner 	/* Start off with an empty buffer. */
8105db2f26eSSascha Wildner 	srsbuf->Pointer = NULL;
8115db2f26eSSascha Wildner 	link = sc->pl_links;
8125db2f26eSSascha Wildner 	for (i = 0; i < sc->pl_num_links; i++) {
8135db2f26eSSascha Wildner 
8145db2f26eSSascha Wildner 		/* Add a new IRQ resource from each link. */
8155db2f26eSSascha Wildner 		link = &sc->pl_links[i];
81606871c60SSascha Wildner 		if (link->l_prs_template.Type == ACPI_RESOURCE_TYPE_IRQ) {
8175db2f26eSSascha Wildner 
8185db2f26eSSascha Wildner 			/* Build an IRQ resource. */
81906871c60SSascha Wildner 			bcopy(&link->l_prs_template, &newres,
82006871c60SSascha Wildner 			    ACPI_RS_SIZE(newres.Data.Irq));
8215db2f26eSSascha Wildner 			newres.Data.Irq.InterruptCount = 1;
8225db2f26eSSascha Wildner 			if (PCI_INTERRUPT_VALID(link->l_irq)) {
8235db2f26eSSascha Wildner 				KASSERT(link->l_irq < NUM_ISA_INTERRUPTS,
8245db2f26eSSascha Wildner 		("%s: can't put non-ISA IRQ %d in legacy IRQ resource type",
8255db2f26eSSascha Wildner 				    __func__, link->l_irq));
8265db2f26eSSascha Wildner 				newres.Data.Irq.Interrupts[0] = link->l_irq;
8275db2f26eSSascha Wildner 			} else
8285db2f26eSSascha Wildner 				newres.Data.Irq.Interrupts[0] = 0;
8295db2f26eSSascha Wildner 		} else {
8305db2f26eSSascha Wildner 
8315db2f26eSSascha Wildner 			/* Build an ExtIRQ resuorce. */
83206871c60SSascha Wildner 			bcopy(&link->l_prs_template, &newres,
83306871c60SSascha Wildner 			    ACPI_RS_SIZE(newres.Data.ExtendedIrq));
8345db2f26eSSascha Wildner 			newres.Data.ExtendedIrq.InterruptCount = 1;
8355db2f26eSSascha Wildner 			if (PCI_INTERRUPT_VALID(link->l_irq))
8365db2f26eSSascha Wildner 				newres.Data.ExtendedIrq.Interrupts[0] =
8375db2f26eSSascha Wildner 				    link->l_irq;
8385db2f26eSSascha Wildner 			else
8395db2f26eSSascha Wildner 				newres.Data.ExtendedIrq.Interrupts[0] = 0;
8405db2f26eSSascha Wildner 		}
8415db2f26eSSascha Wildner 
8425db2f26eSSascha Wildner 		/* Add the new resource to the end of the _SRS buffer. */
8435db2f26eSSascha Wildner 		status = acpi_AppendBufferResource(srsbuf, &newres);
8445db2f26eSSascha Wildner 		if (ACPI_FAILURE(status)) {
8455db2f26eSSascha Wildner 			device_printf(sc->pl_dev,
8465db2f26eSSascha Wildner 			    "Unable to build resources: %s\n",
8475db2f26eSSascha Wildner 			    AcpiFormatException(status));
8485db2f26eSSascha Wildner 			if (srsbuf->Pointer != NULL)
8495db2f26eSSascha Wildner 				AcpiOsFree(srsbuf->Pointer);
8505db2f26eSSascha Wildner 			return (status);
8515db2f26eSSascha Wildner 		}
8525db2f26eSSascha Wildner 	}
8535db2f26eSSascha Wildner 	return (AE_OK);
8545db2f26eSSascha Wildner }
8555db2f26eSSascha Wildner 
8565db2f26eSSascha Wildner static ACPI_STATUS
acpi_pci_link_route_irqs(device_t dev)8575db2f26eSSascha Wildner acpi_pci_link_route_irqs(device_t dev)
8585db2f26eSSascha Wildner {
8595db2f26eSSascha Wildner 	struct acpi_pci_link_softc *sc;
8605db2f26eSSascha Wildner 	ACPI_RESOURCE *resource, *end;
8615db2f26eSSascha Wildner 	ACPI_BUFFER srsbuf;
8625db2f26eSSascha Wildner 	ACPI_STATUS status;
8635db2f26eSSascha Wildner 	struct link *link;
8645db2f26eSSascha Wildner 	int i;
8655db2f26eSSascha Wildner 
8665db2f26eSSascha Wildner 	ACPI_SERIAL_ASSERT(pci_link);
8675db2f26eSSascha Wildner 	sc = device_get_softc(dev);
8685db2f26eSSascha Wildner 	if (sc->pl_crs_bad)
8695db2f26eSSascha Wildner 		status = acpi_pci_link_srs_from_links(sc, &srsbuf);
8705db2f26eSSascha Wildner 	else
8715db2f26eSSascha Wildner 		status = acpi_pci_link_srs_from_crs(sc, &srsbuf);
8725db2f26eSSascha Wildner 
8735db2f26eSSascha Wildner 	/* Write out new resources via _SRS. */
8745db2f26eSSascha Wildner 	status = AcpiSetCurrentResources(acpi_get_handle(dev), &srsbuf);
8755db2f26eSSascha Wildner 	if (ACPI_FAILURE(status)) {
8765db2f26eSSascha Wildner 		device_printf(dev, "Unable to route IRQs: %s\n",
8775db2f26eSSascha Wildner 		    AcpiFormatException(status));
8785db2f26eSSascha Wildner 		AcpiOsFree(srsbuf.Pointer);
8795db2f26eSSascha Wildner 		return (status);
8805db2f26eSSascha Wildner 	}
8815db2f26eSSascha Wildner 
8825db2f26eSSascha Wildner 	/*
8835db2f26eSSascha Wildner 	 * Perform acpi_config_intr() on each IRQ resource if it was just
8845db2f26eSSascha Wildner 	 * routed for the first time.
8855db2f26eSSascha Wildner 	 */
8865db2f26eSSascha Wildner 	link = sc->pl_links;
8875db2f26eSSascha Wildner 	i = 0;
8885db2f26eSSascha Wildner 	resource = (ACPI_RESOURCE *)srsbuf.Pointer;
8895db2f26eSSascha Wildner 	end = (ACPI_RESOURCE *)((char *)srsbuf.Pointer + srsbuf.Length);
8905db2f26eSSascha Wildner 	for (;;) {
8915db2f26eSSascha Wildner 		if (resource->Type == ACPI_RESOURCE_TYPE_END_TAG)
8925db2f26eSSascha Wildner 			break;
8935db2f26eSSascha Wildner 		switch (resource->Type) {
8945db2f26eSSascha Wildner 		case ACPI_RESOURCE_TYPE_IRQ:
8955db2f26eSSascha Wildner 		case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
8965db2f26eSSascha Wildner 			KKASSERT(i < sc->pl_num_links);
8975db2f26eSSascha Wildner 
8985db2f26eSSascha Wildner 			/*
8995db2f26eSSascha Wildner 			 * Only configure the interrupt and update the
9005db2f26eSSascha Wildner 			 * weights if this link has a valid IRQ and was
9015db2f26eSSascha Wildner 			 * previously unrouted.
9025db2f26eSSascha Wildner 			 */
9035db2f26eSSascha Wildner 			if (!link->l_routed &&
9045db2f26eSSascha Wildner 			    PCI_INTERRUPT_VALID(link->l_irq)) {
9055db2f26eSSascha Wildner 				link->l_routed = TRUE;
9065db2f26eSSascha Wildner 				acpi_config_intr(dev, resource);
9075db2f26eSSascha Wildner 				pci_link_interrupt_weights[link->l_irq] +=
9085db2f26eSSascha Wildner 				    link->l_references;
9095db2f26eSSascha Wildner 			}
9105db2f26eSSascha Wildner 			link++;
9115db2f26eSSascha Wildner 			i++;
9125db2f26eSSascha Wildner 			break;
9135db2f26eSSascha Wildner 		}
9145db2f26eSSascha Wildner 		resource = ACPI_NEXT_RESOURCE(resource);
9155db2f26eSSascha Wildner 		if (resource >= end)
9165db2f26eSSascha Wildner 			break;
9175db2f26eSSascha Wildner 	}
9185db2f26eSSascha Wildner 	AcpiOsFree(srsbuf.Pointer);
9195db2f26eSSascha Wildner 	return (AE_OK);
9205db2f26eSSascha Wildner }
9215db2f26eSSascha Wildner 
9225db2f26eSSascha Wildner static int
acpi_pci_link_resume(device_t dev)9235db2f26eSSascha Wildner acpi_pci_link_resume(device_t dev)
9245db2f26eSSascha Wildner {
9255db2f26eSSascha Wildner 	struct acpi_pci_link_softc *sc;
9265db2f26eSSascha Wildner 	ACPI_STATUS status;
9275db2f26eSSascha Wildner 	int i, routed;
9285db2f26eSSascha Wildner 
9295db2f26eSSascha Wildner 	/*
9305db2f26eSSascha Wildner 	 * If all of our links are routed, then restore the link via _SRS,
9315db2f26eSSascha Wildner 	 * otherwise, disable the link via _DIS.
9325db2f26eSSascha Wildner 	 */
9335db2f26eSSascha Wildner 	ACPI_SERIAL_BEGIN(pci_link);
9345db2f26eSSascha Wildner 	sc = device_get_softc(dev);
9355db2f26eSSascha Wildner 	routed = 0;
9365db2f26eSSascha Wildner 	for (i = 0; i < sc->pl_num_links; i++)
9375db2f26eSSascha Wildner 		if (sc->pl_links[i].l_routed)
9385db2f26eSSascha Wildner 			routed++;
9395db2f26eSSascha Wildner 	if (routed == sc->pl_num_links)
9405db2f26eSSascha Wildner 		status = acpi_pci_link_route_irqs(dev);
9415db2f26eSSascha Wildner 	else {
9425db2f26eSSascha Wildner 		AcpiEvaluateObject(acpi_get_handle(dev), "_DIS", NULL, NULL);
9435db2f26eSSascha Wildner 		status = AE_OK;
9445db2f26eSSascha Wildner 	}
9455db2f26eSSascha Wildner 	ACPI_SERIAL_END(pci_link);
9465db2f26eSSascha Wildner 	if (ACPI_FAILURE(status))
9475db2f26eSSascha Wildner 		return (ENXIO);
9485db2f26eSSascha Wildner 	else
9495db2f26eSSascha Wildner 		return (0);
9505db2f26eSSascha Wildner }
9515db2f26eSSascha Wildner 
9525db2f26eSSascha Wildner /*
9535db2f26eSSascha Wildner  * Pick an IRQ to use for this unrouted link.
9545db2f26eSSascha Wildner  */
9555db2f26eSSascha Wildner static uint8_t
acpi_pci_link_choose_irq(device_t dev,struct link * link)9565db2f26eSSascha Wildner acpi_pci_link_choose_irq(device_t dev, struct link *link)
9575db2f26eSSascha Wildner {
9585db2f26eSSascha Wildner 	char tunable_buffer[64], link_name[5];
9593905511eSSascha Wildner 	uint8_t best_irq, pos_irq;
9605db2f26eSSascha Wildner 	int best_weight, pos_weight, i;
9615db2f26eSSascha Wildner 
9625db2f26eSSascha Wildner 	KASSERT(!link->l_routed, ("%s: link already routed", __func__));
9635db2f26eSSascha Wildner 	KASSERT(!PCI_INTERRUPT_VALID(link->l_irq),
9645db2f26eSSascha Wildner 	    ("%s: link already has an IRQ", __func__));
9655db2f26eSSascha Wildner 
9665db2f26eSSascha Wildner 	/* Check for a tunable override. */
9675db2f26eSSascha Wildner 	if (ACPI_SUCCESS(acpi_short_name(acpi_get_handle(dev), link_name,
9685db2f26eSSascha Wildner 	    sizeof(link_name)))) {
9695db2f26eSSascha Wildner 		ksnprintf(tunable_buffer, sizeof(tunable_buffer),
9705db2f26eSSascha Wildner 		    "hw.pci.link.%s.%d.irq", link_name, link->l_res_index);
9715db2f26eSSascha Wildner 		if (kgetenv_int(tunable_buffer, &i) && PCI_INTERRUPT_VALID(i)) {
9725db2f26eSSascha Wildner 			if (!link_valid_irq(link, i))
9735db2f26eSSascha Wildner 				device_printf(dev,
9745db2f26eSSascha Wildner 				    "Warning, IRQ %d is not listed as valid\n",
9755db2f26eSSascha Wildner 				    i);
9765db2f26eSSascha Wildner 			return (i);
9775db2f26eSSascha Wildner 		}
9785db2f26eSSascha Wildner 		ksnprintf(tunable_buffer, sizeof(tunable_buffer),
9795db2f26eSSascha Wildner 		    "hw.pci.link.%s.irq", link_name);
9805db2f26eSSascha Wildner 		if (kgetenv_int(tunable_buffer, &i) && PCI_INTERRUPT_VALID(i)) {
9815db2f26eSSascha Wildner 			if (!link_valid_irq(link, i))
9825db2f26eSSascha Wildner 				device_printf(dev,
9835db2f26eSSascha Wildner 				    "Warning, IRQ %d is not listed as valid\n",
9845db2f26eSSascha Wildner 				    i);
9855db2f26eSSascha Wildner 			return (i);
9865db2f26eSSascha Wildner 		}
9875db2f26eSSascha Wildner 	}
9885db2f26eSSascha Wildner 
9895db2f26eSSascha Wildner 	/*
9905db2f26eSSascha Wildner 	 * If we have a valid BIOS IRQ, use that.  We trust what the BIOS
9915db2f26eSSascha Wildner 	 * says it routed over what _CRS says the link thinks is routed.
9925db2f26eSSascha Wildner 	 */
9935db2f26eSSascha Wildner 	if (PCI_INTERRUPT_VALID(link->l_bios_irq))
9945db2f26eSSascha Wildner 		return (link->l_bios_irq);
9955db2f26eSSascha Wildner 
9965db2f26eSSascha Wildner 	/*
9975db2f26eSSascha Wildner 	 * If we don't have a BIOS IRQ but do have a valid IRQ from _CRS,
9985db2f26eSSascha Wildner 	 * then use that.
9995db2f26eSSascha Wildner 	 */
10005db2f26eSSascha Wildner 	if (PCI_INTERRUPT_VALID(link->l_initial_irq))
10015db2f26eSSascha Wildner 		return (link->l_initial_irq);
10025db2f26eSSascha Wildner 
10035db2f26eSSascha Wildner 	/*
10045db2f26eSSascha Wildner 	 * Ok, we have no useful hints, so we have to pick from the
10055db2f26eSSascha Wildner 	 * possible IRQs.  For ISA IRQs we only use interrupts that
10065db2f26eSSascha Wildner 	 * have already been used by the BIOS.
10075db2f26eSSascha Wildner 	 */
10085db2f26eSSascha Wildner 	best_irq = PCI_INVALID_IRQ;
10095db2f26eSSascha Wildner 	best_weight = INT_MAX;
10105db2f26eSSascha Wildner 	for (i = 0; i < link->l_num_irqs; i++) {
10115db2f26eSSascha Wildner 		pos_irq = link->l_irqs[i];
10125db2f26eSSascha Wildner 		if (pos_irq < NUM_ISA_INTERRUPTS &&
10135db2f26eSSascha Wildner 		    (pci_link_bios_isa_irqs & 1 << pos_irq) == 0)
10145db2f26eSSascha Wildner 			continue;
10155db2f26eSSascha Wildner 		pos_weight = pci_link_interrupt_weights[pos_irq];
10165db2f26eSSascha Wildner 		if (pos_weight < best_weight) {
10175db2f26eSSascha Wildner 			best_weight = pos_weight;
10185db2f26eSSascha Wildner 			best_irq = pos_irq;
10195db2f26eSSascha Wildner 		}
10205db2f26eSSascha Wildner 	}
10215db2f26eSSascha Wildner 
10225db2f26eSSascha Wildner         /*
10235db2f26eSSascha Wildner 	 * If this is an ISA IRQ and SCI could be shared, try using
10245db2f26eSSascha Wildner 	 * the SCI as a fallback.
10255db2f26eSSascha Wildner 	 */
1026737d9e74SSascha Wildner 	if (link->l_isa_irq && acpi_sci_pci_shareable()) {
10275db2f26eSSascha Wildner 		pos_irq = AcpiGbl_FADT.SciInterrupt;
10285db2f26eSSascha Wildner 		pos_weight = pci_link_interrupt_weights[pos_irq];
10295db2f26eSSascha Wildner 		if (pos_weight < best_weight) {
10305db2f26eSSascha Wildner 			best_weight = pos_weight;
10315db2f26eSSascha Wildner 			best_irq = pos_irq;
10325db2f26eSSascha Wildner 		}
10335db2f26eSSascha Wildner 	}
10345db2f26eSSascha Wildner 
10355db2f26eSSascha Wildner 	if (PCI_INTERRUPT_VALID(best_irq)) {
10365db2f26eSSascha Wildner 		if (bootverbose)
10375db2f26eSSascha Wildner 			device_printf(dev, "Picked IRQ %u with weight %d\n",
10385db2f26eSSascha Wildner 			    best_irq, best_weight);
10395db2f26eSSascha Wildner 	} else
10405db2f26eSSascha Wildner 		device_printf(dev, "Unable to choose an IRQ\n");
10415db2f26eSSascha Wildner 	return (best_irq);
10425db2f26eSSascha Wildner }
10435db2f26eSSascha Wildner 
10445db2f26eSSascha Wildner int
acpi_pci_link_route_interrupt(device_t dev,int index)10455db2f26eSSascha Wildner acpi_pci_link_route_interrupt(device_t dev, int index)
10465db2f26eSSascha Wildner {
10475db2f26eSSascha Wildner 	struct link *link;
10485db2f26eSSascha Wildner 
10495db2f26eSSascha Wildner 	if (acpi_disabled("pci_link"))
10505db2f26eSSascha Wildner 		return (PCI_INVALID_IRQ);
10515db2f26eSSascha Wildner 
10525db2f26eSSascha Wildner 	ACPI_SERIAL_BEGIN(pci_link);
10535db2f26eSSascha Wildner 	link = acpi_pci_link_lookup(dev, index);
10545db2f26eSSascha Wildner 	if (link == NULL)
10555db2f26eSSascha Wildner 		panic("%s: apparently invalid index %d", __func__, index);
10565db2f26eSSascha Wildner 
10575db2f26eSSascha Wildner 	/*
10585db2f26eSSascha Wildner 	 * If this link device is already routed to an interrupt, just return
10595db2f26eSSascha Wildner 	 * the interrupt it is routed to.
10605db2f26eSSascha Wildner 	 */
10615db2f26eSSascha Wildner 	if (link->l_routed) {
10625db2f26eSSascha Wildner 		KASSERT(PCI_INTERRUPT_VALID(link->l_irq),
10635db2f26eSSascha Wildner 		    ("%s: link is routed but has an invalid IRQ", __func__));
10645db2f26eSSascha Wildner 		ACPI_SERIAL_END(pci_link);
10655db2f26eSSascha Wildner 		return (link->l_irq);
10665db2f26eSSascha Wildner 	}
10675db2f26eSSascha Wildner 
10685db2f26eSSascha Wildner 	/* Choose an IRQ if we need one. */
10695db2f26eSSascha Wildner 	if (!PCI_INTERRUPT_VALID(link->l_irq)) {
10705db2f26eSSascha Wildner 		link->l_irq = acpi_pci_link_choose_irq(dev, link);
10715db2f26eSSascha Wildner 
10725db2f26eSSascha Wildner 		/*
10735db2f26eSSascha Wildner 		 * Try to route the interrupt we picked.  If it fails, then
10745db2f26eSSascha Wildner 		 * assume the interrupt is not routed.
10755db2f26eSSascha Wildner 		 */
10765db2f26eSSascha Wildner 		if (PCI_INTERRUPT_VALID(link->l_irq)) {
10775db2f26eSSascha Wildner 			acpi_pci_link_route_irqs(dev);
10785db2f26eSSascha Wildner 			if (!link->l_routed)
10795db2f26eSSascha Wildner 				link->l_irq = PCI_INVALID_IRQ;
10805db2f26eSSascha Wildner 		}
10815db2f26eSSascha Wildner 	}
10825db2f26eSSascha Wildner 	ACPI_SERIAL_END(pci_link);
10835db2f26eSSascha Wildner 	return (link->l_irq);
10845db2f26eSSascha Wildner }
10855db2f26eSSascha Wildner 
10865db2f26eSSascha Wildner /*
10875db2f26eSSascha Wildner  * This is gross, but we abuse the identify routine to perform one-time
10885db2f26eSSascha Wildner  * SYSINIT() style initialization for the driver.
10895db2f26eSSascha Wildner  */
10905db2f26eSSascha Wildner static void
acpi_pci_link_identify(driver_t * driver,device_t parent)10915db2f26eSSascha Wildner acpi_pci_link_identify(driver_t *driver, device_t parent)
10925db2f26eSSascha Wildner {
10935db2f26eSSascha Wildner 	/*
10945db2f26eSSascha Wildner 	 * If the SCI is an ISA IRQ and could be shared,
10955db2f26eSSascha Wildner 	 * add it to the bitmask of known good ISA IRQs.
10965db2f26eSSascha Wildner 	 */
10975db2f26eSSascha Wildner 	if (AcpiGbl_FADT.SciInterrupt < NUM_ISA_INTERRUPTS &&
1098737d9e74SSascha Wildner 	    acpi_sci_pci_shareable())
10995db2f26eSSascha Wildner 		pci_link_bios_isa_irqs |= (1 << AcpiGbl_FADT.SciInterrupt);
11005db2f26eSSascha Wildner }
11015db2f26eSSascha Wildner 
11025db2f26eSSascha Wildner static device_method_t acpi_pci_link_methods[] = {
11035db2f26eSSascha Wildner 	/* Device interface */
11045db2f26eSSascha Wildner 	DEVMETHOD(device_identify,	acpi_pci_link_identify),
11055db2f26eSSascha Wildner 	DEVMETHOD(device_probe,		acpi_pci_link_probe),
11065db2f26eSSascha Wildner 	DEVMETHOD(device_attach,	acpi_pci_link_attach),
11075db2f26eSSascha Wildner 	DEVMETHOD(device_resume,	acpi_pci_link_resume),
11085db2f26eSSascha Wildner 
1109d3c9c58eSSascha Wildner 	DEVMETHOD_END
11105db2f26eSSascha Wildner };
11115db2f26eSSascha Wildner 
11125db2f26eSSascha Wildner static driver_t acpi_pci_link_driver = {
11135db2f26eSSascha Wildner 	"pci_link",
11145db2f26eSSascha Wildner 	acpi_pci_link_methods,
11155db2f26eSSascha Wildner 	sizeof(struct acpi_pci_link_softc),
1116*5025fc65SMatthew Dillon 	.gpri = KOBJ_GPRI_ACPI
11175db2f26eSSascha Wildner };
11185db2f26eSSascha Wildner 
11195db2f26eSSascha Wildner static devclass_t pci_link_devclass;
11205db2f26eSSascha Wildner 
11215db2f26eSSascha Wildner DRIVER_MODULE(acpi_pci_link, acpi, acpi_pci_link_driver, pci_link_devclass,
11225db2f26eSSascha Wildner     NULL, NULL);
11235db2f26eSSascha Wildner MODULE_DEPEND(acpi_pci_link, acpi, 1, 1, 1);
1124