1 /* $NetBSD: acpi_pci_link.c,v 1.14 2008/11/17 23:29:49 joerg Exp $ */
4 * Copyright (c) 2002 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: acpi_pci_link.c,v 1.14 2008/11/17 23:29:49 joerg Exp $");
33 #include <sys/param.h>
34 #include <sys/kernel.h>
35 #include <sys/malloc.h>
36 #include <sys/queue.h>
37 #include <sys/reboot.h>
39 #include <dev/acpi/acpica.h>
40 #include <dev/acpi/acpireg.h>
41 #include <dev/acpi/acpivar.h>
43 #include <dev/pci/pcireg.h>
44 #include <dev/pci/pcivar.h>
46 #define _COMPONENT ACPI_BUS_COMPONENT
47 ACPI_MODULE_NAME ("acpi_pci_link")
50 #define NUM_ISA_INTERRUPTS 16
51 #define NUM_ACPI_INTERRUPTS 256
53 #define PCI_INVALID_IRQ 255
54 #define PCI_INTERRUPT_VALID(x) ((x) != PCI_INVALID_IRQ && (x) != 0)
56 #define ACPI_SERIAL_BEGIN(x)
57 #define ACPI_SERIAL_END(x)
60 * An ACPI PCI link device may contain multiple links. Each link has its
61 * own ACPI resource. _PRT entries specify which link is being used via
64 * XXX: A note about Source Indices and DPFs: Currently we assume that
65 * the DPF start and end tags are not counted towards the index that
66 * Source Index corresponds to. Also, we assume that when DPFs are in use
67 * they various sets overlap in terms of Indices. Here's an example
68 * resource list indicating these assumptions:
82 * The XXX is because I'm not sure if this is a valid assumption to make.
85 /* States during DPF processing. */
92 struct acpi_pci_link_softc
{
95 struct link
*pl_links
;
97 ACPI_HANDLE pl_handle
;
98 TAILQ_ENTRY(acpi_pci_link_softc
) pl_list
;
101 static TAILQ_HEAD(, acpi_pci_link_softc
) acpi_pci_linkdevs
=
102 TAILQ_HEAD_INITIALIZER(acpi_pci_linkdevs
);
106 struct acpi_pci_link_softc
*l_sc
;
111 uint8_t l_initial_irq
;
120 ACPI_RESOURCE l_prs_template
;
123 struct link_count_request
{
128 struct link_res_request
{
129 struct acpi_pci_link_softc
*sc
;
135 MALLOC_DEFINE(M_PCI_LINK
, "pci_link", "ACPI PCI Link structures");
137 static int pci_link_interrupt_weights
[NUM_ACPI_INTERRUPTS
];
138 static int pci_link_bios_isa_irqs
;
140 static ACPI_STATUS
acpi_count_irq_resources(ACPI_RESOURCE
*, void *);
141 static ACPI_STATUS
link_add_crs(ACPI_RESOURCE
*, void *);
142 static ACPI_STATUS
link_add_prs(ACPI_RESOURCE
*, void *);
143 static int link_valid_irq(struct link
*, int);
144 static void acpi_pci_link_dump(struct acpi_pci_link_softc
*);
145 static int acpi_pci_link_attach(struct acpi_pci_link_softc
*);
146 static uint8_t acpi_pci_link_search_irq(struct acpi_pci_link_softc
*, int, int,
148 static struct link
*acpi_pci_link_lookup(struct acpi_pci_link_softc
*, int);
149 static ACPI_STATUS
acpi_pci_link_srs(struct acpi_pci_link_softc
*,
151 static ACPI_STATUS
acpi_AppendBufferResource(ACPI_BUFFER
*, ACPI_RESOURCE
*);
154 acpi_count_irq_resources(ACPI_RESOURCE
*res
, void *context
)
156 struct link_count_request
*req
;
158 req
= (struct link_count_request
*)context
;
160 case ACPI_RESOURCE_TYPE_START_DEPENDENT
:
161 switch (req
->in_dpf
) {
163 /* We've started the first DPF. */
164 req
->in_dpf
= DPF_FIRST
;
167 /* We've started the second DPF. */
168 req
->in_dpf
= DPF_IGNORE
;
172 case ACPI_RESOURCE_TYPE_END_DEPENDENT
:
173 /* We are finished with DPF parsing. */
174 KASSERT(req
->in_dpf
!= DPF_OUTSIDE
);
175 req
->in_dpf
= DPF_OUTSIDE
;
177 case ACPI_RESOURCE_TYPE_IRQ
:
178 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ
:
180 * Don't count resources if we are in a DPF set that we are
183 if (req
->in_dpf
!= DPF_IGNORE
)
190 link_add_crs(ACPI_RESOURCE
*res
, void *context
)
192 struct link_res_request
*req
;
195 req
= (struct link_res_request
*)context
;
197 case ACPI_RESOURCE_TYPE_START_DEPENDENT
:
198 switch (req
->in_dpf
) {
200 /* We've started the first DPF. */
201 req
->in_dpf
= DPF_FIRST
;
204 /* We've started the second DPF. */
206 "%s: Multiple dependent functions within a current resource",
211 case ACPI_RESOURCE_TYPE_END_DEPENDENT
:
212 /* We are finished with DPF parsing. */
213 KASSERT(req
->in_dpf
!= DPF_OUTSIDE
);
214 req
->in_dpf
= DPF_OUTSIDE
;
216 case ACPI_RESOURCE_TYPE_IRQ
:
217 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ
:
218 KASSERT(req
->link_index
< req
->sc
->pl_num_links
);
219 link
= &req
->sc
->pl_links
[req
->link_index
];
220 link
->l_res_index
= req
->res_index
;
225 * Only use the current value if there's one IRQ. Some
226 * systems return multiple IRQs (which is nonsense for _CRS)
227 * when the link hasn't been programmed.
229 if (res
->Type
== ACPI_RESOURCE_TYPE_IRQ
) {
230 if (res
->Data
.Irq
.InterruptCount
== 1) {
231 link
->l_irq
= res
->Data
.Irq
.Interrupts
[0];
232 link
->l_trig
= res
->Data
.Irq
.Triggering
;
233 link
->l_pol
= res
->Data
.Irq
.Polarity
;
235 } else if (res
->Data
.ExtendedIrq
.InterruptCount
== 1) {
236 link
->l_irq
= res
->Data
.ExtendedIrq
.Interrupts
[0];
237 link
->l_trig
= res
->Data
.ExtendedIrq
.Triggering
;
238 link
->l_pol
= res
->Data
.ExtendedIrq
.Polarity
;
242 * An IRQ of zero means that the link isn't routed.
244 if (link
->l_irq
== 0)
245 link
->l_irq
= PCI_INVALID_IRQ
;
254 * Populate the set of possible IRQs for each device.
257 link_add_prs(ACPI_RESOURCE
*res
, void *context
)
259 struct link_res_request
*req
;
262 UINT32
*ext_irqs
= NULL
;
263 int i
, is_ext_irq
= 1;
265 req
= (struct link_res_request
*)context
;
267 case ACPI_RESOURCE_TYPE_START_DEPENDENT
:
268 switch (req
->in_dpf
) {
270 /* We've started the first DPF. */
271 req
->in_dpf
= DPF_FIRST
;
274 /* We've started the second DPF. */
275 req
->in_dpf
= DPF_IGNORE
;
279 case ACPI_RESOURCE_TYPE_END_DEPENDENT
:
280 /* We are finished with DPF parsing. */
281 KASSERT(req
->in_dpf
!= DPF_OUTSIDE
);
282 req
->in_dpf
= DPF_OUTSIDE
;
284 case ACPI_RESOURCE_TYPE_IRQ
:
287 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ
:
289 * Don't parse resources if we are in a DPF set that we are
292 if (req
->in_dpf
== DPF_IGNORE
)
295 KASSERT(req
->link_index
< req
->sc
->pl_num_links
);
296 link
= &req
->sc
->pl_links
[req
->link_index
];
297 if (link
->l_res_index
== -1) {
298 KASSERT(req
->sc
->pl_crs_bad
);
299 link
->l_res_index
= req
->res_index
;
305 * Stash a copy of the resource for later use when
308 * Note that in theory res->Length may exceed the size
309 * of ACPI_RESOURCE, due to variable length lists in
310 * subtypes. However, all uses of l_prs_template only
311 * rely on lists lengths of zero or one, for which
312 * sizeof(ACPI_RESOURCE) is sufficient space anyway.
313 * We cannot read longer than Length bytes, in case we
314 * read off the end of mapped memory. So we read
315 * whichever length is shortest, Length or
316 * sizeof(ACPI_RESOURCE).
318 KASSERT(res
->Length
>= ACPI_RS_SIZE_MIN
);
320 memset(&link
->l_prs_template
, 0, sizeof(link
->l_prs_template
));
321 memcpy(&link
->l_prs_template
, res
,
322 MIN(res
->Length
, sizeof(link
->l_prs_template
)));
326 res
->Data
.ExtendedIrq
.InterruptCount
;
327 link
->l_trig
= res
->Data
.ExtendedIrq
.Triggering
;
328 link
->l_pol
= res
->Data
.ExtendedIrq
.Polarity
;
329 ext_irqs
= res
->Data
.ExtendedIrq
.Interrupts
;
331 link
->l_num_irqs
= res
->Data
.Irq
.InterruptCount
;
332 link
->l_trig
= res
->Data
.Irq
.Triggering
;
333 link
->l_pol
= res
->Data
.Irq
.Polarity
;
334 irqs
= res
->Data
.Irq
.Interrupts
;
336 if (link
->l_num_irqs
== 0)
340 * Save a list of the valid IRQs. Also, if all of the
341 * valid IRQs are ISA IRQs, then mark this link as
342 * routed via an ISA interrupt.
344 link
->l_isa_irq
= TRUE
;
345 link
->l_irqs
= malloc(sizeof(int) * link
->l_num_irqs
,
346 M_PCI_LINK
, M_WAITOK
| M_ZERO
);
347 for (i
= 0; i
< link
->l_num_irqs
; i
++) {
349 link
->l_irqs
[i
] = ext_irqs
[i
];
350 if (ext_irqs
[i
] >= NUM_ISA_INTERRUPTS
)
351 link
->l_isa_irq
= FALSE
;
353 link
->l_irqs
[i
] = irqs
[i
];
354 if (irqs
[i
] >= NUM_ISA_INTERRUPTS
)
355 link
->l_isa_irq
= FALSE
;
360 if (req
->in_dpf
== DPF_IGNORE
)
362 if (req
->sc
->pl_crs_bad
)
363 aprint_normal("%s: Warning: possible resource %d "
364 "will be lost during _SRS\n", req
->sc
->pl_name
,
372 link_valid_irq(struct link
*link
, int irq
)
376 /* Invalid interrupts are never valid. */
377 if (!PCI_INTERRUPT_VALID(irq
))
380 /* Any interrupt in the list of possible interrupts is valid. */
381 for (i
= 0; i
< link
->l_num_irqs
; i
++)
382 if (link
->l_irqs
[i
] == irq
)
386 * For links routed via an ISA interrupt, if the SCI is routed via
387 * an ISA interrupt, the SCI is always treated as a valid IRQ.
389 if (link
->l_isa_irq
&& AcpiGbl_FADT
.SciInterrupt
== irq
&&
390 irq
< NUM_ISA_INTERRUPTS
)
393 /* If the interrupt wasn't found in the list it is not valid. */
398 acpi_pci_link_state(void)
400 struct acpi_pci_link_softc
*sc
;
402 TAILQ_FOREACH(sc
, &acpi_pci_linkdevs
, pl_list
) {
403 acpi_pci_link_dump(sc
);
408 acpi_pci_link_dump(struct acpi_pci_link_softc
*sc
)
413 printf("Link Device %s:\n", sc
->pl_name
);
414 printf("Index IRQ Rtd Ref IRQs\n");
415 for (i
= 0; i
< sc
->pl_num_links
; i
++) {
416 link
= &sc
->pl_links
[i
];
417 printf("%5d %3d %c %3d ", i
, link
->l_irq
,
418 link
->l_routed
? 'Y' : 'N', link
->l_references
);
419 if (link
->l_num_irqs
== 0)
421 else for (j
= 0; j
< link
->l_num_irqs
; j
++)
422 printf(" %d", link
->l_irqs
[j
]);
423 printf(" polarity %u trigger %u\n", link
->l_pol
, link
->l_trig
);
429 acpi_pci_link_attach(struct acpi_pci_link_softc
*sc
)
431 struct link_count_request creq
;
432 struct link_res_request rreq
;
436 ACPI_SERIAL_BEGIN(pci_link
);
439 * Count the number of current resources so we know how big of
440 * a link array to allocate. On some systems, _CRS is broken,
441 * so for those systems try to derive the count from _PRS instead.
443 creq
.in_dpf
= DPF_OUTSIDE
;
445 status
= AcpiWalkResources(sc
->pl_handle
, "_CRS",
446 acpi_count_irq_resources
, &creq
);
447 sc
->pl_crs_bad
= ACPI_FAILURE(status
);
448 if (sc
->pl_crs_bad
) {
449 creq
.in_dpf
= DPF_OUTSIDE
;
451 status
= AcpiWalkResources(sc
->pl_handle
, "_PRS",
452 acpi_count_irq_resources
, &creq
);
453 if (ACPI_FAILURE(status
)) {
454 aprint_error("%s: Unable to parse _CRS or _PRS: %s\n",
455 sc
->pl_name
, AcpiFormatException(status
));
456 ACPI_SERIAL_END(pci_link
);
460 sc
->pl_num_links
= creq
.count
;
461 if (creq
.count
== 0) {
462 ACPI_SERIAL_END(pci_link
);
465 sc
->pl_links
= malloc(sizeof(struct link
) * sc
->pl_num_links
,
466 M_PCI_LINK
, M_WAITOK
| M_ZERO
);
468 /* Initialize the child links. */
469 for (i
= 0; i
< sc
->pl_num_links
; i
++) {
470 sc
->pl_links
[i
].l_irq
= PCI_INVALID_IRQ
;
471 sc
->pl_links
[i
].l_bios_irq
= PCI_INVALID_IRQ
;
472 sc
->pl_links
[i
].l_sc
= sc
;
473 sc
->pl_links
[i
].l_isa_irq
= FALSE
;
474 sc
->pl_links
[i
].l_res_index
= -1;
475 sc
->pl_links
[i
].l_dev_count
= 0;
476 sc
->pl_links
[i
].l_devices
= NULL
;
479 /* Try to read the current settings from _CRS if it is valid. */
480 if (!sc
->pl_crs_bad
) {
481 rreq
.in_dpf
= DPF_OUTSIDE
;
485 status
= AcpiWalkResources(sc
->pl_handle
, "_CRS",
486 link_add_crs
, &rreq
);
487 if (ACPI_FAILURE(status
)) {
488 aprint_error("%s: Unable to parse _CRS: %s\n",
489 sc
->pl_name
, AcpiFormatException(status
));
495 * Try to read the possible settings from _PRS. Note that if the
496 * _CRS is toast, we depend on having a working _PRS. However, if
497 * _CRS works, then it is ok for _PRS to be missing.
499 rreq
.in_dpf
= DPF_OUTSIDE
;
503 status
= AcpiWalkResources(sc
->pl_handle
, "_PRS",
504 link_add_prs
, &rreq
);
505 if (ACPI_FAILURE(status
) &&
506 (status
!= AE_NOT_FOUND
|| sc
->pl_crs_bad
)) {
507 aprint_error("%s: Unable to parse _PRS: %s\n",
508 sc
->pl_name
, AcpiFormatException(status
));
511 if (boothowto
& AB_VERBOSE
) {
512 aprint_normal("%s: Links after initial probe:\n", sc
->pl_name
);
513 acpi_pci_link_dump(sc
);
516 /* Verify initial IRQs if we have _PRS. */
517 if (status
!= AE_NOT_FOUND
)
518 for (i
= 0; i
< sc
->pl_num_links
; i
++)
519 if (!link_valid_irq(&sc
->pl_links
[i
],
520 sc
->pl_links
[i
].l_irq
))
521 sc
->pl_links
[i
].l_irq
= PCI_INVALID_IRQ
;
522 if (boothowto
& AB_VERBOSE
) {
523 printf("%s: Links after initial validation:\n", sc
->pl_name
);
524 acpi_pci_link_dump(sc
);
527 /* Save initial IRQs. */
528 for (i
= 0; i
< sc
->pl_num_links
; i
++)
529 sc
->pl_links
[i
].l_initial_irq
= sc
->pl_links
[i
].l_irq
;
532 * Try to disable this link. If successful, set the current IRQ to
533 * zero and flags to indicate this link is not routed. If we can't
534 * run _DIS (i.e., the method doesn't exist), assume the initial
535 * IRQ was routed by the BIOS.
537 #if 0 /* XXX causes spontaneaous resets on some systems. Disabled for now. */
538 if (ACPI_SUCCESS(AcpiEvaluateObject(sc
->pl_handle
, "_DIS", NULL
,
540 for (i
= 0; i
< sc
->pl_num_links
; i
++)
541 sc
->pl_links
[i
].l_irq
= PCI_INVALID_IRQ
;
544 for (i
= 0; i
< sc
->pl_num_links
; i
++)
545 if (PCI_INTERRUPT_VALID(sc
->pl_links
[i
].l_irq
))
546 sc
->pl_links
[i
].l_routed
= TRUE
;
547 if (boothowto
& AB_VERBOSE
) {
548 printf("%s: Links after disable:\n", sc
->pl_name
);
549 acpi_pci_link_dump(sc
);
551 ACPI_SERIAL_END(pci_link
);
554 ACPI_SERIAL_END(pci_link
);
555 for (i
= 0; i
< sc
->pl_num_links
; i
++) {
556 if (sc
->pl_links
[i
].l_irqs
!= NULL
)
557 free(sc
->pl_links
[i
].l_irqs
, M_PCI_LINK
);
558 if (sc
->pl_links
[i
].l_devices
!= NULL
)
559 free(sc
->pl_links
[i
].l_devices
, M_PCI_LINK
);
561 free(sc
->pl_links
, M_PCI_LINK
);
566 acpi_pci_link_add_functions(struct acpi_pci_link_softc
*sc
, struct link
*link
,
567 int bus
, int device
, int pin
)
570 uint8_t func
, maxfunc
, ipin
;
573 tag
= pci_make_tag(acpi_softc
->sc_pc
, bus
, device
, 0);
574 /* See if we have a valid device at function 0. */
575 value
= pci_conf_read(acpi_softc
->sc_pc
, tag
, PCI_BHLC_REG
);
576 if (PCI_HDRTYPE_TYPE(value
) > PCI_HDRTYPE_PCB
)
578 if (PCI_HDRTYPE_MULTIFN(value
))
583 /* Scan all possible functions at this device. */
584 for (func
= 0; func
<= maxfunc
; func
++) {
585 tag
= pci_make_tag(acpi_softc
->sc_pc
, bus
, device
, func
);
586 value
= pci_conf_read(acpi_softc
->sc_pc
, tag
, PCI_ID_REG
);
587 if (PCI_VENDOR(value
) == 0xffff)
589 value
= pci_conf_read(acpi_softc
->sc_pc
, tag
,
591 ipin
= PCI_INTERRUPT_PIN(value
);
593 * See if it uses the pin in question. Note that the passed
594 * in pin uses 0 for A, .. 3 for D whereas the intpin
595 * register uses 0 for no interrupt, 1 for A, .. 4 for D.
600 link
->l_devices
= realloc(link
->l_devices
,
601 sizeof(pcitag_t
) * (link
->l_dev_count
+ 1),
602 M_PCI_LINK
, M_WAITOK
);
603 link
->l_devices
[link
->l_dev_count
] = tag
;
609 acpi_pci_link_search_irq(struct acpi_pci_link_softc
*sc
, int bus
, int device
,
613 uint8_t func
, maxfunc
, ipin
, iline
;
616 tag
= pci_make_tag(acpi_softc
->sc_pc
, bus
, device
, 0);
617 /* See if we have a valid device at function 0. */
618 value
= pci_conf_read(acpi_softc
->sc_pc
, tag
, PCI_BHLC_REG
);
619 if (PCI_HDRTYPE_TYPE(value
) > PCI_HDRTYPE_PCB
)
620 return (PCI_INVALID_IRQ
);
621 if (PCI_HDRTYPE_MULTIFN(value
))
626 /* Scan all possible functions at this device. */
627 for (func
= 0; func
<= maxfunc
; func
++) {
628 tag
= pci_make_tag(acpi_softc
->sc_pc
, bus
, device
, func
);
629 value
= pci_conf_read(acpi_softc
->sc_pc
, tag
, PCI_ID_REG
);
630 if (PCI_VENDOR(value
) == 0xffff)
632 value
= pci_conf_read(acpi_softc
->sc_pc
, tag
,
634 ipin
= PCI_INTERRUPT_PIN(value
);
635 iline
= PCI_INTERRUPT_LINE(value
);
638 * See if it uses the pin in question. Note that the passed
639 * in pin uses 0 for A, .. 3 for D whereas the intpin
640 * register uses 0 for no interrupt, 1 for A, .. 4 for D.
645 "%s: ACPI: Found matching pin for %d.%d.INT%c"
647 sc
->pl_name
, bus
, device
, pin
+ 'A', func
, iline
);
648 if (PCI_INTERRUPT_VALID(iline
))
651 return (PCI_INVALID_IRQ
);
655 * Find the link structure that corresponds to the resource index passed in
656 * via 'source_index'.
659 acpi_pci_link_lookup(struct acpi_pci_link_softc
*sc
, int source_index
)
663 for (i
= 0; i
< sc
->pl_num_links
; i
++)
664 if (sc
->pl_links
[i
].l_res_index
== source_index
)
665 return (&sc
->pl_links
[i
]);
670 acpi_pci_link_add_reference(void *v
, int index
, int bus
, int slot
, int pin
)
672 struct acpi_pci_link_softc
*sc
= v
;
676 /* Bump the reference count. */
677 ACPI_SERIAL_BEGIN(pci_link
);
678 link
= acpi_pci_link_lookup(sc
, index
);
680 printf("%s: apparently invalid index %d\n", sc
->pl_name
, index
);
681 ACPI_SERIAL_END(pci_link
);
684 link
->l_references
++;
685 acpi_pci_link_add_functions(sc
, link
, bus
, slot
, pin
);
687 pci_link_interrupt_weights
[link
->l_irq
]++;
690 * The BIOS only routes interrupts via ISA IRQs using the ATPICs
691 * (8259As). Thus, if this link is routed via an ISA IRQ, go
692 * look to see if the BIOS routed an IRQ for this link at the
693 * indicated (bus, slot, pin). If so, we prefer that IRQ for
694 * this link and add that IRQ to our list of known-good IRQs.
695 * This provides a good work-around for link devices whose _CRS
696 * method is either broken or bogus. We only use the value
697 * returned by _CRS if we can't find a valid IRQ via this method
700 * If this link is not routed via an ISA IRQ (because we are using
701 * APIC for example), then don't bother looking up the BIOS IRQ
702 * as if we find one it won't be valid anyway.
704 if (!link
->l_isa_irq
) {
705 ACPI_SERIAL_END(pci_link
);
709 /* Try to find a BIOS IRQ setting from any matching devices. */
710 bios_irq
= acpi_pci_link_search_irq(sc
, bus
, slot
, pin
);
711 if (!PCI_INTERRUPT_VALID(bios_irq
)) {
712 ACPI_SERIAL_END(pci_link
);
716 /* Validate the BIOS IRQ. */
717 if (!link_valid_irq(link
, bios_irq
)) {
718 printf("%s: BIOS IRQ %u for %d.%d.INT%c is invalid\n",
719 sc
->pl_name
, bios_irq
, (int)bus
, slot
, pin
+ 'A');
720 } else if (!PCI_INTERRUPT_VALID(link
->l_bios_irq
)) {
721 link
->l_bios_irq
= bios_irq
;
722 if (bios_irq
< NUM_ISA_INTERRUPTS
)
723 pci_link_bios_isa_irqs
|= (1 << bios_irq
);
724 if (bios_irq
!= link
->l_initial_irq
&&
725 PCI_INTERRUPT_VALID(link
->l_initial_irq
))
727 "%s: BIOS IRQ %u does not match initial IRQ %u\n",
728 sc
->pl_name
, bios_irq
, link
->l_initial_irq
);
729 } else if (bios_irq
!= link
->l_bios_irq
)
731 "%s: BIOS IRQ %u for %d.%d.INT%c does not match "
732 "previous BIOS IRQ %u\n",
733 sc
->pl_name
, bios_irq
, (int)bus
, slot
, pin
+ 'A',
735 ACPI_SERIAL_END(pci_link
);
739 acpi_pci_link_srs_from_crs(struct acpi_pci_link_softc
*sc
, ACPI_BUFFER
*srsbuf
)
741 ACPI_RESOURCE
*resource
, *end
, newres
, *resptr
;
747 /* Fetch the _CRS. */
748 crsbuf
.Pointer
= NULL
;
749 crsbuf
.Length
= ACPI_ALLOCATE_LOCAL_BUFFER
;
750 status
= AcpiGetCurrentResources(sc
->pl_handle
, &crsbuf
);
751 if (ACPI_SUCCESS(status
) && crsbuf
.Pointer
== NULL
)
752 status
= AE_NO_MEMORY
;
753 if (ACPI_FAILURE(status
)) {
754 aprint_verbose("%s: Unable to fetch current resources: %s\n",
755 sc
->pl_name
, AcpiFormatException(status
));
759 /* Fill in IRQ resources via link structures. */
760 srsbuf
->Pointer
= NULL
;
763 in_dpf
= DPF_OUTSIDE
;
764 resource
= (ACPI_RESOURCE
*)crsbuf
.Pointer
;
765 end
= (ACPI_RESOURCE
*)((char *)crsbuf
.Pointer
+ crsbuf
.Length
);
767 switch (resource
->Type
) {
768 case ACPI_RESOURCE_TYPE_START_DEPENDENT
:
771 /* We've started the first DPF. */
775 /* We've started the second DPF. */
777 "%s: Multiple dependent functions within a current resource",
783 case ACPI_RESOURCE_TYPE_END_DEPENDENT
:
784 /* We are finished with DPF parsing. */
785 KASSERT(in_dpf
!= DPF_OUTSIDE
);
786 in_dpf
= DPF_OUTSIDE
;
789 case ACPI_RESOURCE_TYPE_IRQ
:
790 newres
= link
->l_prs_template
;
792 resptr
->Data
.Irq
.InterruptCount
= 1;
793 if (PCI_INTERRUPT_VALID(link
->l_irq
)) {
794 KASSERT(link
->l_irq
< NUM_ISA_INTERRUPTS
);
795 resptr
->Data
.Irq
.Interrupts
[0] = link
->l_irq
;
796 resptr
->Data
.Irq
.Triggering
= link
->l_trig
;
797 resptr
->Data
.Irq
.Polarity
= link
->l_pol
;
799 resptr
->Data
.Irq
.Interrupts
[0] = 0;
803 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ
:
804 newres
= link
->l_prs_template
;
806 resptr
->Data
.ExtendedIrq
.InterruptCount
= 1;
807 if (PCI_INTERRUPT_VALID(link
->l_irq
)) {
808 resptr
->Data
.ExtendedIrq
.Interrupts
[0] =
810 resptr
->Data
.ExtendedIrq
.Triggering
=
812 resptr
->Data
.ExtendedIrq
.Polarity
= link
->l_pol
;
814 resptr
->Data
.ExtendedIrq
.Interrupts
[0] = 0;
821 if (resptr
!= NULL
) {
822 status
= acpi_AppendBufferResource(srsbuf
, resptr
);
823 if (ACPI_FAILURE(status
)) {
824 printf("%s: Unable to build resources: %s\n",
825 sc
->pl_name
, AcpiFormatException(status
));
826 if (srsbuf
->Pointer
!= NULL
)
827 ACPI_FREE(srsbuf
->Pointer
);
828 ACPI_FREE(crsbuf
.Pointer
);
832 if (resource
->Type
== ACPI_RESOURCE_TYPE_END_TAG
)
834 resource
= ACPI_NEXT_RESOURCE(resource
);
838 ACPI_FREE(crsbuf
.Pointer
);
843 acpi_pci_link_srs_from_links(struct acpi_pci_link_softc
*sc
,
846 ACPI_RESOURCE newres
;
851 /* Start off with an empty buffer. */
852 srsbuf
->Pointer
= NULL
;
854 for (i
= 0; i
< sc
->pl_num_links
; i
++) {
856 /* Add a new IRQ resource from each link. */
857 link
= &sc
->pl_links
[i
];
858 newres
= link
->l_prs_template
;
859 if (newres
.Type
== ACPI_RESOURCE_TYPE_IRQ
) {
861 /* Build an IRQ resource. */
862 newres
.Data
.Irq
.InterruptCount
= 1;
863 if (PCI_INTERRUPT_VALID(link
->l_irq
)) {
864 KASSERT(link
->l_irq
< NUM_ISA_INTERRUPTS
);
865 newres
.Data
.Irq
.Interrupts
[0] = link
->l_irq
;
866 newres
.Data
.Irq
.Triggering
= link
->l_trig
;
867 newres
.Data
.Irq
.Polarity
= link
->l_pol
;
869 newres
.Data
.Irq
.Interrupts
[0] = 0;
872 /* Build an ExtIRQ resuorce. */
873 newres
.Data
.ExtendedIrq
.InterruptCount
= 1;
874 if (PCI_INTERRUPT_VALID(link
->l_irq
)) {
875 newres
.Data
.ExtendedIrq
.Interrupts
[0] =
877 newres
.Data
.ExtendedIrq
.Triggering
=
879 newres
.Data
.ExtendedIrq
.Polarity
=
882 newres
.Data
.ExtendedIrq
.Interrupts
[0] = 0;
886 /* Add the new resource to the end of the _SRS buffer. */
887 status
= acpi_AppendBufferResource(srsbuf
, &newres
);
888 if (ACPI_FAILURE(status
)) {
889 printf("%s: Unable to build resources: %s\n",
890 sc
->pl_name
, AcpiFormatException(status
));
891 if (srsbuf
->Pointer
!= NULL
)
892 ACPI_FREE(srsbuf
->Pointer
);
900 acpi_pci_link_srs(struct acpi_pci_link_softc
*sc
, ACPI_BUFFER
*srsbuf
)
905 status
= acpi_pci_link_srs_from_links(sc
, srsbuf
);
907 status
= acpi_pci_link_srs_from_crs(sc
, srsbuf
);
909 /* Write out new resources via _SRS. */
910 return AcpiSetCurrentResources(sc
->pl_handle
, srsbuf
);
914 acpi_pci_link_route_irqs(struct acpi_pci_link_softc
*sc
, int *irq
, int *pol
,
917 ACPI_RESOURCE
*resource
, *end
;
923 status
= acpi_pci_link_srs(sc
, &srsbuf
);
924 if (ACPI_FAILURE(status
)) {
925 printf("%s: _SRS failed: %s\n",
926 sc
->pl_name
, AcpiFormatException(status
));
930 * Perform acpi_config_intr() on each IRQ resource if it was just
931 * routed for the first time.
935 resource
= (ACPI_RESOURCE
*)srsbuf
.Pointer
;
936 end
= (ACPI_RESOURCE
*)((char *)srsbuf
.Pointer
+ srsbuf
.Length
);
938 if (resource
->Type
== ACPI_RESOURCE_TYPE_END_TAG
)
940 switch (resource
->Type
) {
941 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ
:
944 case ACPI_RESOURCE_TYPE_IRQ
:
946 * Only configure the interrupt and update the
947 * weights if this link has a valid IRQ and was
948 * previously unrouted.
950 if (!link
->l_routed
&&
951 PCI_INTERRUPT_VALID(link
->l_irq
)) {
953 resource
->Data
.ExtendedIrq
.Triggering
:
954 resource
->Data
.Irq
.Triggering
;
956 resource
->Data
.ExtendedIrq
.Polarity
:
957 resource
->Data
.Irq
.Polarity
;
959 resource
->Data
.ExtendedIrq
.Interrupts
[0] :
960 resource
->Data
.Irq
.Interrupts
[0];
961 link
->l_routed
= TRUE
;
962 pci_link_interrupt_weights
[link
->l_irq
] +=
969 resource
= ACPI_NEXT_RESOURCE(resource
);
973 ACPI_FREE(srsbuf
.Pointer
);
978 * Pick an IRQ to use for this unrouted link.
981 acpi_pci_link_choose_irq(struct acpi_pci_link_softc
*sc
, struct link
*link
)
983 u_int8_t best_irq
, pos_irq
;
984 int best_weight
, pos_weight
, i
;
986 KASSERT(!link
->l_routed
);
987 KASSERT(!PCI_INTERRUPT_VALID(link
->l_irq
));
990 * If we have a valid BIOS IRQ, use that. We trust what the BIOS
991 * says it routed over what _CRS says the link thinks is routed.
993 if (PCI_INTERRUPT_VALID(link
->l_bios_irq
))
994 return (link
->l_bios_irq
);
997 * If we don't have a BIOS IRQ but do have a valid IRQ from _CRS,
1000 if (PCI_INTERRUPT_VALID(link
->l_initial_irq
))
1001 return (link
->l_initial_irq
);
1004 * Ok, we have no useful hints, so we have to pick from the
1005 * possible IRQs. For ISA IRQs we only use interrupts that
1006 * have already been used by the BIOS.
1008 best_irq
= PCI_INVALID_IRQ
;
1009 best_weight
= INT_MAX
;
1010 for (i
= 0; i
< link
->l_num_irqs
; i
++) {
1011 pos_irq
= link
->l_irqs
[i
];
1012 if (pos_irq
< NUM_ISA_INTERRUPTS
&&
1013 (pci_link_bios_isa_irqs
& 1 << pos_irq
) == 0)
1015 pos_weight
= pci_link_interrupt_weights
[pos_irq
];
1016 if (pos_weight
< best_weight
) {
1017 best_weight
= pos_weight
;
1023 * If this is an ISA IRQ, try using the SCI if it is also an ISA
1024 * interrupt as a fallback.
1026 if (link
->l_isa_irq
&& !PCI_INTERRUPT_VALID(best_irq
)) {
1027 pos_irq
= AcpiGbl_FADT
.SciInterrupt
;
1028 pos_weight
= pci_link_interrupt_weights
[pos_irq
];
1029 if (pos_weight
< best_weight
) {
1030 best_weight
= pos_weight
;
1035 if (PCI_INTERRUPT_VALID(best_irq
)) {
1036 aprint_verbose("%s: Picked IRQ %u with weight %d\n",
1037 sc
->pl_name
, best_irq
, best_weight
);
1039 printf("%s: Unable to choose an IRQ\n", sc
->pl_name
);
1044 acpi_pci_link_route_interrupt(void *v
, int index
, int *irq
, int *pol
, int *trig
)
1046 struct acpi_pci_link_softc
*sc
= v
;
1051 ACPI_SERIAL_BEGIN(pci_link
);
1052 link
= acpi_pci_link_lookup(sc
, index
);
1054 panic("%s: apparently invalid index %d", __func__
, index
);
1057 * If this link device is already routed to an interrupt, just return
1058 * the interrupt it is routed to.
1060 if (link
->l_routed
) {
1061 KASSERT(PCI_INTERRUPT_VALID(link
->l_irq
));
1062 ACPI_SERIAL_END(pci_link
);
1065 *trig
= link
->l_trig
;
1066 return (link
->l_irq
);
1069 /* Choose an IRQ if we need one. */
1070 if (PCI_INTERRUPT_VALID(link
->l_irq
)) {
1073 *trig
= link
->l_trig
;
1077 link
->l_irq
= acpi_pci_link_choose_irq(sc
, link
);
1080 * Try to route the interrupt we picked. If it fails, then
1081 * assume the interrupt is not routed.
1083 if (!PCI_INTERRUPT_VALID(link
->l_irq
))
1086 acpi_pci_link_route_irqs(sc
, irq
, pol
, trig
);
1087 if (!link
->l_routed
) {
1088 link
->l_irq
= PCI_INVALID_IRQ
;
1093 link
->l_trig
= *trig
;
1094 for (i
= 0; i
< link
->l_dev_count
; ++i
) {
1095 reg
= pci_conf_read(acpi_softc
->sc_pc
, link
->l_devices
[i
],
1097 reg
&= ~(PCI_INTERRUPT_LINE_MASK
<< PCI_INTERRUPT_LINE_SHIFT
);
1098 reg
|= link
->l_irq
<< PCI_INTERRUPT_LINE_SHIFT
;
1099 pci_conf_write(acpi_softc
->sc_pc
, link
->l_devices
[i
],
1100 PCI_INTERRUPT_REG
, reg
);
1104 ACPI_SERIAL_END(pci_link
);
1106 return (link
->l_irq
);
1110 * This is gross, but we abuse the identify routine to perform one-time
1111 * SYSINIT() style initialization for the driver.
1114 acpi_pci_link_init(struct acpi_pci_link_softc
*sc
)
1119 * If the SCI is an ISA IRQ, add it to the bitmask of known good
1122 * XXX: If we are using the APIC, the SCI might have been
1123 * rerouted to an APIC pin in which case this is invalid. However,
1124 * if we are using the APIC, we also shouldn't be having any PCI
1125 * interrupts routed via ISA IRQs, so this is probably ok.
1127 if (AcpiGbl_FADT
.SciInterrupt
< NUM_ISA_INTERRUPTS
)
1128 pci_link_bios_isa_irqs
|= (1 << AcpiGbl_FADT
.SciInterrupt
);
1130 buf
.Length
= sizeof (sc
->pl_name
);
1131 buf
.Pointer
= sc
->pl_name
;
1133 if (ACPI_FAILURE(AcpiGetName(sc
->pl_handle
, ACPI_SINGLE_NAME
, &buf
)))
1134 snprintf(sc
->pl_name
, sizeof (sc
->pl_name
), "%s",
1135 "ACPI link device");
1137 acpi_pci_link_attach(sc
);
1141 acpi_pci_link_devbyhandle(ACPI_HANDLE handle
)
1143 struct acpi_pci_link_softc
*sc
;
1145 TAILQ_FOREACH(sc
, &acpi_pci_linkdevs
, pl_list
) {
1146 if (sc
->pl_handle
== handle
)
1150 sc
= malloc(sizeof (*sc
), M_PCI_LINK
, M_NOWAIT
|M_ZERO
);
1154 sc
->pl_handle
= handle
;
1156 acpi_pci_link_init(sc
);
1158 TAILQ_INSERT_TAIL(&acpi_pci_linkdevs
, sc
, pl_list
);
1164 acpi_pci_link_resume(void)
1166 struct acpi_pci_link_softc
*sc
;
1169 TAILQ_FOREACH(sc
, &acpi_pci_linkdevs
, pl_list
) {
1170 ACPI_SERIAL_BEGIN(pci_link
);
1171 if (ACPI_SUCCESS(acpi_pci_link_srs(sc
, &srsbuf
)))
1172 ACPI_FREE(srsbuf
.Pointer
);
1173 ACPI_SERIAL_END(pci_link
);
1178 acpi_pci_link_handle(void *v
)
1180 struct acpi_pci_link_softc
*sc
= v
;
1182 return sc
->pl_handle
;
1186 acpi_pci_link_name(void *v
)
1188 struct acpi_pci_link_softc
*sc
= v
;
1195 * Append an ACPI_RESOURCE to an ACPI_BUFFER.
1197 * Given a pointer to an ACPI_RESOURCE structure, expand the ACPI_BUFFER
1198 * provided to contain it. If the ACPI_BUFFER is empty, allocate a sensible
1199 * backing block. If the ACPI_RESOURCE is NULL, return an empty set of
1202 #define ACPI_INITIAL_RESOURCE_BUFFER_SIZE 512
1205 acpi_AppendBufferResource(ACPI_BUFFER
*buf
, ACPI_RESOURCE
*res
)
1210 /* Initialise the buffer if necessary. */
1211 if (buf
->Pointer
== NULL
) {
1212 buf
->Length
= ACPI_INITIAL_RESOURCE_BUFFER_SIZE
;
1213 if ((buf
->Pointer
= ACPI_ALLOCATE(buf
->Length
)) == NULL
)
1214 return (AE_NO_MEMORY
);
1215 rp
= (ACPI_RESOURCE
*)buf
->Pointer
;
1216 rp
->Type
= ACPI_RESOURCE_TYPE_END_TAG
;
1224 * Scan the current buffer looking for the terminator.
1225 * This will either find the terminator or hit the end
1226 * of the buffer and return an error.
1228 rp
= (ACPI_RESOURCE
*)buf
->Pointer
;
1230 /* Range check, don't go outside the buffer */
1231 if (rp
>= (ACPI_RESOURCE
*)((u_int8_t
*)buf
->Pointer
+
1233 return (AE_BAD_PARAMETER
);
1234 if (rp
->Type
== ACPI_RESOURCE_TYPE_END_TAG
|| rp
->Length
== 0)
1236 rp
= ACPI_NEXT_RESOURCE(rp
);
1240 * Check the size of the buffer and expand if required.
1243 * size of existing resources before terminator +
1244 * size of new resource and header +
1245 * size of terminator.
1247 * Note that this loop should really only run once, unless
1248 * for some reason we are stuffing a *really* huge resource.
1250 while ((((u_int8_t
*)rp
- (u_int8_t
*)buf
->Pointer
) +
1251 res
->Length
+ ACPI_RS_SIZE_NO_DATA
+
1252 ACPI_RS_SIZE_MIN
) >= buf
->Length
) {
1253 if ((newp
= ACPI_ALLOCATE(buf
->Length
* 2)) == NULL
)
1254 return (AE_NO_MEMORY
);
1255 memcpy(newp
, buf
->Pointer
, buf
->Length
);
1256 rp
= (ACPI_RESOURCE
*)((u_int8_t
*)newp
+
1257 ((u_int8_t
*)rp
- (u_int8_t
*)buf
->Pointer
));
1258 ACPI_FREE(buf
->Pointer
);
1259 buf
->Pointer
= newp
;
1260 buf
->Length
+= buf
->Length
;
1263 /* Insert the new resource. */
1264 memcpy(rp
, res
, res
->Length
+ ACPI_RS_SIZE_NO_DATA
);
1266 /* And add the terminator. */
1267 rp
= ACPI_NEXT_RESOURCE(rp
);
1268 rp
->Type
= ACPI_RESOURCE_TYPE_END_TAG
;