2 * Copyright (c) 2002 Mitsuru IWASAKI <iwasaki@jp.kfreebsd.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $FreeBSD: src/sys/dev/acpica/acpi_pci_link.c,v 1.65 2013/04/23 00:40:24 svnexp Exp $
30 #include <sys/param.h>
32 #include <sys/kernel.h>
33 #include <sys/limits.h>
34 #include <sys/malloc.h>
35 #include <sys/module.h>
38 #include <dev/acpica/acpivar.h>
39 #include <dev/acpica/acpi_pcibvar.h>
40 #include <dev/acpica/acpi_sci_var.h>
42 #include <bus/pci/pci_cfgreg.h>
43 #include <bus/pci/pcireg.h>
44 #include <bus/pci/pcivar.h>
47 /* Hooks for the ACPICA debugging infrastructure. */
48 #define _COMPONENT ACPI_BUS
49 ACPI_MODULE_NAME("PCI_LINK")
51 ACPI_SERIAL_DECL(pci_link
, "ACPI PCI link");
53 #define NUM_ISA_INTERRUPTS 16
54 #define NUM_ACPI_INTERRUPTS 256
57 * An ACPI PCI link device may contain multiple links. Each link has its
58 * own ACPI resource. _PRT entries specify which link is being used via
61 * XXX: A note about Source Indices and DPFs: Currently we assume that
62 * the DPF start and end tags are not counted towards the index that
63 * Source Index corresponds to. Also, we assume that when DPFs are in use
64 * they various sets overlap in terms of Indices. Here's an example
65 * resource list indicating these assumptions:
79 * The XXX is because I'm not sure if this is a valid assumption to make.
82 /* States during DPF processing. */
89 struct acpi_pci_link_softc
{
92 struct link
*pl_links
;
97 struct acpi_pci_link_softc
*l_sc
;
100 uint8_t l_initial_irq
;
108 ACPI_RESOURCE l_prs_template
;
111 struct link_count_request
{
116 struct link_res_request
{
117 struct acpi_pci_link_softc
*sc
;
123 static MALLOC_DEFINE(M_PCI_LINK
, "pci_link", "ACPI PCI Link structures");
125 static int pci_link_interrupt_weights
[NUM_ACPI_INTERRUPTS
];
126 static int pci_link_bios_isa_irqs
;
128 static char *pci_link_ids
[] = { "PNP0C0F", NULL
};
131 * Fetch the short name associated with an ACPI handle and save it in the
135 acpi_short_name(ACPI_HANDLE handle
, char *buffer
, size_t buflen
)
140 buf
.Pointer
= buffer
;
141 return (AcpiGetName(handle
, ACPI_SINGLE_NAME
, &buf
));
145 acpi_pci_link_probe(device_t dev
)
147 char descr
[28], name
[12];
150 * We explicitly do not check _STA since not all systems set it to
153 if (acpi_disabled("pci_link") ||
154 ACPI_ID_PROBE(device_get_parent(dev
), dev
, pci_link_ids
) == NULL
)
157 if (ACPI_SUCCESS(acpi_short_name(acpi_get_handle(dev
), name
,
159 ksnprintf(descr
, sizeof(descr
), "ACPI PCI Link %s", name
);
160 device_set_desc_copy(dev
, descr
);
162 device_set_desc(dev
, "ACPI PCI Link");
168 acpi_count_irq_resources(ACPI_RESOURCE
*res
, void *context
)
170 struct link_count_request
*req
;
172 req
= (struct link_count_request
*)context
;
174 case ACPI_RESOURCE_TYPE_START_DEPENDENT
:
175 switch (req
->in_dpf
) {
177 /* We've started the first DPF. */
178 req
->in_dpf
= DPF_FIRST
;
181 /* We've started the second DPF. */
182 req
->in_dpf
= DPF_IGNORE
;
186 case ACPI_RESOURCE_TYPE_END_DEPENDENT
:
187 /* We are finished with DPF parsing. */
188 KASSERT(req
->in_dpf
!= DPF_OUTSIDE
,
189 ("%s: end dpf when not parsing a dpf", __func__
));
190 req
->in_dpf
= DPF_OUTSIDE
;
192 case ACPI_RESOURCE_TYPE_IRQ
:
193 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ
:
195 * Don't count resources if we are in a DPF set that we are
198 if (req
->in_dpf
!= DPF_IGNORE
)
205 link_add_crs(ACPI_RESOURCE
*res
, void *context
)
207 struct link_res_request
*req
;
210 ACPI_SERIAL_ASSERT(pci_link
);
211 req
= (struct link_res_request
*)context
;
213 case ACPI_RESOURCE_TYPE_START_DEPENDENT
:
214 switch (req
->in_dpf
) {
216 /* We've started the first DPF. */
217 req
->in_dpf
= DPF_FIRST
;
220 /* We've started the second DPF. */
222 "%s: Multiple dependent functions within a current resource",
227 case ACPI_RESOURCE_TYPE_END_DEPENDENT
:
228 /* We are finished with DPF parsing. */
229 KASSERT(req
->in_dpf
!= DPF_OUTSIDE
,
230 ("%s: end dpf when not parsing a dpf", __func__
));
231 req
->in_dpf
= DPF_OUTSIDE
;
233 case ACPI_RESOURCE_TYPE_IRQ
:
234 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ
:
235 KASSERT(req
->link_index
< req
->sc
->pl_num_links
,
236 ("%s: array boundary violation", __func__
));
237 link
= &req
->sc
->pl_links
[req
->link_index
];
238 link
->l_res_index
= req
->res_index
;
239 link
->l_crs_type
= res
->Type
;
244 * Only use the current value if there's one IRQ. Some
245 * systems return multiple IRQs (which is nonsense for _CRS)
246 * when the link hasn't been programmed.
248 if (res
->Type
== ACPI_RESOURCE_TYPE_IRQ
) {
249 if (res
->Data
.Irq
.InterruptCount
== 1)
250 link
->l_irq
= res
->Data
.Irq
.Interrupts
[0];
251 } else if (res
->Data
.ExtendedIrq
.InterruptCount
== 1)
252 link
->l_irq
= res
->Data
.ExtendedIrq
.Interrupts
[0];
255 * An IRQ of zero means that the link isn't routed.
257 if (link
->l_irq
== 0)
258 link
->l_irq
= PCI_INVALID_IRQ
;
267 * Populate the set of possible IRQs for each device.
270 link_add_prs(ACPI_RESOURCE
*res
, void *context
)
273 struct link_res_request
*req
;
276 UINT32
*ext_irqs
= NULL
;
277 int i
, is_ext_irq
= 1;
279 ACPI_SERIAL_ASSERT(pci_link
);
280 req
= (struct link_res_request
*)context
;
282 case ACPI_RESOURCE_TYPE_START_DEPENDENT
:
283 switch (req
->in_dpf
) {
285 /* We've started the first DPF. */
286 req
->in_dpf
= DPF_FIRST
;
289 /* We've started the second DPF. */
290 req
->in_dpf
= DPF_IGNORE
;
294 case ACPI_RESOURCE_TYPE_END_DEPENDENT
:
295 /* We are finished with DPF parsing. */
296 KASSERT(req
->in_dpf
!= DPF_OUTSIDE
,
297 ("%s: end dpf when not parsing a dpf", __func__
));
298 req
->in_dpf
= DPF_OUTSIDE
;
300 case ACPI_RESOURCE_TYPE_IRQ
:
303 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ
:
305 * Don't parse resources if we are in a DPF set that we are
308 if (req
->in_dpf
== DPF_IGNORE
)
311 KASSERT(req
->link_index
< req
->sc
->pl_num_links
,
312 ("%s: array boundary violation", __func__
));
313 link
= &req
->sc
->pl_links
[req
->link_index
];
314 if (link
->l_res_index
== -1) {
315 KASSERT(req
->sc
->pl_crs_bad
,
316 ("res_index should be set"));
317 link
->l_res_index
= req
->res_index
;
323 * Stash a copy of the resource for later use when doing
326 tmp
= &link
->l_prs_template
;
328 bcopy(res
, tmp
, ACPI_RS_SIZE(tmp
->Data
.ExtendedIrq
));
331 * XXX acpi_AppendBufferResource() cannot handle
334 bzero(&tmp
->Data
.ExtendedIrq
.ResourceSource
,
335 sizeof(tmp
->Data
.ExtendedIrq
.ResourceSource
));
336 tmp
->Length
= ACPI_RS_SIZE(tmp
->Data
.ExtendedIrq
);
339 res
->Data
.ExtendedIrq
.InterruptCount
;
340 ext_irqs
= res
->Data
.ExtendedIrq
.Interrupts
;
342 bcopy(res
, tmp
, ACPI_RS_SIZE(tmp
->Data
.Irq
));
343 link
->l_num_irqs
= res
->Data
.Irq
.InterruptCount
;
344 irqs
= res
->Data
.Irq
.Interrupts
;
346 if (link
->l_num_irqs
== 0)
350 * Save a list of the valid IRQs. Also, if all of the
351 * valid IRQs are ISA IRQs, then mark this link as
352 * routed via an ISA interrupt.
354 link
->l_isa_irq
= TRUE
;
356 link
->l_irqs
= kmalloc(sizeof(int) * link
->l_num_irqs
,
357 M_PCI_LINK
, M_WAITOK
| M_ZERO
);
358 for (i
= 0; i
< link
->l_num_irqs
; i
++) {
360 link
->l_irqs
[i
] = ext_irqs
[i
];
361 if (ext_irqs
[i
] >= NUM_ISA_INTERRUPTS
)
362 link
->l_isa_irq
= FALSE
;
364 link
->l_irqs
[i
] = irqs
[i
];
365 if (irqs
[i
] >= NUM_ISA_INTERRUPTS
)
366 link
->l_isa_irq
= FALSE
;
371 * If this is not an ISA IRQ but _CRS used a non-extended
372 * IRQ descriptor, don't use _CRS as a template for _SRS.
374 if (!req
->sc
->pl_crs_bad
&& !link
->l_isa_irq
&&
375 link
->l_crs_type
== ACPI_RESOURCE_TYPE_IRQ
)
376 req
->sc
->pl_crs_bad
= TRUE
;
379 if (req
->in_dpf
== DPF_IGNORE
)
381 if (req
->sc
->pl_crs_bad
)
382 device_printf(req
->sc
->pl_dev
,
383 "Warning: possible resource %d will be lost during _SRS\n",
391 link_valid_irq(struct link
*link
, int irq
)
395 ACPI_SERIAL_ASSERT(pci_link
);
397 /* Invalid interrupts are never valid. */
398 if (!PCI_INTERRUPT_VALID(irq
))
401 /* Any interrupt in the list of possible interrupts is valid. */
402 for (i
= 0; i
< link
->l_num_irqs
; i
++)
403 if (link
->l_irqs
[i
] == irq
)
407 * For links routed via an ISA interrupt, if the SCI is routed via
408 * an ISA interrupt, the SCI is always treated as a valid IRQ.
410 if (link
->l_isa_irq
&& AcpiGbl_FADT
.SciInterrupt
== irq
&&
411 irq
< NUM_ISA_INTERRUPTS
)
414 /* If the interrupt wasn't found in the list it is not valid. */
419 acpi_pci_link_dump(struct acpi_pci_link_softc
*sc
, int header
, const char *tag
)
425 ACPI_SERIAL_ASSERT(pci_link
);
427 ksnprintf(buf
, sizeof(buf
), "%s:",
428 device_get_nameunit(sc
->pl_dev
));
429 kprintf("%-16.16s Index IRQ Rtd Ref IRQs\n", buf
);
431 for (i
= 0; i
< sc
->pl_num_links
; i
++) {
432 link
= &sc
->pl_links
[i
];
433 kprintf(" %-14.14s %5d %3d %c %3d ", i
== 0 ? tag
: "", i
,
434 link
->l_irq
, link
->l_routed
? 'Y' : 'N',
436 if (link
->l_num_irqs
== 0)
438 else for (j
= 0; j
< link
->l_num_irqs
; j
++)
439 kprintf(" %d", link
->l_irqs
[j
]);
445 acpi_pci_link_attach(device_t dev
)
447 struct acpi_pci_link_softc
*sc
;
448 struct link_count_request creq
;
449 struct link_res_request rreq
;
453 sc
= device_get_softc(dev
);
455 ACPI_SERIAL_INIT(pci_link
);
456 ACPI_SERIAL_BEGIN(pci_link
);
459 * Count the number of current resources so we know how big of
460 * a link array to allocate. On some systems, _CRS is broken,
461 * so for those systems try to derive the count from _PRS instead.
463 creq
.in_dpf
= DPF_OUTSIDE
;
465 status
= AcpiWalkResources(acpi_get_handle(dev
), "_CRS",
466 acpi_count_irq_resources
, &creq
);
467 sc
->pl_crs_bad
= ACPI_FAILURE(status
);
468 if (sc
->pl_crs_bad
) {
469 creq
.in_dpf
= DPF_OUTSIDE
;
471 status
= AcpiWalkResources(acpi_get_handle(dev
), "_PRS",
472 acpi_count_irq_resources
, &creq
);
473 if (ACPI_FAILURE(status
)) {
475 "Unable to parse _CRS or _PRS: %s\n",
476 AcpiFormatException(status
));
477 ACPI_SERIAL_END(pci_link
);
481 sc
->pl_num_links
= creq
.count
;
482 if (creq
.count
== 0) {
483 ACPI_SERIAL_END(pci_link
);
486 sc
->pl_links
= kmalloc(sizeof(struct link
) * sc
->pl_num_links
,
487 M_PCI_LINK
, M_WAITOK
| M_ZERO
);
489 /* Initialize the child links. */
490 for (i
= 0; i
< sc
->pl_num_links
; i
++) {
491 sc
->pl_links
[i
].l_irq
= PCI_INVALID_IRQ
;
492 sc
->pl_links
[i
].l_bios_irq
= PCI_INVALID_IRQ
;
493 sc
->pl_links
[i
].l_sc
= sc
;
494 sc
->pl_links
[i
].l_isa_irq
= FALSE
;
495 sc
->pl_links
[i
].l_res_index
= -1;
498 /* Try to read the current settings from _CRS if it is valid. */
499 if (!sc
->pl_crs_bad
) {
500 rreq
.in_dpf
= DPF_OUTSIDE
;
504 status
= AcpiWalkResources(acpi_get_handle(dev
), "_CRS",
505 link_add_crs
, &rreq
);
506 if (ACPI_FAILURE(status
)) {
507 device_printf(dev
, "Unable to parse _CRS: %s\n",
508 AcpiFormatException(status
));
514 * Try to read the possible settings from _PRS. Note that if the
515 * _CRS is toast, we depend on having a working _PRS. However, if
516 * _CRS works, then it is ok for _PRS to be missing.
518 rreq
.in_dpf
= DPF_OUTSIDE
;
522 status
= AcpiWalkResources(acpi_get_handle(dev
), "_PRS",
523 link_add_prs
, &rreq
);
524 if (ACPI_FAILURE(status
) &&
525 (status
!= AE_NOT_FOUND
|| sc
->pl_crs_bad
)) {
526 device_printf(dev
, "Unable to parse _PRS: %s\n",
527 AcpiFormatException(status
));
531 acpi_pci_link_dump(sc
, 1, "Initial Probe");
533 /* Verify initial IRQs if we have _PRS. */
534 if (status
!= AE_NOT_FOUND
)
535 for (i
= 0; i
< sc
->pl_num_links
; i
++)
536 if (!link_valid_irq(&sc
->pl_links
[i
],
537 sc
->pl_links
[i
].l_irq
))
538 sc
->pl_links
[i
].l_irq
= PCI_INVALID_IRQ
;
540 acpi_pci_link_dump(sc
, 0, "Validation");
542 /* Save initial IRQs. */
543 for (i
= 0; i
< sc
->pl_num_links
; i
++)
544 sc
->pl_links
[i
].l_initial_irq
= sc
->pl_links
[i
].l_irq
;
547 * Try to disable this link. If successful, set the current IRQ to
548 * zero and flags to indicate this link is not routed. If we can't
549 * run _DIS (i.e., the method doesn't exist), assume the initial
550 * IRQ was routed by the BIOS.
552 if (ACPI_SUCCESS(AcpiEvaluateObject(acpi_get_handle(dev
), "_DIS", NULL
,
554 for (i
= 0; i
< sc
->pl_num_links
; i
++)
555 sc
->pl_links
[i
].l_irq
= PCI_INVALID_IRQ
;
557 for (i
= 0; i
< sc
->pl_num_links
; i
++)
558 if (PCI_INTERRUPT_VALID(sc
->pl_links
[i
].l_irq
))
559 sc
->pl_links
[i
].l_routed
= TRUE
;
561 acpi_pci_link_dump(sc
, 0, "After Disable");
562 ACPI_SERIAL_END(pci_link
);
565 ACPI_SERIAL_END(pci_link
);
566 for (i
= 0; i
< sc
->pl_num_links
; i
++)
567 if (sc
->pl_links
[i
].l_irqs
!= NULL
)
568 kfree(sc
->pl_links
[i
].l_irqs
, M_PCI_LINK
);
569 kfree(sc
->pl_links
, M_PCI_LINK
);
573 /* XXX: Note that this is identical to pci_pir_search_irq(). */
575 acpi_pci_link_search_irq(int bus
, int device
, int pin
)
578 uint8_t func
, maxfunc
;
580 /* See if we have a valid device at function 0. */
581 value
= pci_cfgregread(bus
, device
, 0, PCIR_HDRTYPE
, 1);
582 if ((value
& PCIM_HDRTYPE
) > PCI_MAXHDRTYPE
)
583 return (PCI_INVALID_IRQ
);
584 if (value
& PCIM_MFDEV
)
585 maxfunc
= PCI_FUNCMAX
;
589 /* Scan all possible functions at this device. */
590 for (func
= 0; func
<= maxfunc
; func
++) {
591 value
= pci_cfgregread(bus
, device
, func
, PCIR_DEVVENDOR
, 4);
592 if (value
== 0xffffffff)
594 value
= pci_cfgregread(bus
, device
, func
, PCIR_INTPIN
, 1);
597 * See if it uses the pin in question. Note that the passed
598 * in pin uses 0 for A, .. 3 for D whereas the intpin
599 * register uses 0 for no interrupt, 1 for A, .. 4 for D.
601 if (value
!= pin
+ 1)
603 value
= pci_cfgregread(bus
, device
, func
, PCIR_INTLINE
, 1);
606 "ACPI: Found matching pin for %d.%d.INT%c at func %d: %d\n",
607 bus
, device
, pin
+ 'A', func
, value
);
608 if (value
!= PCI_INVALID_IRQ
)
611 return (PCI_INVALID_IRQ
);
615 * Find the link structure that corresponds to the resource index passed in
616 * via 'source_index'.
619 acpi_pci_link_lookup(device_t dev
, int source_index
)
621 struct acpi_pci_link_softc
*sc
;
624 ACPI_SERIAL_ASSERT(pci_link
);
625 sc
= device_get_softc(dev
);
626 for (i
= 0; i
< sc
->pl_num_links
; i
++)
627 if (sc
->pl_links
[i
].l_res_index
== source_index
)
628 return (&sc
->pl_links
[i
]);
633 acpi_pci_link_add_reference(device_t dev
, int index
, device_t pcib
, int slot
,
641 * Look up the PCI bus for the specified PCI bridge device. Note
642 * that the PCI bridge device might not have any children yet.
643 * However, looking up its bus number doesn't require a valid child
644 * device, so we just pass NULL.
646 if (BUS_READ_IVAR(pcib
, NULL
, PCIB_IVAR_BUS
, &bus
) != 0) {
647 device_printf(pcib
, "Unable to read PCI bus number");
648 panic("PCI bridge without a bus number");
651 /* Bump the reference count. */
652 ACPI_SERIAL_BEGIN(pci_link
);
653 link
= acpi_pci_link_lookup(dev
, index
);
655 device_printf(dev
, "apparently invalid index %d\n", index
);
656 ACPI_SERIAL_END(pci_link
);
659 link
->l_references
++;
661 pci_link_interrupt_weights
[link
->l_irq
]++;
664 * The BIOS only routes interrupts via ISA IRQs using the ATPICs
665 * (8259As). Thus, if this link is routed via an ISA IRQ, go
666 * look to see if the BIOS routed an IRQ for this link at the
667 * indicated (bus, slot, pin). If so, we prefer that IRQ for
668 * this link and add that IRQ to our list of known-good IRQs.
669 * This provides a good work-around for link devices whose _CRS
670 * method is either broken or bogus. We only use the value
671 * returned by _CRS if we can't find a valid IRQ via this method
674 * If this link is not routed via an ISA IRQ (because we are using
675 * APIC for example), then don't bother looking up the BIOS IRQ
676 * as if we find one it won't be valid anyway.
678 if (!link
->l_isa_irq
) {
679 ACPI_SERIAL_END(pci_link
);
683 /* Try to find a BIOS IRQ setting from any matching devices. */
684 bios_irq
= acpi_pci_link_search_irq(bus
, slot
, pin
);
685 if (!PCI_INTERRUPT_VALID(bios_irq
)) {
686 ACPI_SERIAL_END(pci_link
);
690 /* Validate the BIOS IRQ. */
691 if (!link_valid_irq(link
, bios_irq
)) {
692 device_printf(dev
, "BIOS IRQ %u for %d.%d.INT%c is invalid\n",
693 bios_irq
, (int)bus
, slot
, pin
+ 'A');
694 } else if (!PCI_INTERRUPT_VALID(link
->l_bios_irq
)) {
695 link
->l_bios_irq
= bios_irq
;
697 * SCI setting is handled by acpi_pci_link_identify()
699 if (bios_irq
< NUM_ISA_INTERRUPTS
&&
700 AcpiGbl_FADT
.SciInterrupt
!= bios_irq
)
701 pci_link_bios_isa_irqs
|= (1 << bios_irq
);
702 if (bios_irq
!= link
->l_initial_irq
&&
703 PCI_INTERRUPT_VALID(link
->l_initial_irq
))
705 "BIOS IRQ %u does not match initial IRQ %u\n",
706 bios_irq
, link
->l_initial_irq
);
707 } else if (bios_irq
!= link
->l_bios_irq
)
709 "BIOS IRQ %u for %d.%d.INT%c does not match previous BIOS IRQ %u\n",
710 bios_irq
, (int)bus
, slot
, pin
+ 'A',
712 ACPI_SERIAL_END(pci_link
);
716 acpi_pci_link_srs_from_crs(struct acpi_pci_link_softc
*sc
, ACPI_BUFFER
*srsbuf
)
718 ACPI_RESOURCE
*end
, *res
;
723 /* Fetch the _CRS. */
724 ACPI_SERIAL_ASSERT(pci_link
);
725 srsbuf
->Pointer
= NULL
;
726 srsbuf
->Length
= ACPI_ALLOCATE_BUFFER
;
727 status
= AcpiGetCurrentResources(acpi_get_handle(sc
->pl_dev
), srsbuf
);
728 if (ACPI_SUCCESS(status
) && srsbuf
->Pointer
== NULL
)
729 status
= AE_NO_MEMORY
;
730 if (ACPI_FAILURE(status
)) {
732 device_printf(sc
->pl_dev
,
733 "Unable to fetch current resources: %s\n",
734 AcpiFormatException(status
));
738 /* Fill in IRQ resources via link structures. */
741 in_dpf
= DPF_OUTSIDE
;
742 res
= (ACPI_RESOURCE
*)srsbuf
->Pointer
;
743 end
= (ACPI_RESOURCE
*)((char *)srsbuf
->Pointer
+ srsbuf
->Length
);
746 case ACPI_RESOURCE_TYPE_START_DEPENDENT
:
749 /* We've started the first DPF. */
753 /* We've started the second DPF. */
755 "%s: Multiple dependent functions within a current resource",
760 case ACPI_RESOURCE_TYPE_END_DEPENDENT
:
761 /* We are finished with DPF parsing. */
762 KASSERT(in_dpf
!= DPF_OUTSIDE
,
763 ("%s: end dpf when not parsing a dpf", __func__
));
764 in_dpf
= DPF_OUTSIDE
;
766 case ACPI_RESOURCE_TYPE_IRQ
:
767 KKASSERT(i
< sc
->pl_num_links
);
768 res
->Data
.Irq
.InterruptCount
= 1;
769 if (PCI_INTERRUPT_VALID(link
->l_irq
)) {
770 KASSERT(link
->l_irq
< NUM_ISA_INTERRUPTS
,
771 ("%s: can't put non-ISA IRQ %d in legacy IRQ resource type",
772 __func__
, link
->l_irq
));
773 res
->Data
.Irq
.Interrupts
[0] = link
->l_irq
;
775 res
->Data
.Irq
.Interrupts
[0] = 0;
779 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ
:
780 KKASSERT(i
< sc
->pl_num_links
);
781 res
->Data
.ExtendedIrq
.InterruptCount
= 1;
782 if (PCI_INTERRUPT_VALID(link
->l_irq
))
783 res
->Data
.ExtendedIrq
.Interrupts
[0] =
786 res
->Data
.ExtendedIrq
.Interrupts
[0] = 0;
791 if (res
->Type
== ACPI_RESOURCE_TYPE_END_TAG
)
793 res
= ACPI_NEXT_RESOURCE(res
);
801 acpi_pci_link_srs_from_links(struct acpi_pci_link_softc
*sc
,
804 ACPI_RESOURCE newres
;
809 /* Start off with an empty buffer. */
810 srsbuf
->Pointer
= NULL
;
812 for (i
= 0; i
< sc
->pl_num_links
; i
++) {
814 /* Add a new IRQ resource from each link. */
815 link
= &sc
->pl_links
[i
];
816 if (link
->l_prs_template
.Type
== ACPI_RESOURCE_TYPE_IRQ
) {
818 /* Build an IRQ resource. */
819 bcopy(&link
->l_prs_template
, &newres
,
820 ACPI_RS_SIZE(newres
.Data
.Irq
));
821 newres
.Data
.Irq
.InterruptCount
= 1;
822 if (PCI_INTERRUPT_VALID(link
->l_irq
)) {
823 KASSERT(link
->l_irq
< NUM_ISA_INTERRUPTS
,
824 ("%s: can't put non-ISA IRQ %d in legacy IRQ resource type",
825 __func__
, link
->l_irq
));
826 newres
.Data
.Irq
.Interrupts
[0] = link
->l_irq
;
828 newres
.Data
.Irq
.Interrupts
[0] = 0;
831 /* Build an ExtIRQ resuorce. */
832 bcopy(&link
->l_prs_template
, &newres
,
833 ACPI_RS_SIZE(newres
.Data
.ExtendedIrq
));
834 newres
.Data
.ExtendedIrq
.InterruptCount
= 1;
835 if (PCI_INTERRUPT_VALID(link
->l_irq
))
836 newres
.Data
.ExtendedIrq
.Interrupts
[0] =
839 newres
.Data
.ExtendedIrq
.Interrupts
[0] = 0;
842 /* Add the new resource to the end of the _SRS buffer. */
843 status
= acpi_AppendBufferResource(srsbuf
, &newres
);
844 if (ACPI_FAILURE(status
)) {
845 device_printf(sc
->pl_dev
,
846 "Unable to build resources: %s\n",
847 AcpiFormatException(status
));
848 if (srsbuf
->Pointer
!= NULL
)
849 AcpiOsFree(srsbuf
->Pointer
);
857 acpi_pci_link_route_irqs(device_t dev
)
859 struct acpi_pci_link_softc
*sc
;
860 ACPI_RESOURCE
*resource
, *end
;
866 ACPI_SERIAL_ASSERT(pci_link
);
867 sc
= device_get_softc(dev
);
869 status
= acpi_pci_link_srs_from_links(sc
, &srsbuf
);
871 status
= acpi_pci_link_srs_from_crs(sc
, &srsbuf
);
873 /* Write out new resources via _SRS. */
874 status
= AcpiSetCurrentResources(acpi_get_handle(dev
), &srsbuf
);
875 if (ACPI_FAILURE(status
)) {
876 device_printf(dev
, "Unable to route IRQs: %s\n",
877 AcpiFormatException(status
));
878 AcpiOsFree(srsbuf
.Pointer
);
883 * Perform acpi_config_intr() on each IRQ resource if it was just
884 * routed for the first time.
888 resource
= (ACPI_RESOURCE
*)srsbuf
.Pointer
;
889 end
= (ACPI_RESOURCE
*)((char *)srsbuf
.Pointer
+ srsbuf
.Length
);
891 if (resource
->Type
== ACPI_RESOURCE_TYPE_END_TAG
)
893 switch (resource
->Type
) {
894 case ACPI_RESOURCE_TYPE_IRQ
:
895 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ
:
896 KKASSERT(i
< sc
->pl_num_links
);
899 * Only configure the interrupt and update the
900 * weights if this link has a valid IRQ and was
901 * previously unrouted.
903 if (!link
->l_routed
&&
904 PCI_INTERRUPT_VALID(link
->l_irq
)) {
905 link
->l_routed
= TRUE
;
906 acpi_config_intr(dev
, resource
);
907 pci_link_interrupt_weights
[link
->l_irq
] +=
914 resource
= ACPI_NEXT_RESOURCE(resource
);
918 AcpiOsFree(srsbuf
.Pointer
);
923 acpi_pci_link_resume(device_t dev
)
925 struct acpi_pci_link_softc
*sc
;
930 * If all of our links are routed, then restore the link via _SRS,
931 * otherwise, disable the link via _DIS.
933 ACPI_SERIAL_BEGIN(pci_link
);
934 sc
= device_get_softc(dev
);
936 for (i
= 0; i
< sc
->pl_num_links
; i
++)
937 if (sc
->pl_links
[i
].l_routed
)
939 if (routed
== sc
->pl_num_links
)
940 status
= acpi_pci_link_route_irqs(dev
);
942 AcpiEvaluateObject(acpi_get_handle(dev
), "_DIS", NULL
, NULL
);
945 ACPI_SERIAL_END(pci_link
);
946 if (ACPI_FAILURE(status
))
953 * Pick an IRQ to use for this unrouted link.
956 acpi_pci_link_choose_irq(device_t dev
, struct link
*link
)
958 char tunable_buffer
[64], link_name
[5];
959 uint8_t best_irq
, pos_irq
;
960 int best_weight
, pos_weight
, i
;
962 KASSERT(!link
->l_routed
, ("%s: link already routed", __func__
));
963 KASSERT(!PCI_INTERRUPT_VALID(link
->l_irq
),
964 ("%s: link already has an IRQ", __func__
));
966 /* Check for a tunable override. */
967 if (ACPI_SUCCESS(acpi_short_name(acpi_get_handle(dev
), link_name
,
968 sizeof(link_name
)))) {
969 ksnprintf(tunable_buffer
, sizeof(tunable_buffer
),
970 "hw.pci.link.%s.%d.irq", link_name
, link
->l_res_index
);
971 if (kgetenv_int(tunable_buffer
, &i
) && PCI_INTERRUPT_VALID(i
)) {
972 if (!link_valid_irq(link
, i
))
974 "Warning, IRQ %d is not listed as valid\n",
978 ksnprintf(tunable_buffer
, sizeof(tunable_buffer
),
979 "hw.pci.link.%s.irq", link_name
);
980 if (kgetenv_int(tunable_buffer
, &i
) && PCI_INTERRUPT_VALID(i
)) {
981 if (!link_valid_irq(link
, i
))
983 "Warning, IRQ %d is not listed as valid\n",
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 and SCI could be shared, try using
1024 * the SCI as a fallback.
1026 if (link
->l_isa_irq
&& acpi_sci_pci_shareable()) {
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
)) {
1037 device_printf(dev
, "Picked IRQ %u with weight %d\n",
1038 best_irq
, best_weight
);
1040 device_printf(dev
, "Unable to choose an IRQ\n");
1045 acpi_pci_link_route_interrupt(device_t dev
, int index
)
1049 if (acpi_disabled("pci_link"))
1050 return (PCI_INVALID_IRQ
);
1052 ACPI_SERIAL_BEGIN(pci_link
);
1053 link
= acpi_pci_link_lookup(dev
, index
);
1055 panic("%s: apparently invalid index %d", __func__
, index
);
1058 * If this link device is already routed to an interrupt, just return
1059 * the interrupt it is routed to.
1061 if (link
->l_routed
) {
1062 KASSERT(PCI_INTERRUPT_VALID(link
->l_irq
),
1063 ("%s: link is routed but has an invalid IRQ", __func__
));
1064 ACPI_SERIAL_END(pci_link
);
1065 return (link
->l_irq
);
1068 /* Choose an IRQ if we need one. */
1069 if (!PCI_INTERRUPT_VALID(link
->l_irq
)) {
1070 link
->l_irq
= acpi_pci_link_choose_irq(dev
, link
);
1073 * Try to route the interrupt we picked. If it fails, then
1074 * assume the interrupt is not routed.
1076 if (PCI_INTERRUPT_VALID(link
->l_irq
)) {
1077 acpi_pci_link_route_irqs(dev
);
1078 if (!link
->l_routed
)
1079 link
->l_irq
= PCI_INVALID_IRQ
;
1082 ACPI_SERIAL_END(pci_link
);
1083 return (link
->l_irq
);
1087 * This is gross, but we abuse the identify routine to perform one-time
1088 * SYSINIT() style initialization for the driver.
1091 acpi_pci_link_identify(driver_t
*driver
, device_t parent
)
1094 * If the SCI is an ISA IRQ and could be shared,
1095 * add it to the bitmask of known good ISA IRQs.
1097 if (AcpiGbl_FADT
.SciInterrupt
< NUM_ISA_INTERRUPTS
&&
1098 acpi_sci_pci_shareable())
1099 pci_link_bios_isa_irqs
|= (1 << AcpiGbl_FADT
.SciInterrupt
);
1102 static device_method_t acpi_pci_link_methods
[] = {
1103 /* Device interface */
1104 DEVMETHOD(device_identify
, acpi_pci_link_identify
),
1105 DEVMETHOD(device_probe
, acpi_pci_link_probe
),
1106 DEVMETHOD(device_attach
, acpi_pci_link_attach
),
1107 DEVMETHOD(device_resume
, acpi_pci_link_resume
),
1112 static driver_t acpi_pci_link_driver
= {
1114 acpi_pci_link_methods
,
1115 sizeof(struct acpi_pci_link_softc
),
1118 static devclass_t pci_link_devclass
;
1120 DRIVER_MODULE(acpi_pci_link
, acpi
, acpi_pci_link_driver
, pci_link_devclass
,
1122 MODULE_DEPEND(acpi_pci_link
, acpi
, 1, 1, 1);