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>
36 #include <dev/acpica5/acpivar.h>
37 #include <dev/acpica5/acpi_pcibvar.h>
39 /* Hooks for the ACPI CA debugging infrastructure. */
40 #define _COMPONENT ACPI_BUS
41 ACPI_MODULE_NAME("PCI_LINK")
43 #define MAX_POSSIBLE_INTERRUPTS 16
44 #define MAX_ISA_INTERRUPTS 16
45 #define MAX_ACPI_INTERRUPTS 255
47 struct acpi_pci_link_entry
{
48 TAILQ_ENTRY(acpi_pci_link_entry
) links
;
52 ACPI_RESOURCE possible_resources
;
53 UINT8 number_of_interrupts
;
54 UINT8 interrupts
[MAX_POSSIBLE_INTERRUPTS
];
55 UINT8 sorted_irq
[MAX_POSSIBLE_INTERRUPTS
];
60 TAILQ_HEAD(acpi_pci_link_entries
, acpi_pci_link_entry
);
61 static struct acpi_pci_link_entries acpi_pci_link_entries
;
63 struct acpi_prt_entry
{
64 TAILQ_ENTRY(acpi_prt_entry
) links
;
67 ACPI_PCI_ROUTING_TABLE prt
;
68 struct acpi_pci_link_entry
*pci_link
;
71 TAILQ_HEAD(acpi_prt_entries
, acpi_prt_entry
);
72 static struct acpi_prt_entries acpi_prt_entries
;
74 static int irq_penalty
[MAX_ACPI_INTERRUPTS
];
76 #define ACPI_STA_PRESENT 0x00000001
77 #define ACPI_STA_ENABLE 0x00000002
78 #define ACPI_STA_SHOWINUI 0x00000004
79 #define ACPI_STA_FUNCTIONAL 0x00000008
82 * PCI link object management
86 acpi_pci_link_dump_polarity(UINT32 ActiveHighLow
)
89 switch (ActiveHighLow
) {
90 case ACPI_ACTIVE_HIGH
:
103 acpi_pci_link_dump_trigger(UINT32 EdgeLevel
)
107 case ACPI_EDGE_SENSITIVE
:
110 case ACPI_LEVEL_SENSITIVE
:
120 acpi_pci_link_dump_sharemode(UINT32 SharedExclusive
)
123 switch (SharedExclusive
) {
125 kprintf("exclusive");
137 acpi_pci_link_entry_dump(struct acpi_prt_entry
*entry
)
140 ACPI_RESOURCE_IRQ
*Irq
;
141 ACPI_RESOURCE_EXT_IRQ
*ExtIrq
;
143 if (entry
== NULL
|| entry
->pci_link
== NULL
)
146 kprintf("%s irq %3d: ", acpi_name(entry
->pci_link
->handle
),
147 entry
->pci_link
->current_irq
);
150 for (i
= 0; i
< entry
->pci_link
->number_of_interrupts
; i
++)
151 kprintf("%3d", entry
->pci_link
->interrupts
[i
]);
154 switch (entry
->pci_link
->possible_resources
.Id
) {
155 case ACPI_RSTYPE_IRQ
:
156 Irq
= &entry
->pci_link
->possible_resources
.Data
.Irq
;
157 acpi_pci_link_dump_polarity(Irq
->ActiveHighLow
);
158 acpi_pci_link_dump_trigger(Irq
->EdgeLevel
);
159 acpi_pci_link_dump_sharemode(Irq
->SharedExclusive
);
161 case ACPI_RSTYPE_EXT_IRQ
:
162 ExtIrq
= &entry
->pci_link
->possible_resources
.Data
.ExtendedIrq
;
163 acpi_pci_link_dump_polarity(ExtIrq
->ActiveHighLow
);
164 acpi_pci_link_dump_trigger(ExtIrq
->EdgeLevel
);
165 acpi_pci_link_dump_sharemode(ExtIrq
->SharedExclusive
);
169 kprintf(" %d.%d.%d\n", entry
->busno
,
170 (int)((entry
->prt
.Address
& 0xffff0000) >> 16),
171 (int)entry
->prt
.Pin
);
175 acpi_pci_link_get_object_status(ACPI_HANDLE handle
, UINT32
*sta
)
177 ACPI_DEVICE_INFO
*devinfo
;
181 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__
);
183 if (handle
== NULL
|| sta
== NULL
) {
184 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
, "invalid argument\n"));
185 return_ACPI_STATUS (AE_BAD_PARAMETER
);
189 buf
.Length
= ACPI_ALLOCATE_BUFFER
;
190 error
= AcpiGetObjectInfo(handle
, &buf
);
191 if (ACPI_FAILURE(error
)) {
192 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
,
193 "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 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
, "invalid hardware ID - %s\n",
203 AcpiOsFree(buf
.Pointer
);
204 return_ACPI_STATUS (AE_TYPE
);
207 if ((devinfo
->Valid
& ACPI_VALID_STA
) != 0) {
208 *sta
= devinfo
->CurrentStatus
;
210 ACPI_DEBUG_PRINT((ACPI_DB_WARN
, "invalid status - %s\n",
215 AcpiOsFree(buf
.Pointer
);
216 return_ACPI_STATUS (AE_OK
);
220 acpi_pci_link_get_irq_resources(ACPI_RESOURCE
*resources
,
221 UINT8
*number_of_interrupts
, UINT8 interrupts
[])
225 UINT32 NumberOfInterrupts
;
228 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__
);
230 if (resources
== NULL
|| number_of_interrupts
== NULL
) {
231 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
, "invalid argument\n"));
232 return_ACPI_STATUS (AE_BAD_PARAMETER
);
235 *number_of_interrupts
= 0;
236 NumberOfInterrupts
= 0;
239 if (resources
->Id
== ACPI_RSTYPE_START_DPF
)
240 resources
= ACPI_NEXT_RESOURCE(resources
);
242 if (resources
->Id
!= ACPI_RSTYPE_IRQ
&&
243 resources
->Id
!= ACPI_RSTYPE_EXT_IRQ
) {
244 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
,
245 "Resource is not an IRQ entry - %d\n", resources
->Id
));
246 return_ACPI_STATUS (AE_TYPE
);
249 switch (resources
->Id
) {
250 case ACPI_RSTYPE_IRQ
:
251 NumberOfInterrupts
= resources
->Data
.Irq
.NumberOfInterrupts
;
252 Interrupts
= resources
->Data
.Irq
.Interrupts
;
254 case ACPI_RSTYPE_EXT_IRQ
:
256 resources
->Data
.ExtendedIrq
.NumberOfInterrupts
;
257 Interrupts
= resources
->Data
.ExtendedIrq
.Interrupts
;
261 if (NumberOfInterrupts
== 0) {
262 ACPI_DEBUG_PRINT((ACPI_DB_WARN
, "Blank IRQ resource\n"));
263 return_ACPI_STATUS (AE_NULL_ENTRY
);
267 for (i
= 0; i
< NumberOfInterrupts
; i
++) {
268 if (i
>= MAX_POSSIBLE_INTERRUPTS
) {
269 ACPI_DEBUG_PRINT((ACPI_DB_WARN
, "too many IRQs (%d)\n",
273 if (Interrupts
[i
] == 0) {
274 ACPI_DEBUG_PRINT((ACPI_DB_WARN
, "invalid IRQ %d\n",
278 interrupts
[count
] = Interrupts
[i
];
281 *number_of_interrupts
= count
;
283 return_ACPI_STATUS (AE_OK
);
287 acpi_pci_link_get_current_irq(struct acpi_pci_link_entry
*link
, UINT8
*irq
)
291 ACPI_RESOURCE
*resources
;
292 UINT8 number_of_interrupts
;
293 UINT8 interrupts
[MAX_POSSIBLE_INTERRUPTS
];
295 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__
);
297 if (link
== NULL
|| irq
== NULL
) {
298 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
, "invalid argument\n"));
299 return_ACPI_STATUS (AE_BAD_PARAMETER
);
304 buf
.Length
= ACPI_ALLOCATE_BUFFER
;
305 error
= AcpiGetCurrentResources(link
->handle
, &buf
);
306 if (ACPI_FAILURE(error
)) {
307 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
,
308 "couldn't get PCI interrupt link device _CRS %s - %s\n",
309 acpi_name(link
->handle
), AcpiFormatException(error
)));
310 return_ACPI_STATUS (error
);
312 if (buf
.Pointer
== NULL
) {
313 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
,
314 "couldn't allocate memory - %s\n",
315 acpi_name(link
->handle
)));
316 return_ACPI_STATUS (AE_NO_MEMORY
);
319 resources
= (ACPI_RESOURCE
*) buf
.Pointer
;
320 number_of_interrupts
= 0;
321 bzero(interrupts
, sizeof(interrupts
));
322 error
= acpi_pci_link_get_irq_resources(resources
,
323 &number_of_interrupts
, interrupts
);
324 AcpiOsFree(buf
.Pointer
);
326 if (ACPI_FAILURE(error
)) {
327 ACPI_DEBUG_PRINT((ACPI_DB_WARN
,
328 "couldn't get current IRQ from interrupt link %s - %s\n",
329 acpi_name(link
->handle
), AcpiFormatException(error
)));
330 return_ACPI_STATUS (error
);
333 if (number_of_interrupts
== 0) {
334 ACPI_DEBUG_PRINT((ACPI_DB_WARN
,
335 "PCI interrupt link device _CRS data is corrupted - %s\n",
336 acpi_name(link
->handle
)));
337 return_ACPI_STATUS (AE_NULL_ENTRY
);
340 *irq
= interrupts
[0];
342 return_ACPI_STATUS (AE_OK
);
346 acpi_pci_link_add_link(ACPI_HANDLE handle
, struct acpi_prt_entry
*entry
)
350 ACPI_RESOURCE
*resources
;
351 struct acpi_pci_link_entry
*link
;
353 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__
);
355 entry
->pci_link
= NULL
;
356 TAILQ_FOREACH(link
, &acpi_pci_link_entries
, links
) {
357 if (link
->handle
== handle
) {
358 entry
->pci_link
= link
;
360 return_ACPI_STATUS (AE_OK
);
364 link
= AcpiOsAllocate(sizeof(struct acpi_pci_link_entry
));
366 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
,
367 "couldn't allocate memory - %s\n", acpi_name(handle
)));
368 return_ACPI_STATUS (AE_NO_MEMORY
);
372 buf
.Length
= ACPI_ALLOCATE_BUFFER
;
374 bzero(link
, sizeof(struct acpi_pci_link_entry
));
376 link
->handle
= handle
;
378 error
= acpi_pci_link_get_current_irq(link
, &link
->current_irq
);
379 if (ACPI_FAILURE(error
)) {
380 ACPI_DEBUG_PRINT((ACPI_DB_WARN
,
381 "couldn't get current IRQ from interrupt link %s - %s\n",
382 acpi_name(handle
), AcpiFormatException(error
)));
385 link
->initial_irq
= link
->current_irq
;
387 error
= AcpiGetPossibleResources(handle
, &buf
);
388 if (ACPI_FAILURE(error
)) {
389 ACPI_DEBUG_PRINT((ACPI_DB_WARN
,
390 "couldn't get interrupt link device _PRS data %s - %s\n",
391 acpi_name(handle
), AcpiFormatException(error
)));
394 if (buf
.Pointer
== NULL
) {
395 ACPI_DEBUG_PRINT((ACPI_DB_WARN
,
396 "_PRS nuffer is empty - %s\n", acpi_name(handle
)));
397 error
= AE_NO_MEMORY
;
401 resources
= (ACPI_RESOURCE
*) buf
.Pointer
;
402 bcopy(resources
, &link
->possible_resources
,
403 sizeof(link
->possible_resources
));
405 error
= acpi_pci_link_get_irq_resources(resources
,
406 &link
->number_of_interrupts
, link
->interrupts
);
407 if (ACPI_FAILURE(error
)) {
408 ACPI_DEBUG_PRINT((ACPI_DB_WARN
,
409 "couldn't get possible IRQs from interrupt link %s - %s\n",
410 acpi_name(handle
), AcpiFormatException(error
)));
414 if (link
->number_of_interrupts
== 0) {
415 ACPI_DEBUG_PRINT((ACPI_DB_WARN
,
416 "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 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
,
449 "couldn't handle this routing table - hardwired\n"));
450 return_ACPI_STATUS (AE_BAD_PARAMETER
);
453 error
= AcpiGetHandle(acpi_get_handle(pcidev
), prt
->Source
, &handle
);
454 if (ACPI_FAILURE(error
)) {
455 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
, "couldn't get handle - %s\n",
456 AcpiFormatException(error
)));
457 return_ACPI_STATUS (error
);
460 error
= acpi_pci_link_get_object_status(handle
, &sta
);
461 if (ACPI_FAILURE(error
)) {
462 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
,
463 "couldn't get object status %s - %s\n",
464 acpi_name(handle
), AcpiFormatException(error
)));
465 return_ACPI_STATUS (error
);
468 if ((sta
& (ACPI_STA_PRESENT
| ACPI_STA_FUNCTIONAL
)) == 0) {
469 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
,
470 "interrupt link is not functional - %s\n",
472 return_ACPI_STATUS (AE_ERROR
);
475 TAILQ_FOREACH(entry
, &acpi_prt_entries
, links
) {
476 if (entry
->busno
== busno
&&
477 entry
->prt
.Address
== prt
->Address
&&
478 entry
->prt
.Pin
== prt
->Pin
) {
479 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
,
480 "interrupt link entry already exists - %s\n",
482 return_ACPI_STATUS (AE_ALREADY_EXISTS
);
486 entry
= AcpiOsAllocate(sizeof(struct acpi_prt_entry
));
488 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
,
489 "couldn't allocate memory - %s\n", acpi_name(handle
)));
490 return_ACPI_STATUS (AE_NO_MEMORY
);
492 bzero(entry
, sizeof(struct acpi_prt_entry
));
494 entry
->pcidev
= pcidev
;
495 entry
->busno
= busno
;
496 bcopy(prt
, &entry
->prt
, sizeof(entry
->prt
));
498 error
= acpi_pci_link_add_link(handle
, entry
);
499 if (ACPI_FAILURE(error
)) {
500 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
,
501 "couldn't add _PRT entry to link %s - %s\n",
502 acpi_name(handle
), AcpiFormatException(error
)));
506 TAILQ_INSERT_TAIL(&acpi_prt_entries
, entry
, links
);
510 if (error
!= AE_OK
&& entry
!= NULL
)
513 return_ACPI_STATUS (error
);
517 acpi_pci_link_is_valid_irq(struct acpi_pci_link_entry
*link
, UINT8 irq
)
524 for (i
= 0; i
< link
->number_of_interrupts
; i
++) {
525 if (link
->interrupts
[i
] == irq
)
529 /* allow initial IRQ as valid one. */
530 if (link
->initial_irq
== irq
)
537 acpi_pci_link_set_irq(struct acpi_pci_link_entry
*link
, UINT8 irq
)
540 ACPI_RESOURCE resbuf
;
544 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__
);
546 if (!acpi_pci_link_is_valid_irq(link
, irq
)) {
547 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
,
548 "couldn't set invalid IRQ %d - %s\n", irq
,
549 acpi_name(link
->handle
)));
550 return_ACPI_STATUS (AE_BAD_PARAMETER
);
553 error
= acpi_pci_link_get_current_irq(link
, &link
->current_irq
);
554 if (ACPI_FAILURE(error
)) {
555 ACPI_DEBUG_PRINT((ACPI_DB_WARN
,
556 "couldn't get current IRQ from interrupt link %s - %s\n",
557 acpi_name(link
->handle
), AcpiFormatException(error
)));
560 if (link
->current_irq
== irq
)
561 return_ACPI_STATUS (AE_OK
);
563 bzero(&resbuf
, sizeof(resbuf
));
564 crsbuf
.Pointer
= NULL
;
566 switch (link
->possible_resources
.Id
) {
567 case ACPI_RSTYPE_IRQ
:
568 resbuf
.Id
= ACPI_RSTYPE_IRQ
;
569 resbuf
.Length
= ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_IRQ
);
571 /* structure copy other fields */
572 resbuf
.Data
.Irq
= link
->possible_resources
.Data
.Irq
;
573 resbuf
.Data
.Irq
.NumberOfInterrupts
= 1;
574 resbuf
.Data
.Irq
.Interrupts
[0] = irq
;
576 case ACPI_RSTYPE_EXT_IRQ
:
577 resbuf
.Id
= ACPI_RSTYPE_EXT_IRQ
;
578 resbuf
.Length
= ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_EXT_IRQ
);
580 /* structure copy other fields */
581 resbuf
.Data
.ExtendedIrq
=
582 link
->possible_resources
.Data
.ExtendedIrq
;
583 resbuf
.Data
.ExtendedIrq
.NumberOfInterrupts
= 1;
584 resbuf
.Data
.ExtendedIrq
.Interrupts
[0] = irq
;
587 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
,
588 "Resource is not an IRQ entry %s - %d\n",
589 acpi_name(link
->handle
), link
->possible_resources
.Id
));
590 return_ACPI_STATUS (AE_TYPE
);
593 error
= acpi_AppendBufferResource(&crsbuf
, &resbuf
);
594 if (ACPI_FAILURE(error
)) {
595 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
,
596 "couldn't setup buffer by acpi_AppendBufferResource - %s\n",
597 acpi_name(link
->handle
)));
598 return_ACPI_STATUS (error
);
600 if (crsbuf
.Pointer
== NULL
) {
601 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
,
602 "appended buffer for %s is corrupted\n",
603 acpi_name(link
->handle
)));
604 return_ACPI_STATUS (AE_NO_MEMORY
);
607 error
= AcpiSetCurrentResources(link
->handle
, &crsbuf
);
608 if (ACPI_FAILURE(error
)) {
609 ACPI_DEBUG_PRINT((ACPI_DB_WARN
,
610 "couldn't set link device _SRS %s - %s\n",
611 acpi_name(link
->handle
), AcpiFormatException(error
)));
612 return_ACPI_STATUS (error
);
615 AcpiOsFree(crsbuf
.Pointer
);
616 link
->current_irq
= 0;
618 error
= acpi_pci_link_get_object_status(link
->handle
, &sta
);
619 if (ACPI_FAILURE(error
)) {
620 ACPI_DEBUG_PRINT((ACPI_DB_WARN
,
621 "couldn't get object status %s - %s\n",
622 acpi_name(link
->handle
), AcpiFormatException(error
)));
623 return_ACPI_STATUS (error
);
626 if ((sta
& ACPI_STA_ENABLE
) == 0) {
627 ACPI_DEBUG_PRINT((ACPI_DB_WARN
,
628 "interrupt link %s is disabled\n",
629 acpi_name(link
->handle
)));
630 return_ACPI_STATUS (AE_ERROR
);
633 error
= acpi_pci_link_get_current_irq(link
, &link
->current_irq
);
634 if (ACPI_FAILURE(error
)) {
635 ACPI_DEBUG_PRINT((ACPI_DB_WARN
,
636 "couldn't get current IRQ from interrupt link %s - %s\n",
637 acpi_name(link
->handle
), AcpiFormatException(error
)));
638 return_ACPI_STATUS (error
);
641 if (link
->current_irq
== irq
) {
644 ACPI_DEBUG_PRINT((ACPI_DB_WARN
,
645 "couldn't set IRQ %d to PCI interrupt link %d - %s\n",
646 irq
, link
->current_irq
, acpi_name(link
->handle
)));
647 link
->current_irq
= 0;
651 return_ACPI_STATUS (error
);
655 * Auto arbitration for boot-disabled devices
659 acpi_pci_link_bootdisabled_dump(void)
663 struct acpi_pci_link_entry
*link
;
665 TAILQ_FOREACH(link
, &acpi_pci_link_entries
, links
) {
666 /* boot-disabled link only. */
667 if (link
->current_irq
!= 0)
670 kprintf("%s:\n", acpi_name(link
->handle
));
671 kprintf(" interrupts: ");
672 for (i
= 0; i
< link
->number_of_interrupts
; i
++) {
673 irq
= link
->sorted_irq
[i
];
677 kprintf(" penalty: ");
678 for (i
= 0; i
< link
->number_of_interrupts
; i
++) {
679 irq
= link
->sorted_irq
[i
];
680 kprintf("%6d", irq_penalty
[irq
]);
683 kprintf(" references: %d\n", link
->references
);
684 kprintf(" priority: %d\n", link
->priority
);
689 acpi_pci_link_init_irq_penalty(void)
693 bzero(irq_penalty
, sizeof(irq_penalty
));
694 for (irq
= 0; irq
< MAX_ISA_INTERRUPTS
; irq
++) {
695 /* 0, 1, 2, 8: timer, keyboard, cascade */
696 if (irq
== 0 || irq
== 1 || irq
== 2 || irq
== 8) {
697 irq_penalty
[irq
] = 100000;
701 /* 13, 14, 15: npx, ATA controllers */
702 if (irq
== 13 || irq
== 14 || irq
== 15) {
703 irq_penalty
[irq
] = 10000;
707 /* 3,4,6,7,12: typicially used by legacy hardware */
708 if (irq
== 3 || irq
== 4 || irq
== 6 || irq
== 7 || irq
== 12) {
709 irq_penalty
[irq
] = 1000;
716 link_exclusive(ACPI_RESOURCE
*res
)
719 (res
->Id
!= ACPI_RSTYPE_IRQ
&&
720 res
->Id
!= ACPI_RSTYPE_EXT_IRQ
))
723 if ((res
->Id
== ACPI_RSTYPE_IRQ
&&
724 res
->Data
.Irq
.SharedExclusive
== ACPI_EXCLUSIVE
) ||
725 (res
->Id
== ACPI_RSTYPE_EXT_IRQ
&&
726 res
->Data
.ExtendedIrq
.SharedExclusive
== ACPI_EXCLUSIVE
))
733 acpi_pci_link_update_irq_penalty(device_t dev
, int busno
)
738 struct resource
*res
;
739 struct acpi_prt_entry
*entry
;
740 struct acpi_pci_link_entry
*link
;
742 TAILQ_FOREACH(entry
, &acpi_prt_entries
, links
) {
743 if (entry
->busno
!= busno
)
747 link
= entry
->pci_link
;
751 if (link
->current_irq
!= 0) {
752 /* not boot-disabled link, we will use this IRQ. */
753 irq_penalty
[link
->current_irq
] += 100;
757 /* boot-disabled link */
758 for (i
= 0; i
< link
->number_of_interrupts
; i
++) {
759 /* give 10 for each possible IRQs. */
760 irq
= link
->interrupts
[i
];
761 irq_penalty
[irq
] += 10;
763 /* higher penalty if exclusive. */
764 if (link_exclusive(&link
->possible_resources
))
765 irq_penalty
[irq
] += 100;
767 /* XXX try to get this IRQ in non-sharable mode. */
769 res
= bus_alloc_resource(dev
, SYS_RES_IRQ
,
770 &rid
, irq
, irq
, 1, 0);
772 bus_release_resource(dev
, SYS_RES_IRQ
,
775 /* this is in use, give 100. */
776 irq_penalty
[irq
] += 100;
780 /* initialize `sorted' possible IRQs. */
781 bcopy(link
->interrupts
, link
->sorted_irq
,
782 sizeof(link
->sorted_irq
));
787 acpi_pci_link_set_bootdisabled_priority(void)
792 struct acpi_pci_link_entry
*link
, *link_pri
;
793 TAILQ_HEAD(, acpi_pci_link_entry
) sorted_list
;
796 kprintf("ACPI PCI link before setting link priority:\n");
797 acpi_pci_link_bootdisabled_dump();
800 /* reset priority for all links. */
801 TAILQ_FOREACH(link
, &acpi_pci_link_entries
, links
)
804 TAILQ_FOREACH(link
, &acpi_pci_link_entries
, links
) {
805 /* not boot-disabled link, give no chance to be arbitrated. */
806 if (link
->current_irq
!= 0) {
812 * Calculate the priority for each boot-disabled links.
813 * o IRQ penalty indicates difficulty to use.
814 * o #references for devices indicates importance of the link.
815 * o #interrupts indicates flexibility of the link.
818 for (i
= 0; i
< link
->number_of_interrupts
; i
++) {
819 irq
= link
->interrupts
[i
];
820 sum_penalty
+= irq_penalty
[irq
];
823 link
->priority
= (sum_penalty
* link
->references
) /
824 link
->number_of_interrupts
;
828 * Sort PCI links based on the priority.
829 * XXX Any other better ways rather than using work list?
831 TAILQ_INIT(&sorted_list
);
832 while (!TAILQ_EMPTY(&acpi_pci_link_entries
)) {
833 link
= TAILQ_FIRST(&acpi_pci_link_entries
);
834 /* find an entry which has the highest priority. */
835 TAILQ_FOREACH(link_pri
, &acpi_pci_link_entries
, links
)
836 if (link
->priority
< link_pri
->priority
)
839 /* move to work list. */
840 TAILQ_REMOVE(&acpi_pci_link_entries
, link
, links
);
841 TAILQ_INSERT_TAIL(&sorted_list
, link
, links
);
844 while (!TAILQ_EMPTY(&sorted_list
)) {
845 /* move them back to the list, one by one... */
846 link
= TAILQ_FIRST(&sorted_list
);
847 TAILQ_REMOVE(&sorted_list
, link
, links
);
848 TAILQ_INSERT_TAIL(&acpi_pci_link_entries
, link
, links
);
853 acpi_pci_link_fixup_bootdisabled_link(void)
857 struct acpi_pci_link_entry
*link
;
861 kprintf("ACPI PCI link before fixup for boot-disabled links:\n");
862 acpi_pci_link_bootdisabled_dump();
865 TAILQ_FOREACH(link
, &acpi_pci_link_entries
, links
) {
866 /* ignore non boot-disabled links. */
867 if (link
->current_irq
!= 0)
870 /* sort IRQs based on their penalty descending. */
871 for (i
= 0; i
< link
->number_of_interrupts
; i
++) {
872 irq1
= link
->sorted_irq
[i
];
873 for (j
= i
+ 1; j
< link
->number_of_interrupts
; j
++) {
874 irq2
= link
->sorted_irq
[j
];
875 if (irq_penalty
[irq1
] < irq_penalty
[irq2
]) {
878 link
->sorted_irq
[i
] = irq2
;
879 link
->sorted_irq
[j
] = irq1
;
884 /* try with lower penalty IRQ. */
885 for (i
= 0; i
< link
->number_of_interrupts
; i
++) {
886 irq1
= link
->sorted_irq
[i
];
887 error
= acpi_pci_link_set_irq(link
, irq1
);
888 if (error
== AE_OK
) {
889 /* OK, we use this. give another penalty. */
890 irq_penalty
[irq1
] += 100 * link
->references
;
897 kprintf("ACPI PCI link after fixup for boot-disabled links:\n");
898 acpi_pci_link_bootdisabled_dump();
907 acpi_pci_link_config(device_t dev
, ACPI_BUFFER
*prtbuf
, int busno
)
909 struct acpi_prt_entry
*entry
;
910 ACPI_PCI_ROUTING_TABLE
*prt
;
913 static int first_time
=1;
915 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__
);
917 if (acpi_disabled("pci_link"))
921 TAILQ_INIT(&acpi_prt_entries
);
922 TAILQ_INIT(&acpi_pci_link_entries
);
923 acpi_pci_link_init_irq_penalty();
930 prtp
= prtbuf
->Pointer
;
931 if (prtp
== NULL
) /* didn't get routing table */
934 /* scan the PCI Routing Table */
936 prt
= (ACPI_PCI_ROUTING_TABLE
*)prtp
;
938 if (prt
->Length
== 0) /* end of table */
941 error
= acpi_pci_link_add_prt(dev
, prt
, busno
);
942 if (ACPI_FAILURE(error
)) {
943 ACPI_DEBUG_PRINT((ACPI_DB_WARN
,
944 "couldn't add PCI interrupt link entry - %s\n",
945 AcpiFormatException(error
)));
948 /* skip to next entry */
953 kprintf("ACPI PCI link initial configuration:\n");
954 TAILQ_FOREACH(entry
, &acpi_prt_entries
, links
) {
955 if (entry
->busno
!= busno
)
957 acpi_pci_link_entry_dump(entry
);
961 /* manual configuration. */
962 TAILQ_FOREACH(entry
, &acpi_prt_entries
, links
) {
966 if (entry
->busno
!= busno
)
969 ksnprintf(prthint
, sizeof(prthint
),
970 "hw.acpi.pci.link.%d.%d.%d.irq", entry
->busno
,
971 (int)((entry
->prt
.Address
& 0xffff0000) >> 16),
972 (int)entry
->prt
.Pin
);
974 if (kgetenv_int(prthint
, &irq
) == 0)
977 if (acpi_pci_link_is_valid_irq(entry
->pci_link
, irq
)) {
978 error
= acpi_pci_link_set_irq(entry
->pci_link
, irq
);
979 if (ACPI_FAILURE(error
)) {
980 ACPI_DEBUG_PRINT((ACPI_DB_WARN
,
981 "couldn't set IRQ to link entry %s - %s\n",
982 acpi_name(entry
->pci_link
->handle
),
983 AcpiFormatException(error
)));
989 * Do auto arbitration for this device's PCI link
990 * if hint value 0 is specified.
993 entry
->pci_link
->current_irq
= 0;
996 /* auto arbitration */
997 acpi_pci_link_update_irq_penalty(dev
, busno
);
998 acpi_pci_link_set_bootdisabled_priority();
999 acpi_pci_link_fixup_bootdisabled_link();
1002 kprintf("ACPI PCI link arbitrated configuration:\n");
1003 TAILQ_FOREACH(entry
, &acpi_prt_entries
, links
) {
1004 if (entry
->busno
!= busno
)
1006 acpi_pci_link_entry_dump(entry
);
1014 acpi_pci_link_resume(device_t dev
, ACPI_BUFFER
*prtbuf
, int busno
)
1016 struct acpi_prt_entry
*entry
;
1019 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__
);
1021 if (acpi_disabled("pci_link"))
1024 TAILQ_FOREACH(entry
, &acpi_prt_entries
, links
) {
1025 if (entry
->pcidev
!= dev
)
1028 error
= acpi_pci_link_set_irq(entry
->pci_link
,
1029 entry
->pci_link
->current_irq
);
1030 if (ACPI_FAILURE(error
)) {
1031 ACPI_DEBUG_PRINT((ACPI_DB_WARN
,
1032 "couldn't set IRQ to link entry %s - %s\n",
1033 acpi_name(entry
->pci_link
->handle
),
1034 AcpiFormatException(error
)));