2 * Copyright (c) 2002 Mitsuru IWASAKI <iwasaki@jp.freebsd.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.16 2004/06/14 18:54:14 jhb Exp $
27 * $DragonFly: src/sys/dev/acpica5/acpi_pci_link.c,v 1.7 2006/12/22 23:26:14 swildner Exp $
31 #include <sys/param.h>
32 #include <sys/kernel.h>
37 #include <dev/acpica5/acpivar.h>
38 #include <dev/acpica5/acpi_pcibvar.h>
40 /* Hooks for the ACPI CA debugging infrastructure. */
41 #define _COMPONENT ACPI_BUS
42 ACPI_MODULE_NAME("PCI_LINK")
44 #define MAX_POSSIBLE_INTERRUPTS 16
45 #define MAX_ISA_INTERRUPTS 16
46 #define MAX_ACPI_INTERRUPTS 255
48 struct acpi_pci_link_entry
{
49 TAILQ_ENTRY(acpi_pci_link_entry
) links
;
53 ACPI_RESOURCE possible_resources
;
54 UINT8 number_of_interrupts
;
55 UINT8 interrupts
[MAX_POSSIBLE_INTERRUPTS
];
56 UINT8 sorted_irq
[MAX_POSSIBLE_INTERRUPTS
];
61 TAILQ_HEAD(acpi_pci_link_entries
, acpi_pci_link_entry
);
62 static struct acpi_pci_link_entries acpi_pci_link_entries
;
64 struct acpi_prt_entry
{
65 TAILQ_ENTRY(acpi_prt_entry
) links
;
68 ACPI_PCI_ROUTING_TABLE prt
;
69 struct acpi_pci_link_entry
*pci_link
;
72 TAILQ_HEAD(acpi_prt_entries
, acpi_prt_entry
);
73 static struct acpi_prt_entries acpi_prt_entries
;
75 static int irq_penalty
[MAX_ACPI_INTERRUPTS
];
77 #define ACPI_STA_PRESENT 0x00000001
78 #define ACPI_STA_ENABLE 0x00000002
79 #define ACPI_STA_SHOWINUI 0x00000004
80 #define ACPI_STA_FUNCTIONAL 0x00000008
83 * PCI link object management
87 acpi_pci_link_dump_polarity(UINT32 Polarity
)
91 case ACPI_ACTIVE_HIGH
:
104 acpi_pci_link_dump_trigger(UINT32 Triggering
)
107 switch (Triggering
) {
108 case ACPI_EDGE_SENSITIVE
:
111 case ACPI_LEVEL_SENSITIVE
:
121 acpi_pci_link_dump_sharemode(UINT32 SharedExclusive
)
124 switch (SharedExclusive
) {
126 kprintf("exclusive");
138 acpi_pci_link_entry_dump(struct acpi_prt_entry
*entry
)
141 ACPI_RESOURCE_IRQ
*Irq
;
142 ACPI_RESOURCE_EXTENDED_IRQ
*ExtIrq
;
144 if (entry
== NULL
|| entry
->pci_link
== NULL
)
147 kprintf("%s irq %3d: ", acpi_name(entry
->pci_link
->handle
),
148 entry
->pci_link
->current_irq
);
151 for (i
= 0; i
< entry
->pci_link
->number_of_interrupts
; i
++)
152 kprintf("%3d", entry
->pci_link
->interrupts
[i
]);
155 switch (entry
->pci_link
->possible_resources
.Type
) {
156 case ACPI_RESOURCE_TYPE_IRQ
:
157 Irq
= &entry
->pci_link
->possible_resources
.Data
.Irq
;
158 acpi_pci_link_dump_polarity(Irq
->Polarity
);
159 acpi_pci_link_dump_trigger(Irq
->Triggering
);
160 acpi_pci_link_dump_sharemode(Irq
->Sharable
);
162 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ
:
163 ExtIrq
= &entry
->pci_link
->possible_resources
.Data
.ExtendedIrq
;
164 acpi_pci_link_dump_polarity(ExtIrq
->Polarity
);
165 acpi_pci_link_dump_trigger(ExtIrq
->Triggering
);
166 acpi_pci_link_dump_sharemode(ExtIrq
->Sharable
);
170 kprintf(" %d.%d.%d\n", entry
->busno
,
171 (int)((entry
->prt
.Address
& 0xffff0000) >> 16),
172 (int)entry
->prt
.Pin
);
176 acpi_pci_link_get_object_status(ACPI_HANDLE handle
, UINT32
*sta
)
178 ACPI_DEVICE_INFO
*devinfo
;
182 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__
);
184 if (handle
== NULL
|| sta
== NULL
) {
185 kprintf("invalid argument\n");
186 return_ACPI_STATUS (AE_BAD_PARAMETER
);
190 buf
.Length
= ACPI_ALLOCATE_BUFFER
;
191 error
= AcpiGetObjectInfo(handle
, &buf
);
192 if (ACPI_FAILURE(error
)) {
193 kprintf("couldn't get object info %s - %s\n",
194 acpi_name(handle
), AcpiFormatException(error
));
195 return_ACPI_STATUS (error
);
198 devinfo
= (ACPI_DEVICE_INFO
*)buf
.Pointer
;
199 if ((devinfo
->Valid
& ACPI_VALID_HID
) == 0 ||
200 strcmp(devinfo
->HardwareId
.Value
, "PNP0C0F") != 0) {
201 kprintf("invalid hardware ID - %s\n", acpi_name(handle
));
202 AcpiOsFree(buf
.Pointer
);
203 return_ACPI_STATUS (AE_TYPE
);
206 if ((devinfo
->Valid
& ACPI_VALID_STA
) != 0) {
207 *sta
= devinfo
->CurrentStatus
;
209 kprintf("invalid status - %s\n", acpi_name(handle
));
213 AcpiOsFree(buf
.Pointer
);
214 return_ACPI_STATUS (AE_OK
);
218 acpi_pci_link_get_irq_resources(ACPI_RESOURCE
*resources
,
219 UINT8
*number_of_interrupts
, UINT8 interrupts
[])
223 UINT32 InterruptCount
;
224 UINT32
*Interrupts32
;
227 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__
);
229 if (resources
== NULL
|| number_of_interrupts
== NULL
) {
230 kprintf("invalid argument\n");
231 return_ACPI_STATUS (AE_BAD_PARAMETER
);
234 *number_of_interrupts
= 0;
239 if (resources
->Type
== ACPI_RESOURCE_TYPE_START_DEPENDENT
)
240 resources
= ACPI_NEXT_RESOURCE(resources
);
242 if (resources
->Type
!= ACPI_RESOURCE_TYPE_IRQ
&&
243 resources
->Type
!= ACPI_RESOURCE_TYPE_EXTENDED_IRQ
) {
244 kprintf("Resource is not an IRQ entry - %d\n", resources
->Type
);
245 return_ACPI_STATUS (AE_TYPE
);
248 switch (resources
->Type
) {
249 case ACPI_RESOURCE_TYPE_IRQ
:
250 InterruptCount
= resources
->Data
.Irq
.InterruptCount
;
251 Interrupts8
= resources
->Data
.Irq
.Interrupts
;
253 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ
:
255 resources
->Data
.ExtendedIrq
.InterruptCount
;
256 Interrupts32
= resources
->Data
.ExtendedIrq
.Interrupts
;
260 if (InterruptCount
== 0) {
261 kprintf("Blank IRQ resource\n");
262 return_ACPI_STATUS (AE_NULL_ENTRY
);
266 for (i
= 0; i
< InterruptCount
; i
++) {
269 if (i
>= MAX_POSSIBLE_INTERRUPTS
) {
270 kprintf("too many IRQs (%d)\n", i
);
274 KKASSERT(Interrupts8
!= NULL
|| Interrupts32
!= NULL
);
275 if (Interrupts8
!= NULL
)
276 intr
= Interrupts8
[i
];
278 intr
= Interrupts32
[i
];
281 kprintf("invalid IRQ %d\n", intr
);
284 interrupts
[count
] = intr
;
287 *number_of_interrupts
= count
;
289 return_ACPI_STATUS (AE_OK
);
293 acpi_pci_link_get_current_irq(struct acpi_pci_link_entry
*link
, UINT8
*irq
)
297 ACPI_RESOURCE
*resources
;
298 UINT8 number_of_interrupts
;
299 UINT8 interrupts
[MAX_POSSIBLE_INTERRUPTS
];
301 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__
);
303 if (link
== NULL
|| irq
== NULL
) {
304 kprintf("invalid argument\n");
305 return_ACPI_STATUS (AE_BAD_PARAMETER
);
310 buf
.Length
= ACPI_ALLOCATE_BUFFER
;
311 error
= AcpiGetCurrentResources(link
->handle
, &buf
);
312 if (ACPI_FAILURE(error
)) {
313 kprintf("couldn't get PCI interrupt link device _CRS %s - %s\n",
314 acpi_name(link
->handle
), AcpiFormatException(error
));
315 return_ACPI_STATUS (error
);
317 if (buf
.Pointer
== NULL
) {
318 kprintf("couldn't allocate memory - %s\n",
319 acpi_name(link
->handle
));
320 return_ACPI_STATUS (AE_NO_MEMORY
);
323 resources
= (ACPI_RESOURCE
*) buf
.Pointer
;
324 number_of_interrupts
= 0;
325 bzero(interrupts
, sizeof(interrupts
));
326 error
= acpi_pci_link_get_irq_resources(resources
,
327 &number_of_interrupts
, interrupts
);
328 AcpiOsFree(buf
.Pointer
);
330 if (ACPI_FAILURE(error
)) {
331 kprintf("couldn't get current IRQ from "
332 "interrupt link %s - %s\n",
333 acpi_name(link
->handle
), AcpiFormatException(error
));
334 return_ACPI_STATUS (error
);
337 if (number_of_interrupts
== 0) {
338 kprintf("PCI interrupt link device _CRS data is corrupted - "
339 "%s\n", acpi_name(link
->handle
));
340 return_ACPI_STATUS (AE_NULL_ENTRY
);
343 *irq
= interrupts
[0];
345 return_ACPI_STATUS (AE_OK
);
349 acpi_pci_link_add_link(ACPI_HANDLE handle
, struct acpi_prt_entry
*entry
)
353 ACPI_RESOURCE
*resources
;
354 struct acpi_pci_link_entry
*link
;
356 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__
);
358 entry
->pci_link
= NULL
;
359 TAILQ_FOREACH(link
, &acpi_pci_link_entries
, links
) {
360 if (link
->handle
== handle
) {
361 entry
->pci_link
= link
;
363 return_ACPI_STATUS (AE_OK
);
367 link
= AcpiOsAllocate(sizeof(struct acpi_pci_link_entry
));
369 kprintf("couldn't allocate memory - %s\n", acpi_name(handle
));
370 return_ACPI_STATUS (AE_NO_MEMORY
);
374 buf
.Length
= ACPI_ALLOCATE_BUFFER
;
376 bzero(link
, sizeof(struct acpi_pci_link_entry
));
378 link
->handle
= handle
;
380 error
= acpi_pci_link_get_current_irq(link
, &link
->current_irq
);
381 if (ACPI_FAILURE(error
)) {
382 kprintf("couldn't get current IRQ from "
383 "interrupt link %s - %s\n",
384 acpi_name(handle
), AcpiFormatException(error
));
387 link
->initial_irq
= link
->current_irq
;
389 error
= AcpiGetPossibleResources(handle
, &buf
);
390 if (ACPI_FAILURE(error
)) {
391 kprintf("couldn't get interrupt link device _PRS "
393 acpi_name(handle
), AcpiFormatException(error
));
396 if (buf
.Pointer
== NULL
) {
397 kprintf("_PRS nuffer is empty - %s\n", acpi_name(handle
));
398 error
= AE_NO_MEMORY
;
402 resources
= (ACPI_RESOURCE
*) buf
.Pointer
;
403 bcopy(resources
, &link
->possible_resources
,
404 sizeof(link
->possible_resources
));
406 error
= acpi_pci_link_get_irq_resources(resources
,
407 &link
->number_of_interrupts
, link
->interrupts
);
408 if (ACPI_FAILURE(error
)) {
409 kprintf("couldn't get possible IRQs from "
410 "interrupt link %s - %s\n",
411 acpi_name(handle
), AcpiFormatException(error
));
415 if (link
->number_of_interrupts
== 0) {
416 kprintf("interrupt link device _PRS data is corrupted - %s\n",
418 error
= AE_NULL_ENTRY
;
424 TAILQ_INSERT_TAIL(&acpi_pci_link_entries
, link
, links
);
425 entry
->pci_link
= link
;
429 if (buf
.Pointer
!= NULL
)
430 AcpiOsFree(buf
.Pointer
);
431 if (error
!= AE_OK
&& link
!= NULL
)
434 return_ACPI_STATUS (error
);
438 acpi_pci_link_add_prt(device_t pcidev
, ACPI_PCI_ROUTING_TABLE
*prt
, int busno
)
443 struct acpi_prt_entry
*entry
;
445 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__
);
447 if (prt
== NULL
|| prt
->Source
== NULL
|| prt
->Source
[0] == '\0') {
448 kprintf("couldn't handle this routing table - hardwired\n");
449 return_ACPI_STATUS (AE_BAD_PARAMETER
);
452 error
= AcpiGetHandle(acpi_get_handle(pcidev
), prt
->Source
, &handle
);
453 if (ACPI_FAILURE(error
)) {
454 kprintf("couldn't get handle - %s\n",
455 AcpiFormatException(error
));
456 return_ACPI_STATUS (error
);
459 error
= acpi_pci_link_get_object_status(handle
, &sta
);
460 if (ACPI_FAILURE(error
)) {
461 kprintf("couldn't get object status %s - %s\n",
462 acpi_name(handle
), AcpiFormatException(error
));
463 return_ACPI_STATUS (error
);
466 if ((sta
& (ACPI_STA_PRESENT
| ACPI_STA_FUNCTIONAL
)) == 0) {
467 kprintf("interrupt link is not functional - %s\n",
469 return_ACPI_STATUS (AE_ERROR
);
472 TAILQ_FOREACH(entry
, &acpi_prt_entries
, links
) {
473 if (entry
->busno
== busno
&&
474 entry
->prt
.Address
== prt
->Address
&&
475 entry
->prt
.Pin
== prt
->Pin
) {
476 kprintf("interrupt link entry already exists - %s\n",
478 return_ACPI_STATUS (AE_ALREADY_EXISTS
);
482 entry
= AcpiOsAllocate(sizeof(struct acpi_prt_entry
));
484 kprintf("couldn't allocate memory - %s\n", acpi_name(handle
));
485 return_ACPI_STATUS (AE_NO_MEMORY
);
487 bzero(entry
, sizeof(struct acpi_prt_entry
));
489 entry
->pcidev
= pcidev
;
490 entry
->busno
= busno
;
491 bcopy(prt
, &entry
->prt
, sizeof(entry
->prt
));
493 error
= acpi_pci_link_add_link(handle
, entry
);
494 if (ACPI_FAILURE(error
)) {
495 kprintf("couldn't add _PRT entry to link %s - %s\n",
496 acpi_name(handle
), AcpiFormatException(error
));
500 TAILQ_INSERT_TAIL(&acpi_prt_entries
, entry
, links
);
504 if (error
!= AE_OK
&& entry
!= NULL
)
507 return_ACPI_STATUS (error
);
511 acpi_pci_link_is_valid_irq(struct acpi_pci_link_entry
*link
, UINT8 irq
)
518 for (i
= 0; i
< link
->number_of_interrupts
; i
++) {
519 if (link
->interrupts
[i
] == irq
)
523 /* allow initial IRQ as valid one. */
524 if (link
->initial_irq
== irq
)
531 acpi_pci_link_set_irq(struct acpi_pci_link_entry
*link
, UINT8 irq
)
534 ACPI_RESOURCE resbuf
;
538 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__
);
540 if (!acpi_pci_link_is_valid_irq(link
, irq
)) {
541 kprintf("couldn't set invalid IRQ %d - %s\n", irq
,
542 acpi_name(link
->handle
));
543 return_ACPI_STATUS (AE_BAD_PARAMETER
);
546 error
= acpi_pci_link_get_current_irq(link
, &link
->current_irq
);
547 if (ACPI_FAILURE(error
)) {
548 kprintf("couldn't get current IRQ from "
549 "interrupt link %s - %s\n",
550 acpi_name(link
->handle
), AcpiFormatException(error
));
553 if (link
->current_irq
== irq
)
554 return_ACPI_STATUS (AE_OK
);
556 bzero(&resbuf
, sizeof(resbuf
));
557 crsbuf
.Pointer
= NULL
;
559 switch (link
->possible_resources
.Type
) {
560 case ACPI_RESOURCE_TYPE_IRQ
:
561 resbuf
.Type
= ACPI_RESOURCE_TYPE_IRQ
;
562 resbuf
.Length
= sizeof(ACPI_RESOURCE_IRQ
);
564 /* structure copy other fields */
565 resbuf
.Data
.Irq
= link
->possible_resources
.Data
.Irq
;
566 resbuf
.Data
.Irq
.InterruptCount
= 1;
567 resbuf
.Data
.Irq
.Interrupts
[0] = irq
;
569 case ACPI_RESOURCE_TYPE_EXTENDED_IRQ
:
570 resbuf
.Type
= ACPI_RESOURCE_TYPE_EXTENDED_IRQ
;
571 resbuf
.Length
= sizeof(ACPI_RESOURCE_EXTENDED_IRQ
);
573 /* structure copy other fields */
574 resbuf
.Data
.ExtendedIrq
=
575 link
->possible_resources
.Data
.ExtendedIrq
;
576 resbuf
.Data
.ExtendedIrq
.InterruptCount
= 1;
577 resbuf
.Data
.ExtendedIrq
.Interrupts
[0] = irq
;
580 kprintf("Resource is not an IRQ entry %s - %d\n",
581 acpi_name(link
->handle
), link
->possible_resources
.Type
);
582 return_ACPI_STATUS (AE_TYPE
);
585 error
= acpi_AppendBufferResource(&crsbuf
, &resbuf
);
586 if (ACPI_FAILURE(error
)) {
587 kprintf("couldn't setup buffer by "
588 "acpi_AppendBufferResource - %s\n",
589 acpi_name(link
->handle
));
590 return_ACPI_STATUS (error
);
592 if (crsbuf
.Pointer
== NULL
) {
593 kprintf("appended buffer for %s is corrupted\n",
594 acpi_name(link
->handle
));
595 return_ACPI_STATUS (AE_NO_MEMORY
);
598 error
= AcpiSetCurrentResources(link
->handle
, &crsbuf
);
599 if (ACPI_FAILURE(error
)) {
600 kprintf("couldn't set link device _SRS %s - %s\n",
601 acpi_name(link
->handle
), AcpiFormatException(error
));
602 return_ACPI_STATUS (error
);
605 AcpiOsFree(crsbuf
.Pointer
);
606 link
->current_irq
= 0;
608 error
= acpi_pci_link_get_object_status(link
->handle
, &sta
);
609 if (ACPI_FAILURE(error
)) {
610 kprintf("couldn't get object status %s - %s\n",
611 acpi_name(link
->handle
), AcpiFormatException(error
));
612 return_ACPI_STATUS (error
);
615 if ((sta
& ACPI_STA_ENABLE
) == 0) {
616 kprintf("interrupt link %s is disabled\n",
617 acpi_name(link
->handle
));
618 return_ACPI_STATUS (AE_ERROR
);
621 error
= acpi_pci_link_get_current_irq(link
, &link
->current_irq
);
622 if (ACPI_FAILURE(error
)) {
623 kprintf("couldn't get current IRQ from "
624 "interrupt link %s - %s\n",
625 acpi_name(link
->handle
), AcpiFormatException(error
));
626 return_ACPI_STATUS (error
);
629 if (link
->current_irq
== irq
) {
632 kprintf("couldn't set IRQ %d to PCI interrupt link %d - %s\n",
633 irq
, link
->current_irq
, acpi_name(link
->handle
));
634 link
->current_irq
= 0;
638 return_ACPI_STATUS (error
);
642 * Auto arbitration for boot-disabled devices
646 acpi_pci_link_bootdisabled_dump(void)
650 struct acpi_pci_link_entry
*link
;
652 TAILQ_FOREACH(link
, &acpi_pci_link_entries
, links
) {
653 /* boot-disabled link only. */
654 if (link
->current_irq
!= 0)
657 kprintf("%s:\n", acpi_name(link
->handle
));
658 kprintf(" interrupts: ");
659 for (i
= 0; i
< link
->number_of_interrupts
; i
++) {
660 irq
= link
->sorted_irq
[i
];
664 kprintf(" penalty: ");
665 for (i
= 0; i
< link
->number_of_interrupts
; i
++) {
666 irq
= link
->sorted_irq
[i
];
667 kprintf("%6d", irq_penalty
[irq
]);
670 kprintf(" references: %d\n", link
->references
);
671 kprintf(" priority: %d\n", link
->priority
);
676 acpi_pci_link_init_irq_penalty(void)
680 bzero(irq_penalty
, sizeof(irq_penalty
));
681 for (irq
= 0; irq
< MAX_ISA_INTERRUPTS
; irq
++) {
682 /* 0, 1, 2, 8: timer, keyboard, cascade */
683 if (irq
== 0 || irq
== 1 || irq
== 2 || irq
== 8) {
684 irq_penalty
[irq
] = 100000;
688 /* 13, 14, 15: npx, ATA controllers */
689 if (irq
== 13 || irq
== 14 || irq
== 15) {
690 irq_penalty
[irq
] = 10000;
694 /* 3,4,6,7,12: typicially used by legacy hardware */
695 if (irq
== 3 || irq
== 4 || irq
== 6 || irq
== 7 || irq
== 12) {
696 irq_penalty
[irq
] = 1000;
703 link_exclusive(ACPI_RESOURCE
*res
)
706 (res
->Type
!= ACPI_RESOURCE_TYPE_IRQ
&&
707 res
->Type
!= ACPI_RESOURCE_TYPE_EXTENDED_IRQ
))
710 if ((res
->Type
== ACPI_RESOURCE_TYPE_IRQ
&&
711 res
->Data
.Irq
.Sharable
== ACPI_EXCLUSIVE
) ||
712 (res
->Type
== ACPI_RESOURCE_TYPE_EXTENDED_IRQ
&&
713 res
->Data
.ExtendedIrq
.Sharable
== ACPI_EXCLUSIVE
))
720 acpi_pci_link_update_irq_penalty(device_t dev
, int busno
)
725 struct resource
*res
;
726 struct acpi_prt_entry
*entry
;
727 struct acpi_pci_link_entry
*link
;
729 TAILQ_FOREACH(entry
, &acpi_prt_entries
, links
) {
730 if (entry
->busno
!= busno
)
734 link
= entry
->pci_link
;
738 if (link
->current_irq
!= 0) {
739 /* not boot-disabled link, we will use this IRQ. */
740 irq_penalty
[link
->current_irq
] += 100;
744 /* boot-disabled link */
745 for (i
= 0; i
< link
->number_of_interrupts
; i
++) {
746 /* give 10 for each possible IRQs. */
747 irq
= link
->interrupts
[i
];
748 irq_penalty
[irq
] += 10;
750 /* higher penalty if exclusive. */
751 if (link_exclusive(&link
->possible_resources
))
752 irq_penalty
[irq
] += 100;
754 /* XXX try to get this IRQ in non-sharable mode. */
756 res
= bus_alloc_resource(dev
, SYS_RES_IRQ
,
757 &rid
, irq
, irq
, 1, 0);
759 bus_release_resource(dev
, SYS_RES_IRQ
,
762 /* this is in use, give 100. */
763 irq_penalty
[irq
] += 100;
767 /* initialize `sorted' possible IRQs. */
768 bcopy(link
->interrupts
, link
->sorted_irq
,
769 sizeof(link
->sorted_irq
));
774 acpi_pci_link_set_bootdisabled_priority(void)
779 struct acpi_pci_link_entry
*link
, *link_pri
;
780 TAILQ_HEAD(, acpi_pci_link_entry
) sorted_list
;
783 kprintf("ACPI PCI link before setting link priority:\n");
784 acpi_pci_link_bootdisabled_dump();
787 /* reset priority for all links. */
788 TAILQ_FOREACH(link
, &acpi_pci_link_entries
, links
)
791 TAILQ_FOREACH(link
, &acpi_pci_link_entries
, links
) {
792 /* not boot-disabled link, give no chance to be arbitrated. */
793 if (link
->current_irq
!= 0) {
799 * Calculate the priority for each boot-disabled links.
800 * o IRQ penalty indicates difficulty to use.
801 * o #references for devices indicates importance of the link.
802 * o #interrupts indicates flexibility of the link.
805 for (i
= 0; i
< link
->number_of_interrupts
; i
++) {
806 irq
= link
->interrupts
[i
];
807 sum_penalty
+= irq_penalty
[irq
];
810 link
->priority
= (sum_penalty
* link
->references
) /
811 link
->number_of_interrupts
;
815 * Sort PCI links based on the priority.
816 * XXX Any other better ways rather than using work list?
818 TAILQ_INIT(&sorted_list
);
819 while (!TAILQ_EMPTY(&acpi_pci_link_entries
)) {
820 link
= TAILQ_FIRST(&acpi_pci_link_entries
);
821 /* find an entry which has the highest priority. */
822 TAILQ_FOREACH(link_pri
, &acpi_pci_link_entries
, links
)
823 if (link
->priority
< link_pri
->priority
)
826 /* move to work list. */
827 TAILQ_REMOVE(&acpi_pci_link_entries
, link
, links
);
828 TAILQ_INSERT_TAIL(&sorted_list
, link
, links
);
831 while (!TAILQ_EMPTY(&sorted_list
)) {
832 /* move them back to the list, one by one... */
833 link
= TAILQ_FIRST(&sorted_list
);
834 TAILQ_REMOVE(&sorted_list
, link
, links
);
835 TAILQ_INSERT_TAIL(&acpi_pci_link_entries
, link
, links
);
840 acpi_pci_link_fixup_bootdisabled_link(void)
844 struct acpi_pci_link_entry
*link
;
848 kprintf("ACPI PCI link before fixup for boot-disabled links:\n");
849 acpi_pci_link_bootdisabled_dump();
852 TAILQ_FOREACH(link
, &acpi_pci_link_entries
, links
) {
853 /* ignore non boot-disabled links. */
854 if (link
->current_irq
!= 0)
857 /* sort IRQs based on their penalty descending. */
858 for (i
= 0; i
< link
->number_of_interrupts
; i
++) {
859 irq1
= link
->sorted_irq
[i
];
860 for (j
= i
+ 1; j
< link
->number_of_interrupts
; j
++) {
861 irq2
= link
->sorted_irq
[j
];
862 if (irq_penalty
[irq1
] < irq_penalty
[irq2
]) {
865 link
->sorted_irq
[i
] = irq2
;
866 link
->sorted_irq
[j
] = irq1
;
871 /* try with lower penalty IRQ. */
872 for (i
= 0; i
< link
->number_of_interrupts
; i
++) {
873 irq1
= link
->sorted_irq
[i
];
874 error
= acpi_pci_link_set_irq(link
, irq1
);
875 if (error
== AE_OK
) {
876 /* OK, we use this. give another penalty. */
877 irq_penalty
[irq1
] += 100 * link
->references
;
884 kprintf("ACPI PCI link after fixup for boot-disabled links:\n");
885 acpi_pci_link_bootdisabled_dump();
894 acpi_pci_link_config(device_t dev
, ACPI_BUFFER
*prtbuf
, int busno
)
896 struct acpi_prt_entry
*entry
;
897 ACPI_PCI_ROUTING_TABLE
*prt
;
900 static int first_time
=1;
902 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__
);
904 if (acpi_disabled("pci_link"))
908 TAILQ_INIT(&acpi_prt_entries
);
909 TAILQ_INIT(&acpi_pci_link_entries
);
910 acpi_pci_link_init_irq_penalty();
917 prtp
= prtbuf
->Pointer
;
918 if (prtp
== NULL
) /* didn't get routing table */
921 /* scan the PCI Routing Table */
923 prt
= (ACPI_PCI_ROUTING_TABLE
*)prtp
;
925 if (prt
->Length
== 0) /* end of table */
928 error
= acpi_pci_link_add_prt(dev
, prt
, busno
);
929 if (ACPI_FAILURE(error
)) {
930 kprintf("couldn't add PCI interrupt link entry - %s\n",
931 AcpiFormatException(error
));
934 /* skip to next entry */
939 kprintf("ACPI PCI link initial configuration:\n");
940 TAILQ_FOREACH(entry
, &acpi_prt_entries
, links
) {
941 if (entry
->busno
!= busno
)
943 acpi_pci_link_entry_dump(entry
);
947 /* manual configuration. */
948 TAILQ_FOREACH(entry
, &acpi_prt_entries
, links
) {
952 if (entry
->busno
!= busno
)
955 ksnprintf(prthint
, sizeof(prthint
),
956 "hw.acpi.pci.link.%d.%d.%d.irq", entry
->busno
,
957 (int)((entry
->prt
.Address
& 0xffff0000) >> 16),
958 (int)entry
->prt
.Pin
);
960 if (kgetenv_int(prthint
, &irq
) == 0)
963 if (acpi_pci_link_is_valid_irq(entry
->pci_link
, irq
)) {
964 error
= acpi_pci_link_set_irq(entry
->pci_link
, irq
);
965 if (ACPI_FAILURE(error
)) {
966 kprintf("couldn't set IRQ to "
967 "link entry %s - %s\n",
968 acpi_name(entry
->pci_link
->handle
),
969 AcpiFormatException(error
));
975 * Do auto arbitration for this device's PCI link
976 * if hint value 0 is specified.
979 entry
->pci_link
->current_irq
= 0;
982 /* auto arbitration */
983 acpi_pci_link_update_irq_penalty(dev
, busno
);
984 acpi_pci_link_set_bootdisabled_priority();
985 acpi_pci_link_fixup_bootdisabled_link();
988 kprintf("ACPI PCI link arbitrated configuration:\n");
989 TAILQ_FOREACH(entry
, &acpi_prt_entries
, links
) {
990 if (entry
->busno
!= busno
)
992 acpi_pci_link_entry_dump(entry
);
1000 acpi_pci_link_resume(device_t dev
, ACPI_BUFFER
*prtbuf
, int busno
)
1002 struct acpi_prt_entry
*entry
;
1005 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__
);
1007 if (acpi_disabled("pci_link"))
1010 TAILQ_FOREACH(entry
, &acpi_prt_entries
, links
) {
1011 if (entry
->pcidev
!= dev
)
1014 error
= acpi_pci_link_set_irq(entry
->pci_link
,
1015 entry
->pci_link
->current_irq
);
1016 if (ACPI_FAILURE(error
)) {
1017 kprintf("couldn't set IRQ to link entry %s - %s\n",
1018 acpi_name(entry
->pci_link
->handle
),
1019 AcpiFormatException(error
));