xref: /dflybsd-src/sys/dev/acpica/acpi_pci_link.c (revision 5db2f26edd92ab4befeb61802687554b3ee6769a)
1*5db2f26eSSascha Wildner /*
2*5db2f26eSSascha Wildner  * Copyright (c) 2002 Mitsuru IWASAKI <iwasaki@jp.kfreebsd.org>
3*5db2f26eSSascha Wildner  * All rights reserved.
4*5db2f26eSSascha Wildner  *
5*5db2f26eSSascha Wildner  * Redistribution and use in source and binary forms, with or without
6*5db2f26eSSascha Wildner  * modification, are permitted provided that the following conditions
7*5db2f26eSSascha Wildner  * are met:
8*5db2f26eSSascha Wildner  * 1. Redistributions of source code must retain the above copyright
9*5db2f26eSSascha Wildner  *    notice, this list of conditions and the following disclaimer.
10*5db2f26eSSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
11*5db2f26eSSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
12*5db2f26eSSascha Wildner  *    documentation and/or other materials provided with the distribution.
13*5db2f26eSSascha Wildner  *
14*5db2f26eSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*5db2f26eSSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*5db2f26eSSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*5db2f26eSSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*5db2f26eSSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*5db2f26eSSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*5db2f26eSSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*5db2f26eSSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*5db2f26eSSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*5db2f26eSSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*5db2f26eSSascha Wildner  * SUCH DAMAGE.
25*5db2f26eSSascha Wildner  *
26*5db2f26eSSascha Wildner  * $FreeBSD: src/sys/dev/acpica/acpi_pci_link.c,v 1.56.2.1.6.1 2009/04/15 03:14:26 kensmith Exp $
27*5db2f26eSSascha Wildner  */
28*5db2f26eSSascha Wildner 
29*5db2f26eSSascha Wildner #include "opt_acpi.h"
30*5db2f26eSSascha Wildner #include <sys/param.h>
31*5db2f26eSSascha Wildner #include <sys/bus.h>
32*5db2f26eSSascha Wildner #include <sys/kernel.h>
33*5db2f26eSSascha Wildner #include <sys/limits.h>
34*5db2f26eSSascha Wildner #include <sys/malloc.h>
35*5db2f26eSSascha Wildner #include <sys/module.h>
36*5db2f26eSSascha Wildner 
37*5db2f26eSSascha Wildner #include "acpi.h"
38*5db2f26eSSascha Wildner #include <dev/acpica/acpivar.h>
39*5db2f26eSSascha Wildner #include <dev/acpica/acpi_pcibvar.h>
40*5db2f26eSSascha Wildner #include <dev/acpica/acpi_sci_var.h>
41*5db2f26eSSascha Wildner 
42*5db2f26eSSascha Wildner #include <bus/pci/i386/pci_cfgreg.h>
43*5db2f26eSSascha Wildner #include <bus/pci/pcireg.h>
44*5db2f26eSSascha Wildner #include <bus/pci/pcivar.h>
45*5db2f26eSSascha Wildner #include "pcib_if.h"
46*5db2f26eSSascha Wildner 
47*5db2f26eSSascha Wildner /* Hooks for the ACPI CA debugging infrastructure. */
48*5db2f26eSSascha Wildner #define _COMPONENT	ACPI_BUS
49*5db2f26eSSascha Wildner ACPI_MODULE_NAME("PCI_LINK")
50*5db2f26eSSascha Wildner 
51*5db2f26eSSascha Wildner ACPI_SERIAL_DECL(pci_link, "ACPI PCI link");
52*5db2f26eSSascha Wildner 
53*5db2f26eSSascha Wildner #define NUM_ISA_INTERRUPTS	16
54*5db2f26eSSascha Wildner #define NUM_ACPI_INTERRUPTS	256
55*5db2f26eSSascha Wildner 
56*5db2f26eSSascha Wildner /*
57*5db2f26eSSascha Wildner  * An ACPI PCI link device may contain multiple links.  Each link has its
58*5db2f26eSSascha Wildner  * own ACPI resource.  _PRT entries specify which link is being used via
59*5db2f26eSSascha Wildner  * the Source Index.
60*5db2f26eSSascha Wildner  *
61*5db2f26eSSascha Wildner  * XXX: A note about Source Indices and DPFs:  Currently we assume that
62*5db2f26eSSascha Wildner  * the DPF start and end tags are not counted towards the index that
63*5db2f26eSSascha Wildner  * Source Index corresponds to.  Also, we assume that when DPFs are in use
64*5db2f26eSSascha Wildner  * they various sets overlap in terms of Indices.  Here's an example
65*5db2f26eSSascha Wildner  * resource list indicating these assumptions:
66*5db2f26eSSascha Wildner  *
67*5db2f26eSSascha Wildner  * Resource		Index
68*5db2f26eSSascha Wildner  * --------		-----
69*5db2f26eSSascha Wildner  * I/O Port		0
70*5db2f26eSSascha Wildner  * Start DPF		-
71*5db2f26eSSascha Wildner  * IRQ			1
72*5db2f26eSSascha Wildner  * MemIO		2
73*5db2f26eSSascha Wildner  * Start DPF		-
74*5db2f26eSSascha Wildner  * IRQ			1
75*5db2f26eSSascha Wildner  * MemIO		2
76*5db2f26eSSascha Wildner  * End DPF		-
77*5db2f26eSSascha Wildner  * DMA Channel		3
78*5db2f26eSSascha Wildner  *
79*5db2f26eSSascha Wildner  * The XXX is because I'm not sure if this is a valid assumption to make.
80*5db2f26eSSascha Wildner  */
81*5db2f26eSSascha Wildner 
82*5db2f26eSSascha Wildner /* States during DPF processing. */
83*5db2f26eSSascha Wildner #define	DPF_OUTSIDE	0
84*5db2f26eSSascha Wildner #define	DPF_FIRST	1
85*5db2f26eSSascha Wildner #define	DPF_IGNORE	2
86*5db2f26eSSascha Wildner 
87*5db2f26eSSascha Wildner struct link;
88*5db2f26eSSascha Wildner 
89*5db2f26eSSascha Wildner struct acpi_pci_link_softc {
90*5db2f26eSSascha Wildner 	int	pl_num_links;
91*5db2f26eSSascha Wildner 	int	pl_crs_bad;
92*5db2f26eSSascha Wildner 	struct link *pl_links;
93*5db2f26eSSascha Wildner 	device_t pl_dev;
94*5db2f26eSSascha Wildner };
95*5db2f26eSSascha Wildner 
96*5db2f26eSSascha Wildner struct link {
97*5db2f26eSSascha Wildner 	struct acpi_pci_link_softc *l_sc;
98*5db2f26eSSascha Wildner 	uint8_t	l_bios_irq;
99*5db2f26eSSascha Wildner 	uint8_t	l_irq;
100*5db2f26eSSascha Wildner 	uint8_t	l_initial_irq;
101*5db2f26eSSascha Wildner 	int	l_res_index;
102*5db2f26eSSascha Wildner 	int	l_num_irqs;
103*5db2f26eSSascha Wildner 	int	*l_irqs;
104*5db2f26eSSascha Wildner 	int	l_references;
105*5db2f26eSSascha Wildner 	int	l_routed:1;
106*5db2f26eSSascha Wildner 	int	l_isa_irq:1;
107*5db2f26eSSascha Wildner 	ACPI_RESOURCE l_prs_template;
108*5db2f26eSSascha Wildner };
109*5db2f26eSSascha Wildner 
110*5db2f26eSSascha Wildner struct link_count_request {
111*5db2f26eSSascha Wildner 	int	in_dpf;
112*5db2f26eSSascha Wildner 	int	count;
113*5db2f26eSSascha Wildner };
114*5db2f26eSSascha Wildner 
115*5db2f26eSSascha Wildner struct link_res_request {
116*5db2f26eSSascha Wildner 	struct acpi_pci_link_softc *sc;
117*5db2f26eSSascha Wildner 	int	in_dpf;
118*5db2f26eSSascha Wildner 	int	res_index;
119*5db2f26eSSascha Wildner 	int	link_index;
120*5db2f26eSSascha Wildner };
121*5db2f26eSSascha Wildner 
122*5db2f26eSSascha Wildner MALLOC_DEFINE(M_PCI_LINK, "pci_link", "ACPI PCI Link structures");
123*5db2f26eSSascha Wildner 
124*5db2f26eSSascha Wildner static int pci_link_interrupt_weights[NUM_ACPI_INTERRUPTS];
125*5db2f26eSSascha Wildner static int pci_link_bios_isa_irqs;
126*5db2f26eSSascha Wildner 
127*5db2f26eSSascha Wildner static char *pci_link_ids[] = { "PNP0C0F", NULL };
128*5db2f26eSSascha Wildner 
129*5db2f26eSSascha Wildner /*
130*5db2f26eSSascha Wildner  * Fetch the short name associated with an ACPI handle and save it in the
131*5db2f26eSSascha Wildner  * passed in buffer.
132*5db2f26eSSascha Wildner  */
133*5db2f26eSSascha Wildner static ACPI_STATUS
134*5db2f26eSSascha Wildner acpi_short_name(ACPI_HANDLE handle, char *buffer, size_t buflen)
135*5db2f26eSSascha Wildner {
136*5db2f26eSSascha Wildner 	ACPI_BUFFER buf;
137*5db2f26eSSascha Wildner 
138*5db2f26eSSascha Wildner 	buf.Length = buflen;
139*5db2f26eSSascha Wildner 	buf.Pointer = buffer;
140*5db2f26eSSascha Wildner 	return (AcpiGetName(handle, ACPI_SINGLE_NAME, &buf));
141*5db2f26eSSascha Wildner }
142*5db2f26eSSascha Wildner 
143*5db2f26eSSascha Wildner static int
144*5db2f26eSSascha Wildner acpi_pci_link_probe(device_t dev)
145*5db2f26eSSascha Wildner {
146*5db2f26eSSascha Wildner 	char descr[28], name[12];
147*5db2f26eSSascha Wildner 
148*5db2f26eSSascha Wildner 	/*
149*5db2f26eSSascha Wildner 	 * We explicitly do not check _STA since not all systems set it to
150*5db2f26eSSascha Wildner 	 * sensible values.
151*5db2f26eSSascha Wildner 	 */
152*5db2f26eSSascha Wildner 	if (acpi_disabled("pci_link") ||
153*5db2f26eSSascha Wildner 	    ACPI_ID_PROBE(device_get_parent(dev), dev, pci_link_ids) == NULL)
154*5db2f26eSSascha Wildner 		return (ENXIO);
155*5db2f26eSSascha Wildner 
156*5db2f26eSSascha Wildner 	if (ACPI_SUCCESS(acpi_short_name(acpi_get_handle(dev), name,
157*5db2f26eSSascha Wildner 	    sizeof(name)))) {
158*5db2f26eSSascha Wildner 		ksnprintf(descr, sizeof(descr), "ACPI PCI Link %s", name);
159*5db2f26eSSascha Wildner 		device_set_desc_copy(dev, descr);
160*5db2f26eSSascha Wildner 	} else
161*5db2f26eSSascha Wildner 		device_set_desc(dev, "ACPI PCI Link");
162*5db2f26eSSascha Wildner 	device_quiet(dev);
163*5db2f26eSSascha Wildner 	return (0);
164*5db2f26eSSascha Wildner }
165*5db2f26eSSascha Wildner 
166*5db2f26eSSascha Wildner static ACPI_STATUS
167*5db2f26eSSascha Wildner acpi_count_irq_resources(ACPI_RESOURCE *res, void *context)
168*5db2f26eSSascha Wildner {
169*5db2f26eSSascha Wildner 	struct link_count_request *req;
170*5db2f26eSSascha Wildner 
171*5db2f26eSSascha Wildner 	req = (struct link_count_request *)context;
172*5db2f26eSSascha Wildner 	switch (res->Type) {
173*5db2f26eSSascha Wildner 	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
174*5db2f26eSSascha Wildner 		switch (req->in_dpf) {
175*5db2f26eSSascha Wildner 		case DPF_OUTSIDE:
176*5db2f26eSSascha Wildner 			/* We've started the first DPF. */
177*5db2f26eSSascha Wildner 			req->in_dpf = DPF_FIRST;
178*5db2f26eSSascha Wildner 			break;
179*5db2f26eSSascha Wildner 		case DPF_FIRST:
180*5db2f26eSSascha Wildner 			/* We've started the second DPF. */
181*5db2f26eSSascha Wildner 			req->in_dpf = DPF_IGNORE;
182*5db2f26eSSascha Wildner 			break;
183*5db2f26eSSascha Wildner 		}
184*5db2f26eSSascha Wildner 		break;
185*5db2f26eSSascha Wildner 	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
186*5db2f26eSSascha Wildner 		/* We are finished with DPF parsing. */
187*5db2f26eSSascha Wildner 		KASSERT(req->in_dpf != DPF_OUTSIDE,
188*5db2f26eSSascha Wildner 		    ("%s: end dpf when not parsing a dpf", __func__));
189*5db2f26eSSascha Wildner 		req->in_dpf = DPF_OUTSIDE;
190*5db2f26eSSascha Wildner 		break;
191*5db2f26eSSascha Wildner 	case ACPI_RESOURCE_TYPE_IRQ:
192*5db2f26eSSascha Wildner 	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
193*5db2f26eSSascha Wildner 		/*
194*5db2f26eSSascha Wildner 		 * Don't count resources if we are in a DPF set that we are
195*5db2f26eSSascha Wildner 		 * ignoring.
196*5db2f26eSSascha Wildner 		 */
197*5db2f26eSSascha Wildner 		if (req->in_dpf != DPF_IGNORE)
198*5db2f26eSSascha Wildner 			req->count++;
199*5db2f26eSSascha Wildner 	}
200*5db2f26eSSascha Wildner 	return (AE_OK);
201*5db2f26eSSascha Wildner }
202*5db2f26eSSascha Wildner 
203*5db2f26eSSascha Wildner static ACPI_STATUS
204*5db2f26eSSascha Wildner link_add_crs(ACPI_RESOURCE *res, void *context)
205*5db2f26eSSascha Wildner {
206*5db2f26eSSascha Wildner 	struct link_res_request *req;
207*5db2f26eSSascha Wildner 	struct link *link;
208*5db2f26eSSascha Wildner 
209*5db2f26eSSascha Wildner 	ACPI_SERIAL_ASSERT(pci_link);
210*5db2f26eSSascha Wildner 	req = (struct link_res_request *)context;
211*5db2f26eSSascha Wildner 	switch (res->Type) {
212*5db2f26eSSascha Wildner 	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
213*5db2f26eSSascha Wildner 		switch (req->in_dpf) {
214*5db2f26eSSascha Wildner 		case DPF_OUTSIDE:
215*5db2f26eSSascha Wildner 			/* We've started the first DPF. */
216*5db2f26eSSascha Wildner 			req->in_dpf = DPF_FIRST;
217*5db2f26eSSascha Wildner 			break;
218*5db2f26eSSascha Wildner 		case DPF_FIRST:
219*5db2f26eSSascha Wildner 			/* We've started the second DPF. */
220*5db2f26eSSascha Wildner 			panic(
221*5db2f26eSSascha Wildner 		"%s: Multiple dependent functions within a current resource",
222*5db2f26eSSascha Wildner 			    __func__);
223*5db2f26eSSascha Wildner 			break;
224*5db2f26eSSascha Wildner 		}
225*5db2f26eSSascha Wildner 		break;
226*5db2f26eSSascha Wildner 	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
227*5db2f26eSSascha Wildner 		/* We are finished with DPF parsing. */
228*5db2f26eSSascha Wildner 		KASSERT(req->in_dpf != DPF_OUTSIDE,
229*5db2f26eSSascha Wildner 		    ("%s: end dpf when not parsing a dpf", __func__));
230*5db2f26eSSascha Wildner 		req->in_dpf = DPF_OUTSIDE;
231*5db2f26eSSascha Wildner 		break;
232*5db2f26eSSascha Wildner 	case ACPI_RESOURCE_TYPE_IRQ:
233*5db2f26eSSascha Wildner 	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
234*5db2f26eSSascha Wildner 		KASSERT(req->link_index < req->sc->pl_num_links,
235*5db2f26eSSascha Wildner 		    ("%s: array boundary violation", __func__));
236*5db2f26eSSascha Wildner 		link = &req->sc->pl_links[req->link_index];
237*5db2f26eSSascha Wildner 		link->l_res_index = req->res_index;
238*5db2f26eSSascha Wildner 		req->link_index++;
239*5db2f26eSSascha Wildner 		req->res_index++;
240*5db2f26eSSascha Wildner 
241*5db2f26eSSascha Wildner 		/*
242*5db2f26eSSascha Wildner 		 * Only use the current value if there's one IRQ.  Some
243*5db2f26eSSascha Wildner 		 * systems return multiple IRQs (which is nonsense for _CRS)
244*5db2f26eSSascha Wildner 		 * when the link hasn't been programmed.
245*5db2f26eSSascha Wildner 		 */
246*5db2f26eSSascha Wildner 		if (res->Type == ACPI_RESOURCE_TYPE_IRQ) {
247*5db2f26eSSascha Wildner 			if (res->Data.Irq.InterruptCount == 1)
248*5db2f26eSSascha Wildner 				link->l_irq = res->Data.Irq.Interrupts[0];
249*5db2f26eSSascha Wildner 		} else if (res->Data.ExtendedIrq.InterruptCount == 1)
250*5db2f26eSSascha Wildner 			link->l_irq = res->Data.ExtendedIrq.Interrupts[0];
251*5db2f26eSSascha Wildner 
252*5db2f26eSSascha Wildner 		/*
253*5db2f26eSSascha Wildner 		 * An IRQ of zero means that the link isn't routed.
254*5db2f26eSSascha Wildner 		 */
255*5db2f26eSSascha Wildner 		if (link->l_irq == 0)
256*5db2f26eSSascha Wildner 			link->l_irq = PCI_INVALID_IRQ;
257*5db2f26eSSascha Wildner 		break;
258*5db2f26eSSascha Wildner 	default:
259*5db2f26eSSascha Wildner 		req->res_index++;
260*5db2f26eSSascha Wildner 	}
261*5db2f26eSSascha Wildner 	return (AE_OK);
262*5db2f26eSSascha Wildner }
263*5db2f26eSSascha Wildner 
264*5db2f26eSSascha Wildner /*
265*5db2f26eSSascha Wildner  * Populate the set of possible IRQs for each device.
266*5db2f26eSSascha Wildner  */
267*5db2f26eSSascha Wildner static ACPI_STATUS
268*5db2f26eSSascha Wildner link_add_prs(ACPI_RESOURCE *res, void *context)
269*5db2f26eSSascha Wildner {
270*5db2f26eSSascha Wildner 	struct link_res_request *req;
271*5db2f26eSSascha Wildner 	struct link *link;
272*5db2f26eSSascha Wildner 	UINT8 *irqs = NULL;
273*5db2f26eSSascha Wildner 	UINT32 *ext_irqs = NULL;
274*5db2f26eSSascha Wildner 	int i, is_ext_irq = 1;
275*5db2f26eSSascha Wildner 
276*5db2f26eSSascha Wildner 	ACPI_SERIAL_ASSERT(pci_link);
277*5db2f26eSSascha Wildner 	req = (struct link_res_request *)context;
278*5db2f26eSSascha Wildner 	switch (res->Type) {
279*5db2f26eSSascha Wildner 	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
280*5db2f26eSSascha Wildner 		switch (req->in_dpf) {
281*5db2f26eSSascha Wildner 		case DPF_OUTSIDE:
282*5db2f26eSSascha Wildner 			/* We've started the first DPF. */
283*5db2f26eSSascha Wildner 			req->in_dpf = DPF_FIRST;
284*5db2f26eSSascha Wildner 			break;
285*5db2f26eSSascha Wildner 		case DPF_FIRST:
286*5db2f26eSSascha Wildner 			/* We've started the second DPF. */
287*5db2f26eSSascha Wildner 			req->in_dpf = DPF_IGNORE;
288*5db2f26eSSascha Wildner 			break;
289*5db2f26eSSascha Wildner 		}
290*5db2f26eSSascha Wildner 		break;
291*5db2f26eSSascha Wildner 	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
292*5db2f26eSSascha Wildner 		/* We are finished with DPF parsing. */
293*5db2f26eSSascha Wildner 		KASSERT(req->in_dpf != DPF_OUTSIDE,
294*5db2f26eSSascha Wildner 		    ("%s: end dpf when not parsing a dpf", __func__));
295*5db2f26eSSascha Wildner 		req->in_dpf = DPF_OUTSIDE;
296*5db2f26eSSascha Wildner 		break;
297*5db2f26eSSascha Wildner 	case ACPI_RESOURCE_TYPE_IRQ:
298*5db2f26eSSascha Wildner 		is_ext_irq = 0;
299*5db2f26eSSascha Wildner 		/* fall through */
300*5db2f26eSSascha Wildner 	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
301*5db2f26eSSascha Wildner 		/*
302*5db2f26eSSascha Wildner 		 * Don't parse resources if we are in a DPF set that we are
303*5db2f26eSSascha Wildner 		 * ignoring.
304*5db2f26eSSascha Wildner 		 */
305*5db2f26eSSascha Wildner 		if (req->in_dpf == DPF_IGNORE)
306*5db2f26eSSascha Wildner 			break;
307*5db2f26eSSascha Wildner 
308*5db2f26eSSascha Wildner 		KASSERT(req->link_index < req->sc->pl_num_links,
309*5db2f26eSSascha Wildner 		    ("%s: array boundary violation", __func__));
310*5db2f26eSSascha Wildner 		link = &req->sc->pl_links[req->link_index];
311*5db2f26eSSascha Wildner 		if (link->l_res_index == -1) {
312*5db2f26eSSascha Wildner 			KASSERT(req->sc->pl_crs_bad,
313*5db2f26eSSascha Wildner 			    ("res_index should be set"));
314*5db2f26eSSascha Wildner 			link->l_res_index = req->res_index;
315*5db2f26eSSascha Wildner 		}
316*5db2f26eSSascha Wildner 		req->link_index++;
317*5db2f26eSSascha Wildner 		req->res_index++;
318*5db2f26eSSascha Wildner 
319*5db2f26eSSascha Wildner 		/*
320*5db2f26eSSascha Wildner 		 * Stash a copy of the resource for later use when doing
321*5db2f26eSSascha Wildner 		 * _SRS.
322*5db2f26eSSascha Wildner 		 */
323*5db2f26eSSascha Wildner 		bcopy(res, &link->l_prs_template, sizeof(ACPI_RESOURCE));
324*5db2f26eSSascha Wildner 		if (is_ext_irq) {
325*5db2f26eSSascha Wildner 			link->l_num_irqs =
326*5db2f26eSSascha Wildner 			    res->Data.ExtendedIrq.InterruptCount;
327*5db2f26eSSascha Wildner 			ext_irqs = res->Data.ExtendedIrq.Interrupts;
328*5db2f26eSSascha Wildner 		} else {
329*5db2f26eSSascha Wildner 			link->l_num_irqs = res->Data.Irq.InterruptCount;
330*5db2f26eSSascha Wildner 			irqs = res->Data.Irq.Interrupts;
331*5db2f26eSSascha Wildner 		}
332*5db2f26eSSascha Wildner 		if (link->l_num_irqs == 0)
333*5db2f26eSSascha Wildner 			break;
334*5db2f26eSSascha Wildner 
335*5db2f26eSSascha Wildner 		/*
336*5db2f26eSSascha Wildner 		 * Save a list of the valid IRQs.  Also, if all of the
337*5db2f26eSSascha Wildner 		 * valid IRQs are ISA IRQs, then mark this link as
338*5db2f26eSSascha Wildner 		 * routed via an ISA interrupt.
339*5db2f26eSSascha Wildner 		 */
340*5db2f26eSSascha Wildner 		link->l_isa_irq = TRUE;
341*5db2f26eSSascha Wildner 
342*5db2f26eSSascha Wildner 		link->l_irqs = kmalloc(sizeof(int) * link->l_num_irqs,
343*5db2f26eSSascha Wildner 		    M_PCI_LINK, M_WAITOK | M_ZERO);
344*5db2f26eSSascha Wildner 		for (i = 0; i < link->l_num_irqs; i++) {
345*5db2f26eSSascha Wildner 			if (is_ext_irq) {
346*5db2f26eSSascha Wildner 				link->l_irqs[i] = ext_irqs[i];
347*5db2f26eSSascha Wildner 				if (ext_irqs[i] >= NUM_ISA_INTERRUPTS)
348*5db2f26eSSascha Wildner 					link->l_isa_irq = FALSE;
349*5db2f26eSSascha Wildner 			} else {
350*5db2f26eSSascha Wildner 				link->l_irqs[i] = irqs[i];
351*5db2f26eSSascha Wildner 				if (irqs[i] >= NUM_ISA_INTERRUPTS)
352*5db2f26eSSascha Wildner 					link->l_isa_irq = FALSE;
353*5db2f26eSSascha Wildner 			}
354*5db2f26eSSascha Wildner 		}
355*5db2f26eSSascha Wildner 		break;
356*5db2f26eSSascha Wildner 	default:
357*5db2f26eSSascha Wildner 		if (req->in_dpf == DPF_IGNORE)
358*5db2f26eSSascha Wildner 			break;
359*5db2f26eSSascha Wildner 		if (req->sc->pl_crs_bad)
360*5db2f26eSSascha Wildner 			device_printf(req->sc->pl_dev,
361*5db2f26eSSascha Wildner 		    "Warning: possible resource %d will be lost during _SRS\n",
362*5db2f26eSSascha Wildner 			    req->res_index);
363*5db2f26eSSascha Wildner 		req->res_index++;
364*5db2f26eSSascha Wildner 	}
365*5db2f26eSSascha Wildner 	return (AE_OK);
366*5db2f26eSSascha Wildner }
367*5db2f26eSSascha Wildner 
368*5db2f26eSSascha Wildner static int
369*5db2f26eSSascha Wildner link_valid_irq(struct link *link, int irq)
370*5db2f26eSSascha Wildner {
371*5db2f26eSSascha Wildner 	int i;
372*5db2f26eSSascha Wildner 
373*5db2f26eSSascha Wildner 	ACPI_SERIAL_ASSERT(pci_link);
374*5db2f26eSSascha Wildner 
375*5db2f26eSSascha Wildner 	/* Invalid interrupts are never valid. */
376*5db2f26eSSascha Wildner 	if (!PCI_INTERRUPT_VALID(irq))
377*5db2f26eSSascha Wildner 		return (FALSE);
378*5db2f26eSSascha Wildner 
379*5db2f26eSSascha Wildner 	/* Any interrupt in the list of possible interrupts is valid. */
380*5db2f26eSSascha Wildner 	for (i = 0; i < link->l_num_irqs; i++)
381*5db2f26eSSascha Wildner 		if (link->l_irqs[i] == irq)
382*5db2f26eSSascha Wildner 			 return (TRUE);
383*5db2f26eSSascha Wildner 
384*5db2f26eSSascha Wildner 	/*
385*5db2f26eSSascha Wildner 	 * For links routed via an ISA interrupt, if the SCI is routed via
386*5db2f26eSSascha Wildner 	 * an ISA interrupt, the SCI is always treated as a valid IRQ.
387*5db2f26eSSascha Wildner 	 */
388*5db2f26eSSascha Wildner 	if (link->l_isa_irq && AcpiGbl_FADT.SciInterrupt == irq &&
389*5db2f26eSSascha Wildner 	    irq < NUM_ISA_INTERRUPTS)
390*5db2f26eSSascha Wildner 		return (TRUE);
391*5db2f26eSSascha Wildner 
392*5db2f26eSSascha Wildner 	/* If the interrupt wasn't found in the list it is not valid. */
393*5db2f26eSSascha Wildner 	return (FALSE);
394*5db2f26eSSascha Wildner }
395*5db2f26eSSascha Wildner 
396*5db2f26eSSascha Wildner static void
397*5db2f26eSSascha Wildner acpi_pci_link_dump(struct acpi_pci_link_softc *sc, int header, const char *tag)
398*5db2f26eSSascha Wildner {
399*5db2f26eSSascha Wildner 	struct link *link;
400*5db2f26eSSascha Wildner 	char buf[16];
401*5db2f26eSSascha Wildner 	int i, j;
402*5db2f26eSSascha Wildner 
403*5db2f26eSSascha Wildner 	ACPI_SERIAL_ASSERT(pci_link);
404*5db2f26eSSascha Wildner 	if (header) {
405*5db2f26eSSascha Wildner 		ksnprintf(buf, sizeof(buf), "%s:",
406*5db2f26eSSascha Wildner 		    device_get_nameunit(sc->pl_dev));
407*5db2f26eSSascha Wildner 		kprintf("%-16.16s  Index  IRQ  Rtd  Ref  IRQs\n", buf);
408*5db2f26eSSascha Wildner 	}
409*5db2f26eSSascha Wildner 	for (i = 0; i < sc->pl_num_links; i++) {
410*5db2f26eSSascha Wildner 		link = &sc->pl_links[i];
411*5db2f26eSSascha Wildner 		kprintf("  %-14.14s  %5d  %3d   %c   %3d ", i == 0 ? tag : "", i,
412*5db2f26eSSascha Wildner 		    link->l_irq, link->l_routed ? 'Y' : 'N',
413*5db2f26eSSascha Wildner 		    link->l_references);
414*5db2f26eSSascha Wildner 		if (link->l_num_irqs == 0)
415*5db2f26eSSascha Wildner 			kprintf(" none");
416*5db2f26eSSascha Wildner 		else for (j = 0; j < link->l_num_irqs; j++)
417*5db2f26eSSascha Wildner 			kprintf(" %d", link->l_irqs[j]);
418*5db2f26eSSascha Wildner 		kprintf("\n");
419*5db2f26eSSascha Wildner 	}
420*5db2f26eSSascha Wildner }
421*5db2f26eSSascha Wildner 
422*5db2f26eSSascha Wildner static int
423*5db2f26eSSascha Wildner acpi_pci_link_attach(device_t dev)
424*5db2f26eSSascha Wildner {
425*5db2f26eSSascha Wildner 	struct acpi_pci_link_softc *sc;
426*5db2f26eSSascha Wildner 	struct link_count_request creq;
427*5db2f26eSSascha Wildner 	struct link_res_request rreq;
428*5db2f26eSSascha Wildner 	ACPI_STATUS status;
429*5db2f26eSSascha Wildner 	int i;
430*5db2f26eSSascha Wildner 
431*5db2f26eSSascha Wildner 	sc = device_get_softc(dev);
432*5db2f26eSSascha Wildner 	sc->pl_dev = dev;
433*5db2f26eSSascha Wildner 	ACPI_SERIAL_INIT(pci_link);
434*5db2f26eSSascha Wildner 	ACPI_SERIAL_BEGIN(pci_link);
435*5db2f26eSSascha Wildner 
436*5db2f26eSSascha Wildner 	/*
437*5db2f26eSSascha Wildner 	 * Count the number of current resources so we know how big of
438*5db2f26eSSascha Wildner 	 * a link array to allocate.  On some systems, _CRS is broken,
439*5db2f26eSSascha Wildner 	 * so for those systems try to derive the count from _PRS instead.
440*5db2f26eSSascha Wildner 	 */
441*5db2f26eSSascha Wildner 	creq.in_dpf = DPF_OUTSIDE;
442*5db2f26eSSascha Wildner 	creq.count = 0;
443*5db2f26eSSascha Wildner 	status = AcpiWalkResources(acpi_get_handle(dev), "_CRS",
444*5db2f26eSSascha Wildner 	    acpi_count_irq_resources, &creq);
445*5db2f26eSSascha Wildner 	sc->pl_crs_bad = ACPI_FAILURE(status);
446*5db2f26eSSascha Wildner 	if (sc->pl_crs_bad) {
447*5db2f26eSSascha Wildner 		creq.in_dpf = DPF_OUTSIDE;
448*5db2f26eSSascha Wildner 		creq.count = 0;
449*5db2f26eSSascha Wildner 		status = AcpiWalkResources(acpi_get_handle(dev), "_PRS",
450*5db2f26eSSascha Wildner 		    acpi_count_irq_resources, &creq);
451*5db2f26eSSascha Wildner 		if (ACPI_FAILURE(status)) {
452*5db2f26eSSascha Wildner 			device_printf(dev,
453*5db2f26eSSascha Wildner 			    "Unable to parse _CRS or _PRS: %s\n",
454*5db2f26eSSascha Wildner 			    AcpiFormatException(status));
455*5db2f26eSSascha Wildner 			ACPI_SERIAL_END(pci_link);
456*5db2f26eSSascha Wildner 			return (ENXIO);
457*5db2f26eSSascha Wildner 		}
458*5db2f26eSSascha Wildner 	}
459*5db2f26eSSascha Wildner 	sc->pl_num_links = creq.count;
460*5db2f26eSSascha Wildner 	if (creq.count == 0) {
461*5db2f26eSSascha Wildner 		ACPI_SERIAL_END(pci_link);
462*5db2f26eSSascha Wildner 		return (0);
463*5db2f26eSSascha Wildner 	}
464*5db2f26eSSascha Wildner 	sc->pl_links = kmalloc(sizeof(struct link) * sc->pl_num_links,
465*5db2f26eSSascha Wildner 	    M_PCI_LINK, M_WAITOK | M_ZERO);
466*5db2f26eSSascha Wildner 
467*5db2f26eSSascha Wildner 	/* Initialize the child links. */
468*5db2f26eSSascha Wildner 	for (i = 0; i < sc->pl_num_links; i++) {
469*5db2f26eSSascha Wildner 		sc->pl_links[i].l_irq = PCI_INVALID_IRQ;
470*5db2f26eSSascha Wildner 		sc->pl_links[i].l_bios_irq = PCI_INVALID_IRQ;
471*5db2f26eSSascha Wildner 		sc->pl_links[i].l_sc = sc;
472*5db2f26eSSascha Wildner 		sc->pl_links[i].l_isa_irq = FALSE;
473*5db2f26eSSascha Wildner 		sc->pl_links[i].l_res_index = -1;
474*5db2f26eSSascha Wildner 	}
475*5db2f26eSSascha Wildner 
476*5db2f26eSSascha Wildner 	/* Try to read the current settings from _CRS if it is valid. */
477*5db2f26eSSascha Wildner 	if (!sc->pl_crs_bad) {
478*5db2f26eSSascha Wildner 		rreq.in_dpf = DPF_OUTSIDE;
479*5db2f26eSSascha Wildner 		rreq.link_index = 0;
480*5db2f26eSSascha Wildner 		rreq.res_index = 0;
481*5db2f26eSSascha Wildner 		rreq.sc = sc;
482*5db2f26eSSascha Wildner 		status = AcpiWalkResources(acpi_get_handle(dev), "_CRS",
483*5db2f26eSSascha Wildner 		    link_add_crs, &rreq);
484*5db2f26eSSascha Wildner 		if (ACPI_FAILURE(status)) {
485*5db2f26eSSascha Wildner 			device_printf(dev, "Unable to parse _CRS: %s\n",
486*5db2f26eSSascha Wildner 			    AcpiFormatException(status));
487*5db2f26eSSascha Wildner 			goto fail;
488*5db2f26eSSascha Wildner 		}
489*5db2f26eSSascha Wildner 	}
490*5db2f26eSSascha Wildner 
491*5db2f26eSSascha Wildner 	/*
492*5db2f26eSSascha Wildner 	 * Try to read the possible settings from _PRS.  Note that if the
493*5db2f26eSSascha Wildner 	 * _CRS is toast, we depend on having a working _PRS.  However, if
494*5db2f26eSSascha Wildner 	 * _CRS works, then it is ok for _PRS to be missing.
495*5db2f26eSSascha Wildner 	 */
496*5db2f26eSSascha Wildner 	rreq.in_dpf = DPF_OUTSIDE;
497*5db2f26eSSascha Wildner 	rreq.link_index = 0;
498*5db2f26eSSascha Wildner 	rreq.res_index = 0;
499*5db2f26eSSascha Wildner 	rreq.sc = sc;
500*5db2f26eSSascha Wildner 	status = AcpiWalkResources(acpi_get_handle(dev), "_PRS",
501*5db2f26eSSascha Wildner 	    link_add_prs, &rreq);
502*5db2f26eSSascha Wildner 	if (ACPI_FAILURE(status) &&
503*5db2f26eSSascha Wildner 	    (status != AE_NOT_FOUND || sc->pl_crs_bad)) {
504*5db2f26eSSascha Wildner 		device_printf(dev, "Unable to parse _PRS: %s\n",
505*5db2f26eSSascha Wildner 		    AcpiFormatException(status));
506*5db2f26eSSascha Wildner 		goto fail;
507*5db2f26eSSascha Wildner 	}
508*5db2f26eSSascha Wildner 	if (bootverbose)
509*5db2f26eSSascha Wildner 		acpi_pci_link_dump(sc, 1, "Initial Probe");
510*5db2f26eSSascha Wildner 
511*5db2f26eSSascha Wildner 	/* Verify initial IRQs if we have _PRS. */
512*5db2f26eSSascha Wildner 	if (status != AE_NOT_FOUND)
513*5db2f26eSSascha Wildner 		for (i = 0; i < sc->pl_num_links; i++)
514*5db2f26eSSascha Wildner 			if (!link_valid_irq(&sc->pl_links[i],
515*5db2f26eSSascha Wildner 			    sc->pl_links[i].l_irq))
516*5db2f26eSSascha Wildner 				sc->pl_links[i].l_irq = PCI_INVALID_IRQ;
517*5db2f26eSSascha Wildner 	if (bootverbose)
518*5db2f26eSSascha Wildner 		acpi_pci_link_dump(sc, 0, "Validation");
519*5db2f26eSSascha Wildner 
520*5db2f26eSSascha Wildner 	/* Save initial IRQs. */
521*5db2f26eSSascha Wildner 	for (i = 0; i < sc->pl_num_links; i++)
522*5db2f26eSSascha Wildner 		sc->pl_links[i].l_initial_irq = sc->pl_links[i].l_irq;
523*5db2f26eSSascha Wildner 
524*5db2f26eSSascha Wildner 	/*
525*5db2f26eSSascha Wildner 	 * Try to disable this link.  If successful, set the current IRQ to
526*5db2f26eSSascha Wildner 	 * zero and flags to indicate this link is not routed.  If we can't
527*5db2f26eSSascha Wildner 	 * run _DIS (i.e., the method doesn't exist), assume the initial
528*5db2f26eSSascha Wildner 	 * IRQ was routed by the BIOS.
529*5db2f26eSSascha Wildner 	 */
530*5db2f26eSSascha Wildner 	if (ACPI_SUCCESS(AcpiEvaluateObject(acpi_get_handle(dev), "_DIS", NULL,
531*5db2f26eSSascha Wildner 	    NULL)))
532*5db2f26eSSascha Wildner 		for (i = 0; i < sc->pl_num_links; i++)
533*5db2f26eSSascha Wildner 			sc->pl_links[i].l_irq = PCI_INVALID_IRQ;
534*5db2f26eSSascha Wildner 	else
535*5db2f26eSSascha Wildner 		for (i = 0; i < sc->pl_num_links; i++)
536*5db2f26eSSascha Wildner 			if (PCI_INTERRUPT_VALID(sc->pl_links[i].l_irq))
537*5db2f26eSSascha Wildner 				sc->pl_links[i].l_routed = TRUE;
538*5db2f26eSSascha Wildner 	if (bootverbose)
539*5db2f26eSSascha Wildner 		acpi_pci_link_dump(sc, 0, "After Disable");
540*5db2f26eSSascha Wildner 	ACPI_SERIAL_END(pci_link);
541*5db2f26eSSascha Wildner 	return (0);
542*5db2f26eSSascha Wildner fail:
543*5db2f26eSSascha Wildner 	ACPI_SERIAL_END(pci_link);
544*5db2f26eSSascha Wildner 	for (i = 0; i < sc->pl_num_links; i++)
545*5db2f26eSSascha Wildner 		if (sc->pl_links[i].l_irqs != NULL)
546*5db2f26eSSascha Wildner 			kfree(sc->pl_links[i].l_irqs, M_PCI_LINK);
547*5db2f26eSSascha Wildner 	kfree(sc->pl_links, M_PCI_LINK);
548*5db2f26eSSascha Wildner 	return (ENXIO);
549*5db2f26eSSascha Wildner }
550*5db2f26eSSascha Wildner 
551*5db2f26eSSascha Wildner /* XXX: Note that this is identical to pci_pir_search_irq(). */
552*5db2f26eSSascha Wildner static uint8_t
553*5db2f26eSSascha Wildner acpi_pci_link_search_irq(int bus, int device, int pin)
554*5db2f26eSSascha Wildner {
555*5db2f26eSSascha Wildner 	uint32_t value;
556*5db2f26eSSascha Wildner 	uint8_t func, maxfunc;
557*5db2f26eSSascha Wildner 
558*5db2f26eSSascha Wildner 	/* See if we have a valid device at function 0. */
559*5db2f26eSSascha Wildner 	value = pci_cfgregread(bus, device, 0, PCIR_HDRTYPE, 1);
560*5db2f26eSSascha Wildner 	if ((value & PCIM_HDRTYPE) > PCI_MAXHDRTYPE)
561*5db2f26eSSascha Wildner 		return (PCI_INVALID_IRQ);
562*5db2f26eSSascha Wildner 	if (value & PCIM_MFDEV)
563*5db2f26eSSascha Wildner 		maxfunc = PCI_FUNCMAX;
564*5db2f26eSSascha Wildner 	else
565*5db2f26eSSascha Wildner 		maxfunc = 0;
566*5db2f26eSSascha Wildner 
567*5db2f26eSSascha Wildner 	/* Scan all possible functions at this device. */
568*5db2f26eSSascha Wildner 	for (func = 0; func <= maxfunc; func++) {
569*5db2f26eSSascha Wildner 		value = pci_cfgregread(bus, device, func, PCIR_DEVVENDOR, 4);
570*5db2f26eSSascha Wildner 		if (value == 0xffffffff)
571*5db2f26eSSascha Wildner 			continue;
572*5db2f26eSSascha Wildner 		value = pci_cfgregread(bus, device, func, PCIR_INTPIN, 1);
573*5db2f26eSSascha Wildner 
574*5db2f26eSSascha Wildner 		/*
575*5db2f26eSSascha Wildner 		 * See if it uses the pin in question.  Note that the passed
576*5db2f26eSSascha Wildner 		 * in pin uses 0 for A, .. 3 for D whereas the intpin
577*5db2f26eSSascha Wildner 		 * register uses 0 for no interrupt, 1 for A, .. 4 for D.
578*5db2f26eSSascha Wildner 		 */
579*5db2f26eSSascha Wildner 		if (value != pin + 1)
580*5db2f26eSSascha Wildner 			continue;
581*5db2f26eSSascha Wildner 		value = pci_cfgregread(bus, device, func, PCIR_INTLINE, 1);
582*5db2f26eSSascha Wildner 		if (bootverbose)
583*5db2f26eSSascha Wildner 			kprintf(
584*5db2f26eSSascha Wildner 		"ACPI: Found matching pin for %d.%d.INT%c at func %d: %d\n",
585*5db2f26eSSascha Wildner 			    bus, device, pin + 'A', func, value);
586*5db2f26eSSascha Wildner 		if (value != PCI_INVALID_IRQ)
587*5db2f26eSSascha Wildner 			return (value);
588*5db2f26eSSascha Wildner 	}
589*5db2f26eSSascha Wildner 	return (PCI_INVALID_IRQ);
590*5db2f26eSSascha Wildner }
591*5db2f26eSSascha Wildner 
592*5db2f26eSSascha Wildner /*
593*5db2f26eSSascha Wildner  * Find the link structure that corresponds to the resource index passed in
594*5db2f26eSSascha Wildner  * via 'source_index'.
595*5db2f26eSSascha Wildner  */
596*5db2f26eSSascha Wildner static struct link *
597*5db2f26eSSascha Wildner acpi_pci_link_lookup(device_t dev, int source_index)
598*5db2f26eSSascha Wildner {
599*5db2f26eSSascha Wildner 	struct acpi_pci_link_softc *sc;
600*5db2f26eSSascha Wildner 	int i;
601*5db2f26eSSascha Wildner 
602*5db2f26eSSascha Wildner 	ACPI_SERIAL_ASSERT(pci_link);
603*5db2f26eSSascha Wildner 	sc = device_get_softc(dev);
604*5db2f26eSSascha Wildner 	for (i = 0; i < sc->pl_num_links; i++)
605*5db2f26eSSascha Wildner 		if (sc->pl_links[i].l_res_index == source_index)
606*5db2f26eSSascha Wildner 			return (&sc->pl_links[i]);
607*5db2f26eSSascha Wildner 	return (NULL);
608*5db2f26eSSascha Wildner }
609*5db2f26eSSascha Wildner 
610*5db2f26eSSascha Wildner void
611*5db2f26eSSascha Wildner acpi_pci_link_add_reference(device_t dev, int index, device_t pcib, int slot,
612*5db2f26eSSascha Wildner     int pin)
613*5db2f26eSSascha Wildner {
614*5db2f26eSSascha Wildner 	struct link *link;
615*5db2f26eSSascha Wildner 	uint8_t bios_irq;
616*5db2f26eSSascha Wildner 	uintptr_t bus;
617*5db2f26eSSascha Wildner 
618*5db2f26eSSascha Wildner 	/*
619*5db2f26eSSascha Wildner 	 * Look up the PCI bus for the specified PCI bridge device.  Note
620*5db2f26eSSascha Wildner 	 * that the PCI bridge device might not have any children yet.
621*5db2f26eSSascha Wildner 	 * However, looking up its bus number doesn't require a valid child
622*5db2f26eSSascha Wildner 	 * device, so we just pass NULL.
623*5db2f26eSSascha Wildner 	 */
624*5db2f26eSSascha Wildner 	if (BUS_READ_IVAR(pcib, NULL, PCIB_IVAR_BUS, &bus) != 0) {
625*5db2f26eSSascha Wildner 		device_printf(pcib, "Unable to read PCI bus number");
626*5db2f26eSSascha Wildner 		panic("PCI bridge without a bus number");
627*5db2f26eSSascha Wildner 	}
628*5db2f26eSSascha Wildner 
629*5db2f26eSSascha Wildner 	/* Bump the reference count. */
630*5db2f26eSSascha Wildner 	ACPI_SERIAL_BEGIN(pci_link);
631*5db2f26eSSascha Wildner 	link = acpi_pci_link_lookup(dev, index);
632*5db2f26eSSascha Wildner 	if (link == NULL) {
633*5db2f26eSSascha Wildner 		device_printf(dev, "apparently invalid index %d\n", index);
634*5db2f26eSSascha Wildner 		ACPI_SERIAL_END(pci_link);
635*5db2f26eSSascha Wildner 		return;
636*5db2f26eSSascha Wildner 	}
637*5db2f26eSSascha Wildner 	link->l_references++;
638*5db2f26eSSascha Wildner 	if (link->l_routed)
639*5db2f26eSSascha Wildner 		pci_link_interrupt_weights[link->l_irq]++;
640*5db2f26eSSascha Wildner 
641*5db2f26eSSascha Wildner 	/*
642*5db2f26eSSascha Wildner 	 * The BIOS only routes interrupts via ISA IRQs using the ATPICs
643*5db2f26eSSascha Wildner 	 * (8259As).  Thus, if this link is routed via an ISA IRQ, go
644*5db2f26eSSascha Wildner 	 * look to see if the BIOS routed an IRQ for this link at the
645*5db2f26eSSascha Wildner 	 * indicated (bus, slot, pin).  If so, we prefer that IRQ for
646*5db2f26eSSascha Wildner 	 * this link and add that IRQ to our list of known-good IRQs.
647*5db2f26eSSascha Wildner 	 * This provides a good work-around for link devices whose _CRS
648*5db2f26eSSascha Wildner 	 * method is either broken or bogus.  We only use the value
649*5db2f26eSSascha Wildner 	 * returned by _CRS if we can't find a valid IRQ via this method
650*5db2f26eSSascha Wildner 	 * in fact.
651*5db2f26eSSascha Wildner 	 *
652*5db2f26eSSascha Wildner 	 * If this link is not routed via an ISA IRQ (because we are using
653*5db2f26eSSascha Wildner 	 * APIC for example), then don't bother looking up the BIOS IRQ
654*5db2f26eSSascha Wildner 	 * as if we find one it won't be valid anyway.
655*5db2f26eSSascha Wildner 	 */
656*5db2f26eSSascha Wildner 	if (!link->l_isa_irq) {
657*5db2f26eSSascha Wildner 		ACPI_SERIAL_END(pci_link);
658*5db2f26eSSascha Wildner 		return;
659*5db2f26eSSascha Wildner 	}
660*5db2f26eSSascha Wildner 
661*5db2f26eSSascha Wildner 	/* Try to find a BIOS IRQ setting from any matching devices. */
662*5db2f26eSSascha Wildner 	bios_irq = acpi_pci_link_search_irq(bus, slot, pin);
663*5db2f26eSSascha Wildner 	if (!PCI_INTERRUPT_VALID(bios_irq)) {
664*5db2f26eSSascha Wildner 		ACPI_SERIAL_END(pci_link);
665*5db2f26eSSascha Wildner 		return;
666*5db2f26eSSascha Wildner 	}
667*5db2f26eSSascha Wildner 
668*5db2f26eSSascha Wildner 	/* Validate the BIOS IRQ. */
669*5db2f26eSSascha Wildner 	if (!link_valid_irq(link, bios_irq)) {
670*5db2f26eSSascha Wildner 		device_printf(dev, "BIOS IRQ %u for %d.%d.INT%c is invalid\n",
671*5db2f26eSSascha Wildner 		    bios_irq, (int)bus, slot, pin + 'A');
672*5db2f26eSSascha Wildner 	} else if (!PCI_INTERRUPT_VALID(link->l_bios_irq)) {
673*5db2f26eSSascha Wildner 		link->l_bios_irq = bios_irq;
674*5db2f26eSSascha Wildner 		/*
675*5db2f26eSSascha Wildner 		 * SCI setting is handled by acpi_pci_link_identify()
676*5db2f26eSSascha Wildner 		 */
677*5db2f26eSSascha Wildner 		if (bios_irq < NUM_ISA_INTERRUPTS &&
678*5db2f26eSSascha Wildner 		    AcpiGbl_FADT.SciInterrupt != bios_irq)
679*5db2f26eSSascha Wildner 			pci_link_bios_isa_irqs |= (1 << bios_irq);
680*5db2f26eSSascha Wildner 		if (bios_irq != link->l_initial_irq &&
681*5db2f26eSSascha Wildner 		    PCI_INTERRUPT_VALID(link->l_initial_irq))
682*5db2f26eSSascha Wildner 			device_printf(dev,
683*5db2f26eSSascha Wildner 			    "BIOS IRQ %u does not match initial IRQ %u\n",
684*5db2f26eSSascha Wildner 			    bios_irq, link->l_initial_irq);
685*5db2f26eSSascha Wildner 	} else if (bios_irq != link->l_bios_irq)
686*5db2f26eSSascha Wildner 		device_printf(dev,
687*5db2f26eSSascha Wildner 	    "BIOS IRQ %u for %d.%d.INT%c does not match previous BIOS IRQ %u\n",
688*5db2f26eSSascha Wildner 		    bios_irq, (int)bus, slot, pin + 'A',
689*5db2f26eSSascha Wildner 		    link->l_bios_irq);
690*5db2f26eSSascha Wildner 	ACPI_SERIAL_END(pci_link);
691*5db2f26eSSascha Wildner }
692*5db2f26eSSascha Wildner 
693*5db2f26eSSascha Wildner static ACPI_STATUS
694*5db2f26eSSascha Wildner acpi_pci_link_srs_from_crs(struct acpi_pci_link_softc *sc, ACPI_BUFFER *srsbuf)
695*5db2f26eSSascha Wildner {
696*5db2f26eSSascha Wildner 	ACPI_RESOURCE *resource, *end, newres, *resptr;
697*5db2f26eSSascha Wildner 	ACPI_BUFFER crsbuf;
698*5db2f26eSSascha Wildner 	ACPI_STATUS status;
699*5db2f26eSSascha Wildner 	struct link *link;
700*5db2f26eSSascha Wildner 	int i, in_dpf;
701*5db2f26eSSascha Wildner 
702*5db2f26eSSascha Wildner 	/* Fetch the _CRS. */
703*5db2f26eSSascha Wildner 	ACPI_SERIAL_ASSERT(pci_link);
704*5db2f26eSSascha Wildner 	crsbuf.Pointer = NULL;
705*5db2f26eSSascha Wildner 	crsbuf.Length = ACPI_ALLOCATE_BUFFER;
706*5db2f26eSSascha Wildner 	status = AcpiGetCurrentResources(acpi_get_handle(sc->pl_dev), &crsbuf);
707*5db2f26eSSascha Wildner 	if (ACPI_SUCCESS(status) && crsbuf.Pointer == NULL)
708*5db2f26eSSascha Wildner 		status = AE_NO_MEMORY;
709*5db2f26eSSascha Wildner 	if (ACPI_FAILURE(status)) {
710*5db2f26eSSascha Wildner 		if (bootverbose)
711*5db2f26eSSascha Wildner 			device_printf(sc->pl_dev,
712*5db2f26eSSascha Wildner 			    "Unable to fetch current resources: %s\n",
713*5db2f26eSSascha Wildner 			    AcpiFormatException(status));
714*5db2f26eSSascha Wildner 		return (status);
715*5db2f26eSSascha Wildner 	}
716*5db2f26eSSascha Wildner 
717*5db2f26eSSascha Wildner 	/* Fill in IRQ resources via link structures. */
718*5db2f26eSSascha Wildner 	srsbuf->Pointer = NULL;
719*5db2f26eSSascha Wildner 	link = sc->pl_links;
720*5db2f26eSSascha Wildner 	i = 0;
721*5db2f26eSSascha Wildner 	in_dpf = DPF_OUTSIDE;
722*5db2f26eSSascha Wildner 	resource = (ACPI_RESOURCE *)crsbuf.Pointer;
723*5db2f26eSSascha Wildner 	end = (ACPI_RESOURCE *)((char *)crsbuf.Pointer + crsbuf.Length);
724*5db2f26eSSascha Wildner 	for (;;) {
725*5db2f26eSSascha Wildner 		switch (resource->Type) {
726*5db2f26eSSascha Wildner 		case ACPI_RESOURCE_TYPE_START_DEPENDENT:
727*5db2f26eSSascha Wildner 			switch (in_dpf) {
728*5db2f26eSSascha Wildner 			case DPF_OUTSIDE:
729*5db2f26eSSascha Wildner 				/* We've started the first DPF. */
730*5db2f26eSSascha Wildner 				in_dpf = DPF_FIRST;
731*5db2f26eSSascha Wildner 				break;
732*5db2f26eSSascha Wildner 			case DPF_FIRST:
733*5db2f26eSSascha Wildner 				/* We've started the second DPF. */
734*5db2f26eSSascha Wildner 				panic(
735*5db2f26eSSascha Wildner 		"%s: Multiple dependent functions within a current resource",
736*5db2f26eSSascha Wildner 				    __func__);
737*5db2f26eSSascha Wildner 				break;
738*5db2f26eSSascha Wildner 			}
739*5db2f26eSSascha Wildner 			resptr = NULL;
740*5db2f26eSSascha Wildner 			break;
741*5db2f26eSSascha Wildner 		case ACPI_RESOURCE_TYPE_END_DEPENDENT:
742*5db2f26eSSascha Wildner 			/* We are finished with DPF parsing. */
743*5db2f26eSSascha Wildner 			KASSERT(in_dpf != DPF_OUTSIDE,
744*5db2f26eSSascha Wildner 			    ("%s: end dpf when not parsing a dpf", __func__));
745*5db2f26eSSascha Wildner 			in_dpf = DPF_OUTSIDE;
746*5db2f26eSSascha Wildner 			resptr = NULL;
747*5db2f26eSSascha Wildner 			break;
748*5db2f26eSSascha Wildner 		case ACPI_RESOURCE_TYPE_IRQ:
749*5db2f26eSSascha Wildner 			KKASSERT(i < sc->pl_num_links);
750*5db2f26eSSascha Wildner 			KKASSERT(link->l_prs_template.Type == ACPI_RESOURCE_TYPE_IRQ);
751*5db2f26eSSascha Wildner 			newres = link->l_prs_template;
752*5db2f26eSSascha Wildner 			resptr = &newres;
753*5db2f26eSSascha Wildner 			resptr->Data.Irq.InterruptCount = 1;
754*5db2f26eSSascha Wildner 			if (PCI_INTERRUPT_VALID(link->l_irq)) {
755*5db2f26eSSascha Wildner 				KASSERT(link->l_irq < NUM_ISA_INTERRUPTS,
756*5db2f26eSSascha Wildner 		("%s: can't put non-ISA IRQ %d in legacy IRQ resource type",
757*5db2f26eSSascha Wildner 				    __func__, link->l_irq));
758*5db2f26eSSascha Wildner 				resptr->Data.Irq.Interrupts[0] = link->l_irq;
759*5db2f26eSSascha Wildner 			} else
760*5db2f26eSSascha Wildner 				resptr->Data.Irq.Interrupts[0] = 0;
761*5db2f26eSSascha Wildner 			link++;
762*5db2f26eSSascha Wildner 			i++;
763*5db2f26eSSascha Wildner 			break;
764*5db2f26eSSascha Wildner 		case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
765*5db2f26eSSascha Wildner 			KKASSERT(i < sc->pl_num_links);
766*5db2f26eSSascha Wildner 			KKASSERT(link->l_prs_template.Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ);
767*5db2f26eSSascha Wildner 			newres = link->l_prs_template;
768*5db2f26eSSascha Wildner 			resptr = &newres;
769*5db2f26eSSascha Wildner 			resptr->Data.ExtendedIrq.InterruptCount = 1;
770*5db2f26eSSascha Wildner 			if (PCI_INTERRUPT_VALID(link->l_irq))
771*5db2f26eSSascha Wildner 				resptr->Data.ExtendedIrq.Interrupts[0] =
772*5db2f26eSSascha Wildner 				    link->l_irq;
773*5db2f26eSSascha Wildner 			else
774*5db2f26eSSascha Wildner 				resptr->Data.ExtendedIrq.Interrupts[0] = 0;
775*5db2f26eSSascha Wildner 			link++;
776*5db2f26eSSascha Wildner 			i++;
777*5db2f26eSSascha Wildner 			break;
778*5db2f26eSSascha Wildner 		default:
779*5db2f26eSSascha Wildner 			resptr = resource;
780*5db2f26eSSascha Wildner 		}
781*5db2f26eSSascha Wildner 		if (resptr != NULL) {
782*5db2f26eSSascha Wildner 			status = acpi_AppendBufferResource(srsbuf, resptr);
783*5db2f26eSSascha Wildner 			if (ACPI_FAILURE(status)) {
784*5db2f26eSSascha Wildner 				device_printf(sc->pl_dev,
785*5db2f26eSSascha Wildner 				    "Unable to build resources: %s\n",
786*5db2f26eSSascha Wildner 				    AcpiFormatException(status));
787*5db2f26eSSascha Wildner 				if (srsbuf->Pointer != NULL)
788*5db2f26eSSascha Wildner 					AcpiOsFree(srsbuf->Pointer);
789*5db2f26eSSascha Wildner 				AcpiOsFree(crsbuf.Pointer);
790*5db2f26eSSascha Wildner 				return (status);
791*5db2f26eSSascha Wildner 			}
792*5db2f26eSSascha Wildner 		}
793*5db2f26eSSascha Wildner 		if (resource->Type == ACPI_RESOURCE_TYPE_END_TAG)
794*5db2f26eSSascha Wildner 			break;
795*5db2f26eSSascha Wildner 		resource = ACPI_NEXT_RESOURCE(resource);
796*5db2f26eSSascha Wildner 		if (resource >= end)
797*5db2f26eSSascha Wildner 			break;
798*5db2f26eSSascha Wildner 	}
799*5db2f26eSSascha Wildner 	AcpiOsFree(crsbuf.Pointer);
800*5db2f26eSSascha Wildner 	return (AE_OK);
801*5db2f26eSSascha Wildner }
802*5db2f26eSSascha Wildner 
803*5db2f26eSSascha Wildner static ACPI_STATUS
804*5db2f26eSSascha Wildner acpi_pci_link_srs_from_links(struct acpi_pci_link_softc *sc,
805*5db2f26eSSascha Wildner     ACPI_BUFFER *srsbuf)
806*5db2f26eSSascha Wildner {
807*5db2f26eSSascha Wildner 	ACPI_RESOURCE newres;
808*5db2f26eSSascha Wildner 	ACPI_STATUS status;
809*5db2f26eSSascha Wildner 	struct link *link;
810*5db2f26eSSascha Wildner 	int i;
811*5db2f26eSSascha Wildner 
812*5db2f26eSSascha Wildner 	/* Start off with an empty buffer. */
813*5db2f26eSSascha Wildner 	srsbuf->Pointer = NULL;
814*5db2f26eSSascha Wildner 	link = sc->pl_links;
815*5db2f26eSSascha Wildner 	for (i = 0; i < sc->pl_num_links; i++) {
816*5db2f26eSSascha Wildner 
817*5db2f26eSSascha Wildner 		/* Add a new IRQ resource from each link. */
818*5db2f26eSSascha Wildner 		link = &sc->pl_links[i];
819*5db2f26eSSascha Wildner 		newres = link->l_prs_template;
820*5db2f26eSSascha Wildner 		if (newres.Type == ACPI_RESOURCE_TYPE_IRQ) {
821*5db2f26eSSascha Wildner 
822*5db2f26eSSascha Wildner 			/* Build an IRQ resource. */
823*5db2f26eSSascha Wildner 			newres.Data.Irq.InterruptCount = 1;
824*5db2f26eSSascha Wildner 			if (PCI_INTERRUPT_VALID(link->l_irq)) {
825*5db2f26eSSascha Wildner 				KASSERT(link->l_irq < NUM_ISA_INTERRUPTS,
826*5db2f26eSSascha Wildner 		("%s: can't put non-ISA IRQ %d in legacy IRQ resource type",
827*5db2f26eSSascha Wildner 				    __func__, link->l_irq));
828*5db2f26eSSascha Wildner 				newres.Data.Irq.Interrupts[0] = link->l_irq;
829*5db2f26eSSascha Wildner 			} else
830*5db2f26eSSascha Wildner 				newres.Data.Irq.Interrupts[0] = 0;
831*5db2f26eSSascha Wildner 		} else {
832*5db2f26eSSascha Wildner 
833*5db2f26eSSascha Wildner 			/* Build an ExtIRQ resuorce. */
834*5db2f26eSSascha Wildner 			newres.Data.ExtendedIrq.InterruptCount = 1;
835*5db2f26eSSascha Wildner 			if (PCI_INTERRUPT_VALID(link->l_irq))
836*5db2f26eSSascha Wildner 				newres.Data.ExtendedIrq.Interrupts[0] =
837*5db2f26eSSascha Wildner 				    link->l_irq;
838*5db2f26eSSascha Wildner 			else
839*5db2f26eSSascha Wildner 				newres.Data.ExtendedIrq.Interrupts[0] = 0;
840*5db2f26eSSascha Wildner 		}
841*5db2f26eSSascha Wildner 
842*5db2f26eSSascha Wildner 		/* Add the new resource to the end of the _SRS buffer. */
843*5db2f26eSSascha Wildner 		status = acpi_AppendBufferResource(srsbuf, &newres);
844*5db2f26eSSascha Wildner 		if (ACPI_FAILURE(status)) {
845*5db2f26eSSascha Wildner 			device_printf(sc->pl_dev,
846*5db2f26eSSascha Wildner 			    "Unable to build resources: %s\n",
847*5db2f26eSSascha Wildner 			    AcpiFormatException(status));
848*5db2f26eSSascha Wildner 			if (srsbuf->Pointer != NULL)
849*5db2f26eSSascha Wildner 				AcpiOsFree(srsbuf->Pointer);
850*5db2f26eSSascha Wildner 			return (status);
851*5db2f26eSSascha Wildner 		}
852*5db2f26eSSascha Wildner 	}
853*5db2f26eSSascha Wildner 	return (AE_OK);
854*5db2f26eSSascha Wildner }
855*5db2f26eSSascha Wildner 
856*5db2f26eSSascha Wildner static ACPI_STATUS
857*5db2f26eSSascha Wildner acpi_pci_link_route_irqs(device_t dev)
858*5db2f26eSSascha Wildner {
859*5db2f26eSSascha Wildner 	struct acpi_pci_link_softc *sc;
860*5db2f26eSSascha Wildner 	ACPI_RESOURCE *resource, *end;
861*5db2f26eSSascha Wildner 	ACPI_BUFFER srsbuf;
862*5db2f26eSSascha Wildner 	ACPI_STATUS status;
863*5db2f26eSSascha Wildner 	struct link *link;
864*5db2f26eSSascha Wildner 	int i;
865*5db2f26eSSascha Wildner 
866*5db2f26eSSascha Wildner 	ACPI_SERIAL_ASSERT(pci_link);
867*5db2f26eSSascha Wildner 	sc = device_get_softc(dev);
868*5db2f26eSSascha Wildner 	if (sc->pl_crs_bad)
869*5db2f26eSSascha Wildner 		status = acpi_pci_link_srs_from_links(sc, &srsbuf);
870*5db2f26eSSascha Wildner 	else
871*5db2f26eSSascha Wildner 		status = acpi_pci_link_srs_from_crs(sc, &srsbuf);
872*5db2f26eSSascha Wildner 
873*5db2f26eSSascha Wildner 	/* Write out new resources via _SRS. */
874*5db2f26eSSascha Wildner 	status = AcpiSetCurrentResources(acpi_get_handle(dev), &srsbuf);
875*5db2f26eSSascha Wildner 	if (ACPI_FAILURE(status)) {
876*5db2f26eSSascha Wildner 		device_printf(dev, "Unable to route IRQs: %s\n",
877*5db2f26eSSascha Wildner 		    AcpiFormatException(status));
878*5db2f26eSSascha Wildner 		AcpiOsFree(srsbuf.Pointer);
879*5db2f26eSSascha Wildner 		return (status);
880*5db2f26eSSascha Wildner 	}
881*5db2f26eSSascha Wildner 
882*5db2f26eSSascha Wildner 	/*
883*5db2f26eSSascha Wildner 	 * Perform acpi_config_intr() on each IRQ resource if it was just
884*5db2f26eSSascha Wildner 	 * routed for the first time.
885*5db2f26eSSascha Wildner 	 */
886*5db2f26eSSascha Wildner 	link = sc->pl_links;
887*5db2f26eSSascha Wildner 	i = 0;
888*5db2f26eSSascha Wildner 	resource = (ACPI_RESOURCE *)srsbuf.Pointer;
889*5db2f26eSSascha Wildner 	end = (ACPI_RESOURCE *)((char *)srsbuf.Pointer + srsbuf.Length);
890*5db2f26eSSascha Wildner 	for (;;) {
891*5db2f26eSSascha Wildner 		if (resource->Type == ACPI_RESOURCE_TYPE_END_TAG)
892*5db2f26eSSascha Wildner 			break;
893*5db2f26eSSascha Wildner 		switch (resource->Type) {
894*5db2f26eSSascha Wildner 		case ACPI_RESOURCE_TYPE_IRQ:
895*5db2f26eSSascha Wildner 		case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
896*5db2f26eSSascha Wildner 			KKASSERT(i < sc->pl_num_links);
897*5db2f26eSSascha Wildner 
898*5db2f26eSSascha Wildner 			/*
899*5db2f26eSSascha Wildner 			 * Only configure the interrupt and update the
900*5db2f26eSSascha Wildner 			 * weights if this link has a valid IRQ and was
901*5db2f26eSSascha Wildner 			 * previously unrouted.
902*5db2f26eSSascha Wildner 			 */
903*5db2f26eSSascha Wildner 			if (!link->l_routed &&
904*5db2f26eSSascha Wildner 			    PCI_INTERRUPT_VALID(link->l_irq)) {
905*5db2f26eSSascha Wildner 				link->l_routed = TRUE;
906*5db2f26eSSascha Wildner 				acpi_config_intr(dev, resource);
907*5db2f26eSSascha Wildner 				pci_link_interrupt_weights[link->l_irq] +=
908*5db2f26eSSascha Wildner 				    link->l_references;
909*5db2f26eSSascha Wildner 			}
910*5db2f26eSSascha Wildner 			link++;
911*5db2f26eSSascha Wildner 			i++;
912*5db2f26eSSascha Wildner 			break;
913*5db2f26eSSascha Wildner 		}
914*5db2f26eSSascha Wildner 		resource = ACPI_NEXT_RESOURCE(resource);
915*5db2f26eSSascha Wildner 		if (resource >= end)
916*5db2f26eSSascha Wildner 			break;
917*5db2f26eSSascha Wildner 	}
918*5db2f26eSSascha Wildner 	AcpiOsFree(srsbuf.Pointer);
919*5db2f26eSSascha Wildner 	return (AE_OK);
920*5db2f26eSSascha Wildner }
921*5db2f26eSSascha Wildner 
922*5db2f26eSSascha Wildner static int
923*5db2f26eSSascha Wildner acpi_pci_link_resume(device_t dev)
924*5db2f26eSSascha Wildner {
925*5db2f26eSSascha Wildner 	struct acpi_pci_link_softc *sc;
926*5db2f26eSSascha Wildner 	ACPI_STATUS status;
927*5db2f26eSSascha Wildner 	int i, routed;
928*5db2f26eSSascha Wildner 
929*5db2f26eSSascha Wildner 	/*
930*5db2f26eSSascha Wildner 	 * If all of our links are routed, then restore the link via _SRS,
931*5db2f26eSSascha Wildner 	 * otherwise, disable the link via _DIS.
932*5db2f26eSSascha Wildner 	 */
933*5db2f26eSSascha Wildner 	ACPI_SERIAL_BEGIN(pci_link);
934*5db2f26eSSascha Wildner 	sc = device_get_softc(dev);
935*5db2f26eSSascha Wildner 	routed = 0;
936*5db2f26eSSascha Wildner 	for (i = 0; i < sc->pl_num_links; i++)
937*5db2f26eSSascha Wildner 		if (sc->pl_links[i].l_routed)
938*5db2f26eSSascha Wildner 			routed++;
939*5db2f26eSSascha Wildner 	if (routed == sc->pl_num_links)
940*5db2f26eSSascha Wildner 		status = acpi_pci_link_route_irqs(dev);
941*5db2f26eSSascha Wildner 	else {
942*5db2f26eSSascha Wildner 		AcpiEvaluateObject(acpi_get_handle(dev), "_DIS", NULL, NULL);
943*5db2f26eSSascha Wildner 		status = AE_OK;
944*5db2f26eSSascha Wildner 	}
945*5db2f26eSSascha Wildner 	ACPI_SERIAL_END(pci_link);
946*5db2f26eSSascha Wildner 	if (ACPI_FAILURE(status))
947*5db2f26eSSascha Wildner 		return (ENXIO);
948*5db2f26eSSascha Wildner 	else
949*5db2f26eSSascha Wildner 		return (0);
950*5db2f26eSSascha Wildner }
951*5db2f26eSSascha Wildner 
952*5db2f26eSSascha Wildner /*
953*5db2f26eSSascha Wildner  * Pick an IRQ to use for this unrouted link.
954*5db2f26eSSascha Wildner  */
955*5db2f26eSSascha Wildner static uint8_t
956*5db2f26eSSascha Wildner acpi_pci_link_choose_irq(device_t dev, struct link *link)
957*5db2f26eSSascha Wildner {
958*5db2f26eSSascha Wildner 	char tunable_buffer[64], link_name[5];
959*5db2f26eSSascha Wildner 	u_int8_t best_irq, pos_irq;
960*5db2f26eSSascha Wildner 	int best_weight, pos_weight, i;
961*5db2f26eSSascha Wildner 
962*5db2f26eSSascha Wildner 	KASSERT(!link->l_routed, ("%s: link already routed", __func__));
963*5db2f26eSSascha Wildner 	KASSERT(!PCI_INTERRUPT_VALID(link->l_irq),
964*5db2f26eSSascha Wildner 	    ("%s: link already has an IRQ", __func__));
965*5db2f26eSSascha Wildner 
966*5db2f26eSSascha Wildner 	/* Check for a tunable override. */
967*5db2f26eSSascha Wildner 	if (ACPI_SUCCESS(acpi_short_name(acpi_get_handle(dev), link_name,
968*5db2f26eSSascha Wildner 	    sizeof(link_name)))) {
969*5db2f26eSSascha Wildner 		ksnprintf(tunable_buffer, sizeof(tunable_buffer),
970*5db2f26eSSascha Wildner 		    "hw.pci.link.%s.%d.irq", link_name, link->l_res_index);
971*5db2f26eSSascha Wildner 		if (kgetenv_int(tunable_buffer, &i) && PCI_INTERRUPT_VALID(i)) {
972*5db2f26eSSascha Wildner 			if (!link_valid_irq(link, i))
973*5db2f26eSSascha Wildner 				device_printf(dev,
974*5db2f26eSSascha Wildner 				    "Warning, IRQ %d is not listed as valid\n",
975*5db2f26eSSascha Wildner 				    i);
976*5db2f26eSSascha Wildner 			return (i);
977*5db2f26eSSascha Wildner 		}
978*5db2f26eSSascha Wildner 		ksnprintf(tunable_buffer, sizeof(tunable_buffer),
979*5db2f26eSSascha Wildner 		    "hw.pci.link.%s.irq", link_name);
980*5db2f26eSSascha Wildner 		if (kgetenv_int(tunable_buffer, &i) && PCI_INTERRUPT_VALID(i)) {
981*5db2f26eSSascha Wildner 			if (!link_valid_irq(link, i))
982*5db2f26eSSascha Wildner 				device_printf(dev,
983*5db2f26eSSascha Wildner 				    "Warning, IRQ %d is not listed as valid\n",
984*5db2f26eSSascha Wildner 				    i);
985*5db2f26eSSascha Wildner 			return (i);
986*5db2f26eSSascha Wildner 		}
987*5db2f26eSSascha Wildner 	}
988*5db2f26eSSascha Wildner 
989*5db2f26eSSascha Wildner 	/*
990*5db2f26eSSascha Wildner 	 * If we have a valid BIOS IRQ, use that.  We trust what the BIOS
991*5db2f26eSSascha Wildner 	 * says it routed over what _CRS says the link thinks is routed.
992*5db2f26eSSascha Wildner 	 */
993*5db2f26eSSascha Wildner 	if (PCI_INTERRUPT_VALID(link->l_bios_irq))
994*5db2f26eSSascha Wildner 		return (link->l_bios_irq);
995*5db2f26eSSascha Wildner 
996*5db2f26eSSascha Wildner 	/*
997*5db2f26eSSascha Wildner 	 * If we don't have a BIOS IRQ but do have a valid IRQ from _CRS,
998*5db2f26eSSascha Wildner 	 * then use that.
999*5db2f26eSSascha Wildner 	 */
1000*5db2f26eSSascha Wildner 	if (PCI_INTERRUPT_VALID(link->l_initial_irq))
1001*5db2f26eSSascha Wildner 		return (link->l_initial_irq);
1002*5db2f26eSSascha Wildner 
1003*5db2f26eSSascha Wildner 	/*
1004*5db2f26eSSascha Wildner 	 * Ok, we have no useful hints, so we have to pick from the
1005*5db2f26eSSascha Wildner 	 * possible IRQs.  For ISA IRQs we only use interrupts that
1006*5db2f26eSSascha Wildner 	 * have already been used by the BIOS.
1007*5db2f26eSSascha Wildner 	 */
1008*5db2f26eSSascha Wildner 	best_irq = PCI_INVALID_IRQ;
1009*5db2f26eSSascha Wildner 	best_weight = INT_MAX;
1010*5db2f26eSSascha Wildner 	for (i = 0; i < link->l_num_irqs; i++) {
1011*5db2f26eSSascha Wildner 		pos_irq = link->l_irqs[i];
1012*5db2f26eSSascha Wildner 		if (pos_irq < NUM_ISA_INTERRUPTS &&
1013*5db2f26eSSascha Wildner 		    (pci_link_bios_isa_irqs & 1 << pos_irq) == 0)
1014*5db2f26eSSascha Wildner 			continue;
1015*5db2f26eSSascha Wildner 		pos_weight = pci_link_interrupt_weights[pos_irq];
1016*5db2f26eSSascha Wildner 		if (pos_weight < best_weight) {
1017*5db2f26eSSascha Wildner 			best_weight = pos_weight;
1018*5db2f26eSSascha Wildner 			best_irq = pos_irq;
1019*5db2f26eSSascha Wildner 		}
1020*5db2f26eSSascha Wildner 	}
1021*5db2f26eSSascha Wildner 
1022*5db2f26eSSascha Wildner         /*
1023*5db2f26eSSascha Wildner 	 * If this is an ISA IRQ and SCI could be shared, try using
1024*5db2f26eSSascha Wildner 	 * the SCI as a fallback.
1025*5db2f26eSSascha Wildner 	 */
1026*5db2f26eSSascha Wildner 	if (link->l_isa_irq && acpi_sci_pci_shariable()) {
1027*5db2f26eSSascha Wildner 		pos_irq = AcpiGbl_FADT.SciInterrupt;
1028*5db2f26eSSascha Wildner 		pos_weight = pci_link_interrupt_weights[pos_irq];
1029*5db2f26eSSascha Wildner 		if (pos_weight < best_weight) {
1030*5db2f26eSSascha Wildner 			best_weight = pos_weight;
1031*5db2f26eSSascha Wildner 			best_irq = pos_irq;
1032*5db2f26eSSascha Wildner 		}
1033*5db2f26eSSascha Wildner 	}
1034*5db2f26eSSascha Wildner 
1035*5db2f26eSSascha Wildner 	if (PCI_INTERRUPT_VALID(best_irq)) {
1036*5db2f26eSSascha Wildner 		if (bootverbose)
1037*5db2f26eSSascha Wildner 			device_printf(dev, "Picked IRQ %u with weight %d\n",
1038*5db2f26eSSascha Wildner 			    best_irq, best_weight);
1039*5db2f26eSSascha Wildner 	} else
1040*5db2f26eSSascha Wildner 		device_printf(dev, "Unable to choose an IRQ\n");
1041*5db2f26eSSascha Wildner 	return (best_irq);
1042*5db2f26eSSascha Wildner }
1043*5db2f26eSSascha Wildner 
1044*5db2f26eSSascha Wildner int
1045*5db2f26eSSascha Wildner acpi_pci_link_route_interrupt(device_t dev, int index)
1046*5db2f26eSSascha Wildner {
1047*5db2f26eSSascha Wildner 	struct link *link;
1048*5db2f26eSSascha Wildner 
1049*5db2f26eSSascha Wildner 	if (acpi_disabled("pci_link"))
1050*5db2f26eSSascha Wildner 		return (PCI_INVALID_IRQ);
1051*5db2f26eSSascha Wildner 
1052*5db2f26eSSascha Wildner 	ACPI_SERIAL_BEGIN(pci_link);
1053*5db2f26eSSascha Wildner 	link = acpi_pci_link_lookup(dev, index);
1054*5db2f26eSSascha Wildner 	if (link == NULL)
1055*5db2f26eSSascha Wildner 		panic("%s: apparently invalid index %d", __func__, index);
1056*5db2f26eSSascha Wildner 
1057*5db2f26eSSascha Wildner 	/*
1058*5db2f26eSSascha Wildner 	 * If this link device is already routed to an interrupt, just return
1059*5db2f26eSSascha Wildner 	 * the interrupt it is routed to.
1060*5db2f26eSSascha Wildner 	 */
1061*5db2f26eSSascha Wildner 	if (link->l_routed) {
1062*5db2f26eSSascha Wildner 		KASSERT(PCI_INTERRUPT_VALID(link->l_irq),
1063*5db2f26eSSascha Wildner 		    ("%s: link is routed but has an invalid IRQ", __func__));
1064*5db2f26eSSascha Wildner 		ACPI_SERIAL_END(pci_link);
1065*5db2f26eSSascha Wildner 		return (link->l_irq);
1066*5db2f26eSSascha Wildner 	}
1067*5db2f26eSSascha Wildner 
1068*5db2f26eSSascha Wildner 	/* Choose an IRQ if we need one. */
1069*5db2f26eSSascha Wildner 	if (!PCI_INTERRUPT_VALID(link->l_irq)) {
1070*5db2f26eSSascha Wildner 		link->l_irq = acpi_pci_link_choose_irq(dev, link);
1071*5db2f26eSSascha Wildner 
1072*5db2f26eSSascha Wildner 		/*
1073*5db2f26eSSascha Wildner 		 * Try to route the interrupt we picked.  If it fails, then
1074*5db2f26eSSascha Wildner 		 * assume the interrupt is not routed.
1075*5db2f26eSSascha Wildner 		 */
1076*5db2f26eSSascha Wildner 		if (PCI_INTERRUPT_VALID(link->l_irq)) {
1077*5db2f26eSSascha Wildner 			acpi_pci_link_route_irqs(dev);
1078*5db2f26eSSascha Wildner 			if (!link->l_routed)
1079*5db2f26eSSascha Wildner 				link->l_irq = PCI_INVALID_IRQ;
1080*5db2f26eSSascha Wildner 		}
1081*5db2f26eSSascha Wildner 	}
1082*5db2f26eSSascha Wildner 	ACPI_SERIAL_END(pci_link);
1083*5db2f26eSSascha Wildner 	return (link->l_irq);
1084*5db2f26eSSascha Wildner }
1085*5db2f26eSSascha Wildner 
1086*5db2f26eSSascha Wildner /*
1087*5db2f26eSSascha Wildner  * This is gross, but we abuse the identify routine to perform one-time
1088*5db2f26eSSascha Wildner  * SYSINIT() style initialization for the driver.
1089*5db2f26eSSascha Wildner  */
1090*5db2f26eSSascha Wildner static void
1091*5db2f26eSSascha Wildner acpi_pci_link_identify(driver_t *driver, device_t parent)
1092*5db2f26eSSascha Wildner {
1093*5db2f26eSSascha Wildner 	/*
1094*5db2f26eSSascha Wildner 	 * If the SCI is an ISA IRQ and could be shared,
1095*5db2f26eSSascha Wildner 	 * add it to the bitmask of known good ISA IRQs.
1096*5db2f26eSSascha Wildner 	 */
1097*5db2f26eSSascha Wildner 	if (AcpiGbl_FADT.SciInterrupt < NUM_ISA_INTERRUPTS &&
1098*5db2f26eSSascha Wildner 	    acpi_sci_pci_shariable())
1099*5db2f26eSSascha Wildner 		pci_link_bios_isa_irqs |= (1 << AcpiGbl_FADT.SciInterrupt);
1100*5db2f26eSSascha Wildner }
1101*5db2f26eSSascha Wildner 
1102*5db2f26eSSascha Wildner static device_method_t acpi_pci_link_methods[] = {
1103*5db2f26eSSascha Wildner 	/* Device interface */
1104*5db2f26eSSascha Wildner 	DEVMETHOD(device_identify,	acpi_pci_link_identify),
1105*5db2f26eSSascha Wildner 	DEVMETHOD(device_probe,		acpi_pci_link_probe),
1106*5db2f26eSSascha Wildner 	DEVMETHOD(device_attach,	acpi_pci_link_attach),
1107*5db2f26eSSascha Wildner 	DEVMETHOD(device_resume,	acpi_pci_link_resume),
1108*5db2f26eSSascha Wildner 
1109*5db2f26eSSascha Wildner 	{0, 0}
1110*5db2f26eSSascha Wildner };
1111*5db2f26eSSascha Wildner 
1112*5db2f26eSSascha Wildner static driver_t acpi_pci_link_driver = {
1113*5db2f26eSSascha Wildner 	"pci_link",
1114*5db2f26eSSascha Wildner 	acpi_pci_link_methods,
1115*5db2f26eSSascha Wildner 	sizeof(struct acpi_pci_link_softc),
1116*5db2f26eSSascha Wildner };
1117*5db2f26eSSascha Wildner 
1118*5db2f26eSSascha Wildner static devclass_t pci_link_devclass;
1119*5db2f26eSSascha Wildner 
1120*5db2f26eSSascha Wildner DRIVER_MODULE(acpi_pci_link, acpi, acpi_pci_link_driver, pci_link_devclass,
1121*5db2f26eSSascha Wildner     NULL, NULL);
1122*5db2f26eSSascha Wildner MODULE_DEPEND(acpi_pci_link, acpi, 1, 1, 1);
1123