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.13 2004/01/20 21:38:48 jhb Exp $
27 * $DragonFly: src/sys/dev/acpica5/acpi_pci_link.c,v 1.1 2004/02/21 06:48:08 dillon Exp $
31 #include <sys/param.h>
32 #include <sys/kernel.h>
37 #include <dev/acpica5/acpivar.h>
38 #include <dev/acpica5/acpi_pcibvar.h>
41 * Hooks for the ACPI CA debugging infrastructure
43 #define _COMPONENT ACPI_BUS
44 ACPI_MODULE_NAME("PCI_LINK")
46 #define MAX_POSSIBLE_INTERRUPTS 16
47 #define MAX_ISA_INTERRUPTS 16
48 #define MAX_ACPI_INTERRUPTS 255
50 struct acpi_pci_link_entry {
51 TAILQ_ENTRY(acpi_pci_link_entry) links;
55 ACPI_RESOURCE possible_resources;
56 UINT8 number_of_interrupts;
57 UINT8 interrupts[MAX_POSSIBLE_INTERRUPTS];
59 UINT8 sorted_irq[MAX_POSSIBLE_INTERRUPTS];
64 TAILQ_HEAD(acpi_pci_link_entries, acpi_pci_link_entry);
65 static struct acpi_pci_link_entries acpi_pci_link_entries;
67 struct acpi_prt_entry {
68 TAILQ_ENTRY(acpi_prt_entry) links;
71 ACPI_PCI_ROUTING_TABLE prt;
72 struct acpi_pci_link_entry *pci_link;
75 TAILQ_HEAD(acpi_prt_entries, acpi_prt_entry);
76 static struct acpi_prt_entries acpi_prt_entries;
78 static int irq_penalty[MAX_ACPI_INTERRUPTS];
80 #define ACPI_STA_PRESENT 0x00000001
81 #define ACPI_STA_ENABLE 0x00000002
82 #define ACPI_STA_SHOWINUI 0x00000004
83 #define ACPI_STA_FUNCTIONAL 0x00000008
86 * PCI link object management
90 acpi_pci_link_dump_polarity(UINT32 ActiveHighLow)
93 switch (ActiveHighLow) {
94 case ACPI_ACTIVE_HIGH:
109 acpi_pci_link_dump_trigger(UINT32 EdgeLevel)
113 case ACPI_EDGE_SENSITIVE:
117 case ACPI_LEVEL_SENSITIVE:
128 acpi_pci_link_dump_sharemode(UINT32 SharedExclusive)
131 switch (SharedExclusive) {
147 acpi_pci_link_entry_dump(struct acpi_prt_entry *entry)
150 ACPI_RESOURCE_IRQ *Irq;
151 ACPI_RESOURCE_EXT_IRQ *ExtIrq;
153 if (entry == NULL || entry->pci_link == NULL) {
157 printf("%s irq %3d: ", acpi_name(entry->pci_link->handle),
158 entry->pci_link->current_irq);
161 for (i = 0; i < entry->pci_link->number_of_interrupts; i++) {
162 printf("%3d", entry->pci_link->interrupts[i]);
166 switch (entry->pci_link->possible_resources.Id) {
167 case ACPI_RSTYPE_IRQ:
168 Irq = &entry->pci_link->possible_resources.Data.Irq;
170 acpi_pci_link_dump_polarity(Irq->ActiveHighLow);
171 acpi_pci_link_dump_trigger(Irq->EdgeLevel);
172 acpi_pci_link_dump_sharemode(Irq->SharedExclusive);
175 case ACPI_RSTYPE_EXT_IRQ:
176 ExtIrq = &entry->pci_link->possible_resources.Data.ExtendedIrq;
178 acpi_pci_link_dump_polarity(ExtIrq->ActiveHighLow);
179 acpi_pci_link_dump_trigger(ExtIrq->EdgeLevel);
180 acpi_pci_link_dump_sharemode(ExtIrq->SharedExclusive);
184 printf(" %d.%d.%d", entry->busno,
185 (int)((entry->prt.Address & 0xffff0000) >> 16),
186 (int)entry->prt.Pin);
192 acpi_pci_link_get_object_status(ACPI_HANDLE handle, UINT32 *sta)
194 ACPI_DEVICE_INFO *devinfo;
198 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
200 if (handle == NULL || sta == NULL) {
201 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
202 "invalid argument\n"));
203 return_ACPI_STATUS (AE_BAD_PARAMETER);
207 buf.Length = ACPI_ALLOCATE_BUFFER;
208 error = AcpiGetObjectInfo(handle, &buf);
209 if (ACPI_FAILURE(error)) {
210 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
211 "couldn't get object info %s - %s\n",
212 acpi_name(handle), AcpiFormatException(error)));
213 return_ACPI_STATUS (error);
215 devinfo = (ACPI_DEVICE_INFO *)buf.Pointer;
217 if ((devinfo->Valid & ACPI_VALID_HID) == 0 ||
218 strcmp(devinfo->HardwareId.Value, "PNP0C0F") != 0) {
219 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid hardware ID - %s\n",
221 AcpiOsFree(buf.Pointer);
222 return_ACPI_STATUS (AE_TYPE);
225 if ((devinfo->Valid & ACPI_VALID_STA) != 0) {
226 *sta = devinfo->CurrentStatus;
228 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "invalid status - %s\n",
233 AcpiOsFree(buf.Pointer);
234 return_ACPI_STATUS (AE_OK);
238 acpi_pci_link_get_irq_resources(ACPI_RESOURCE *resources,
239 UINT8 *number_of_interrupts, UINT8 interrupts[])
243 UINT32 NumberOfInterrupts;
246 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
248 if (resources == NULL || number_of_interrupts == NULL) {
249 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid argument\n"));
250 return_ACPI_STATUS (AE_BAD_PARAMETER);
253 *number_of_interrupts = 0;
254 NumberOfInterrupts = 0;
257 if (resources->Id == ACPI_RSTYPE_START_DPF)
258 resources = ACPI_NEXT_RESOURCE(resources);
260 if (resources->Id != ACPI_RSTYPE_IRQ &&
261 resources->Id != ACPI_RSTYPE_EXT_IRQ) {
262 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
263 "Resource is not an IRQ entry - %d\n", resources->Id));
264 return_ACPI_STATUS (AE_TYPE);
267 switch (resources->Id) {
268 case ACPI_RSTYPE_IRQ:
269 NumberOfInterrupts = resources->Data.Irq.NumberOfInterrupts;
270 Interrupts = resources->Data.Irq.Interrupts;
273 case ACPI_RSTYPE_EXT_IRQ:
274 NumberOfInterrupts = resources->Data.ExtendedIrq.NumberOfInterrupts;
275 Interrupts = resources->Data.ExtendedIrq.Interrupts;
279 if (NumberOfInterrupts == 0) {
280 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Blank IRQ resource\n"));
281 return_ACPI_STATUS (AE_NULL_ENTRY);
285 for (i = 0; i < NumberOfInterrupts; i++) {
286 if (i >= MAX_POSSIBLE_INTERRUPTS) {
287 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "too many IRQs %d\n", i));
291 if (Interrupts[i] == 0) {
292 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid IRQ %d\n",
296 interrupts[count] = Interrupts[i];
299 *number_of_interrupts = count;
301 return_ACPI_STATUS (AE_OK);
305 acpi_pci_link_get_current_irq(struct acpi_pci_link_entry *link, UINT8 *irq)
309 ACPI_RESOURCE *resources;
310 UINT8 number_of_interrupts;
311 UINT8 interrupts[MAX_POSSIBLE_INTERRUPTS];;
313 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
315 if (link == NULL || irq == NULL) {
316 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid argument\n"));
317 return_ACPI_STATUS (AE_BAD_PARAMETER);
322 buf.Length = ACPI_ALLOCATE_BUFFER;
323 error = AcpiGetCurrentResources(link->handle, &buf);
324 if (ACPI_FAILURE(error)) {
325 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
326 "couldn't get PCI interrupt link device _CRS %s - %s\n",
327 acpi_name(link->handle), AcpiFormatException(error)));
328 return_ACPI_STATUS (error);
330 if (buf.Pointer == NULL) {
331 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
332 "couldn't allocate memory - %s\n",
333 acpi_name(link->handle)));
334 return_ACPI_STATUS (AE_NO_MEMORY);
337 resources = (ACPI_RESOURCE *) buf.Pointer;
339 number_of_interrupts = 0;
340 bzero(interrupts, sizeof(interrupts));
341 error = acpi_pci_link_get_irq_resources(resources,
342 &number_of_interrupts, interrupts);
343 AcpiOsFree(buf.Pointer);
345 if (ACPI_FAILURE(error)) {
346 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
347 "couldn't get current IRQ from PCI interrupt link %s - %s\n",
348 acpi_name(link->handle), AcpiFormatException(error)));
349 return_ACPI_STATUS (error);
352 if (number_of_interrupts == 0) {
353 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
354 "PCI interrupt link device _CRS data is corrupted - %s\n",
355 acpi_name(link->handle)));
356 return_ACPI_STATUS (AE_NULL_ENTRY);
359 *irq = interrupts[0];
361 return_ACPI_STATUS (AE_OK);
365 acpi_pci_link_add_link(ACPI_HANDLE handle, struct acpi_prt_entry *entry)
369 ACPI_RESOURCE *resources;
370 struct acpi_pci_link_entry *link;
372 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
374 entry->pci_link = NULL;
375 TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
376 if (link->handle == handle) {
377 entry->pci_link = link;
379 return_ACPI_STATUS (AE_OK);
383 link = AcpiOsAllocate(sizeof(struct acpi_pci_link_entry));
385 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
386 "couldn't allocate memory - %s\n", acpi_name(handle)));
387 return_ACPI_STATUS (AE_NO_MEMORY);
391 buf.Length = ACPI_ALLOCATE_BUFFER;
393 bzero(link, sizeof(struct acpi_pci_link_entry));
395 link->handle = handle;
397 error = acpi_pci_link_get_current_irq(link, &link->current_irq);
398 if (ACPI_FAILURE(error)) {
399 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
400 "couldn't get current IRQ from PCI interrupt link %s - %s\n",
401 acpi_name(handle), AcpiFormatException(error)));
404 link->initial_irq = link->current_irq;
406 error = AcpiGetPossibleResources(handle, &buf);
407 if (ACPI_FAILURE(error)) {
408 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
409 "couldn't get PCI interrupt link device _PRS data %s - %s\n",
410 acpi_name(handle), AcpiFormatException(error)));
414 if (buf.Pointer == NULL) {
415 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
416 "_PRS nuffer is empty - %s\n", acpi_name(handle)));
417 error = AE_NO_MEMORY;
421 resources = (ACPI_RESOURCE *) buf.Pointer;
422 bcopy(resources, &link->possible_resources,
423 sizeof(link->possible_resources));
425 error = acpi_pci_link_get_irq_resources(resources,
426 &link->number_of_interrupts, link->interrupts);
427 if (ACPI_FAILURE(error)) {
428 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
429 "couldn't get possible IRQs from PCI interrupt link %s - %s\n",
430 acpi_name(handle), AcpiFormatException(error)));
434 if (link->number_of_interrupts == 0) {
435 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
436 "PCI interrupt link device _PRS data is corrupted - %s\n",
438 error = AE_NULL_ENTRY;
444 TAILQ_INSERT_TAIL(&acpi_pci_link_entries, link, links);
445 entry->pci_link = link;
449 if (buf.Pointer != NULL) {
450 AcpiOsFree(buf.Pointer);
453 if (error != AE_OK && link != NULL) {
457 return_ACPI_STATUS (error);
461 acpi_pci_link_add_prt(device_t pcidev, ACPI_PCI_ROUTING_TABLE *prt, int busno)
466 struct acpi_prt_entry *entry;
468 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
470 if ((prt == NULL) || (prt->Source == NULL) || (prt->Source[0] == '\0')) {
471 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
472 "couldn't handle this routing table - hardwired\n"));
473 return_ACPI_STATUS (AE_BAD_PARAMETER);
476 error = AcpiGetHandle(acpi_get_handle(pcidev), prt->Source, &handle);
477 if (ACPI_FAILURE(error)) {
478 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
479 "couldn't get acpi handle - %s\n",
480 AcpiFormatException(error)));
481 return_ACPI_STATUS (error);
484 error = acpi_pci_link_get_object_status(handle, &sta);
485 if (ACPI_FAILURE(error)) {
486 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
487 "couldn't get object status %s - %s\n",
488 acpi_name(handle), AcpiFormatException(error)));
489 return_ACPI_STATUS (error);
492 if (!(sta & (ACPI_STA_PRESENT | ACPI_STA_FUNCTIONAL))) {
493 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
494 "PCI interrupt link is not functional - %s\n",
496 return_ACPI_STATUS (AE_ERROR);
499 TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
500 if (entry->busno == busno &&
501 entry->prt.Address == prt->Address &&
502 entry->prt.Pin == prt->Pin) {
503 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
504 "PCI interrupt link entry already exists - %s\n",
506 return_ACPI_STATUS (AE_ALREADY_EXISTS);
510 entry = AcpiOsAllocate(sizeof(struct acpi_prt_entry));
512 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
513 "couldn't allocate memory - %s\n", acpi_name(handle)));
514 return_ACPI_STATUS (AE_NO_MEMORY);
517 bzero(entry, sizeof(struct acpi_prt_entry));
519 entry->pcidev = pcidev;
520 entry->busno = busno;
521 bcopy(prt, &entry->prt, sizeof(entry->prt));
523 error = acpi_pci_link_add_link(handle, entry);
524 if (ACPI_FAILURE(error)) {
525 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
526 "couldn't add prt entry to pci link %s - %s\n",
527 acpi_name(handle), AcpiFormatException(error)));
531 TAILQ_INSERT_TAIL(&acpi_prt_entries, entry, links);
535 if (error != AE_OK && entry != NULL) {
539 return_ACPI_STATUS (error);
543 acpi_pci_link_is_valid_irq(struct acpi_pci_link_entry *link, UINT8 irq)
551 for (i = 0; i < link->number_of_interrupts; i++) {
552 if (link->interrupts[i] == irq) {
557 /* allow initial IRQ as valid one. */
558 if (link->initial_irq == irq) {
566 acpi_pci_link_set_irq(struct acpi_pci_link_entry *link, UINT8 irq)
569 ACPI_RESOURCE resbuf;
573 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
575 if (!acpi_pci_link_is_valid_irq(link, irq)) {
576 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
577 "couldn't set invalid IRQ %d - %s\n", irq,
578 acpi_name(link->handle)));
579 return_ACPI_STATUS (AE_BAD_PARAMETER);
582 error = acpi_pci_link_get_current_irq(link, &link->current_irq);
583 if (ACPI_FAILURE(error)) {
584 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
585 "couldn't get current IRQ from PCI interrupt link %s - %s\n",
586 acpi_name(link->handle), AcpiFormatException(error)));
589 if (link->current_irq == irq) {
590 return_ACPI_STATUS (AE_OK);
593 bzero(&resbuf, sizeof(resbuf));
594 crsbuf.Pointer = NULL;
596 switch (link->possible_resources.Id) {
598 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
599 "Resource is not an IRQ entry %s - %d\n",
600 acpi_name(link->handle), link->possible_resources.Id));
601 return_ACPI_STATUS (AE_TYPE);
603 case ACPI_RSTYPE_IRQ:
604 resbuf.Id = ACPI_RSTYPE_IRQ;
605 resbuf.Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_IRQ);
607 /* structure copy other fields */
608 resbuf.Data.Irq = link->possible_resources.Data.Irq;
609 resbuf.Data.Irq.NumberOfInterrupts = 1;
610 resbuf.Data.Irq.Interrupts[0] = irq;
613 case ACPI_RSTYPE_EXT_IRQ:
614 resbuf.Id = ACPI_RSTYPE_EXT_IRQ;
615 resbuf.Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_EXT_IRQ);
617 /* structure copy other fields */
618 resbuf.Data.ExtendedIrq = link->possible_resources.Data.ExtendedIrq;
619 resbuf.Data.ExtendedIrq.NumberOfInterrupts = 1;
620 resbuf.Data.ExtendedIrq.Interrupts[0] = irq;
624 error = acpi_AppendBufferResource(&crsbuf, &resbuf);
625 if (ACPI_FAILURE(error)) {
626 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
627 "couldn't setup buffer by acpi_AppendBufferResource - %s\n",
628 acpi_name(link->handle)));
629 return_ACPI_STATUS (error);
632 if (crsbuf.Pointer == NULL) {
633 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
634 "buffer setup by acpi_AppendBufferResource is corrupted - %s\n",
635 acpi_name(link->handle)));
636 return_ACPI_STATUS (AE_NO_MEMORY);
639 error = AcpiSetCurrentResources(link->handle, &crsbuf);
640 if (ACPI_FAILURE(error)) {
641 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
642 "couldn't set PCI interrupt link device _SRS %s - %s\n",
643 acpi_name(link->handle), AcpiFormatException(error)));
644 return_ACPI_STATUS (error);
647 AcpiOsFree(crsbuf.Pointer);
648 link->current_irq = 0;
650 error = acpi_pci_link_get_object_status(link->handle, &sta);
651 if (ACPI_FAILURE(error)) {
652 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
653 "couldn't get object status %s - %s\n",
654 acpi_name(link->handle), AcpiFormatException(error)));
655 return_ACPI_STATUS (error);
658 if (!(sta & ACPI_STA_ENABLE)) {
659 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
660 "PCI interrupt link is disabled - %s\n",
661 acpi_name(link->handle)));
662 return_ACPI_STATUS (AE_ERROR);
665 error = acpi_pci_link_get_current_irq(link, &link->current_irq);
666 if (ACPI_FAILURE(error)) {
667 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
668 "couldn't get current IRQ from PCI interrupt link %s - %s\n",
669 acpi_name(link->handle), AcpiFormatException(error)));
670 return_ACPI_STATUS (error);
673 if (link->current_irq == irq) {
676 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
677 "couldn't set IRQ %d to PCI interrupt link %d - %s\n",
678 irq, link->current_irq, acpi_name(link->handle)));
680 link->current_irq = 0;
684 return_ACPI_STATUS (error);
688 * Auto arbitration for boot-disabled devices
692 acpi_pci_link_bootdisabled_dump(void)
697 struct acpi_pci_link_entry *link;
699 TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
700 /* boot-disabled link only. */
701 if (link->current_irq != 0) {
705 printf("%s:\n", acpi_name(link->handle));
706 printf(" interrupts: ");
707 for (i = 0; i < link->number_of_interrupts; i++) {
708 irq = link->sorted_irq[i];
712 printf(" penalty: ");
713 for (i = 0; i < link->number_of_interrupts; i++) {
714 irq = link->sorted_irq[i];
715 printf("%6d", irq_penalty[irq]);
718 printf(" references: %d\n", link->references);
719 printf(" priority: %d\n", link->priority);
724 acpi_pci_link_init_irq_penalty(void)
728 bzero(irq_penalty, sizeof(irq_penalty));
729 for (irq = 0; irq < MAX_ISA_INTERRUPTS; irq++) {
730 /* 0, 1, 2, 8: timer, keyboard, cascade */
731 if (irq == 0 || irq == 1 || irq == 2 || irq == 8) {
732 irq_penalty[irq] = 100000;
736 /* 13, 14, 15: npx, ATA controllers */
737 if (irq == 13 || irq == 14 || irq == 15) {
738 irq_penalty[irq] = 10000;
742 /* 3,4,6,7,12: typicially used by legacy hardware */
743 if (irq == 3 || irq == 4 || irq == 6 || irq == 7 || irq == 12) {
744 irq_penalty[irq] = 1000;
751 acpi_pci_link_is_irq_exclusive(ACPI_RESOURCE *res)
757 if (res->Id != ACPI_RSTYPE_IRQ &&
758 res->Id != ACPI_RSTYPE_EXT_IRQ) {
762 if (res->Id == ACPI_RSTYPE_IRQ &&
763 res->Data.Irq.SharedExclusive == ACPI_EXCLUSIVE) {
767 if (res->Id == ACPI_RSTYPE_EXT_IRQ &&
768 res->Data.ExtendedIrq.SharedExclusive == ACPI_EXCLUSIVE) {
776 acpi_pci_link_update_irq_penalty(device_t dev, int busno)
781 struct resource *res;
782 struct acpi_prt_entry *entry;
783 struct acpi_pci_link_entry *link;
785 TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
786 if (entry->busno != busno) {
790 link = entry->pci_link;
792 continue; /* impossible... */
795 if (link->current_irq != 0) {
796 /* not boot-disabled link, we will use this IRQ. */
797 irq_penalty[link->current_irq] += 100;
801 /* boot-disabled link */
802 for (i = 0; i < link->number_of_interrupts; i++) {
803 /* give 10 for each possible IRQs. */
804 irq = link->interrupts[i];
805 irq_penalty[irq] += 10;
807 /* higher penalty if exclusive. */
808 if (acpi_pci_link_is_irq_exclusive(&link->possible_resources)) {
809 irq_penalty[irq] += 100;
812 /* XXX try to get this IRQ in non-sharable mode. */
814 res = bus_alloc_resource(dev, SYS_RES_IRQ,
815 &rid, irq, irq, 1, 0);
817 bus_release_resource(dev, SYS_RES_IRQ,
820 /* this is in use, give 100. */
821 irq_penalty[irq] += 100;
825 /* initialize `sorted' possible IRQs. */
826 bcopy(link->interrupts, link->sorted_irq,
827 sizeof(link->sorted_irq));
832 acpi_pci_link_set_bootdisabled_priority(void)
837 struct acpi_pci_link_entry *link, *link_pri;
838 TAILQ_HEAD(, acpi_pci_link_entry) sorted_list;
841 printf("---- before setting priority for links ------------\n");
842 acpi_pci_link_bootdisabled_dump();
845 /* reset priority for all links. */
846 TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
850 TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
851 /* not boot-disabled link, give no chance to be arbitrated. */
852 if (link->current_irq != 0) {
858 * Calculate the priority for each boot-disabled links.
859 * o IRQ penalty indicates difficulty to use.
860 * o #references for devices indicates importance of the link.
861 * o #interrupts indicates flexibility of the link.
864 for (i = 0; i < link->number_of_interrupts; i++) {
865 irq = link->interrupts[i];
866 sum_penalty += irq_penalty[irq];
869 link->priority = (sum_penalty * link->references) / link->number_of_interrupts;
873 * Sort PCI links based on the priority.
874 * XXX Any other better ways rather than using work list?
876 TAILQ_INIT(&sorted_list);
877 while (!TAILQ_EMPTY(&acpi_pci_link_entries)) {
878 link = TAILQ_FIRST(&acpi_pci_link_entries);
879 /* find an entry which has the highest priority. */
880 TAILQ_FOREACH(link_pri, &acpi_pci_link_entries, links) {
881 if (link->priority < link_pri->priority) {
885 /* move to work list. */
886 TAILQ_REMOVE(&acpi_pci_link_entries, link, links);
887 TAILQ_INSERT_TAIL(&sorted_list, link, links);
890 while (!TAILQ_EMPTY(&sorted_list)) {
891 /* move them back to the list, one by one... */
892 link = TAILQ_FIRST(&sorted_list);
893 TAILQ_REMOVE(&sorted_list, link, links);
894 TAILQ_INSERT_TAIL(&acpi_pci_link_entries, link, links);
899 acpi_pci_link_fixup_bootdisabled_link(void)
903 struct acpi_pci_link_entry *link;
907 printf("---- before fixup boot-disabled links -------------\n");
908 acpi_pci_link_bootdisabled_dump();
911 TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
912 /* ignore non boot-disabled links. */
913 if (link->current_irq != 0) {
917 /* sort IRQs based on their penalty descending. */
918 for (i = 0; i < link->number_of_interrupts; i++) {
919 irq1 = link->sorted_irq[i];
920 for (j = i + 1; j < link->number_of_interrupts; j++) {
921 irq2 = link->sorted_irq[j];
922 if (irq_penalty[irq1] < irq_penalty[irq2]) {
925 link->sorted_irq[i] = irq2;
926 link->sorted_irq[j] = irq1;
931 /* try with lower penalty IRQ. */
932 for (i = 0; i < link->number_of_interrupts; i++) {
933 irq1 = link->sorted_irq[i];
934 error = acpi_pci_link_set_irq(link, irq1);
935 if (error == AE_OK) {
936 /* OK, we use this. give another penalty. */
937 irq_penalty[irq1] += 100 * link->references;
940 /* NG, try next IRQ... */
945 printf("---- after fixup boot-disabled links --------------\n");
946 acpi_pci_link_bootdisabled_dump();
955 acpi_pci_link_config(device_t dev, ACPI_BUFFER *prtbuf, int busno)
957 struct acpi_prt_entry *entry;
958 ACPI_PCI_ROUTING_TABLE *prt;
961 static int first_time =1;
963 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
965 if (acpi_disabled("pci_link")) {
970 TAILQ_INIT(&acpi_prt_entries);
971 TAILQ_INIT(&acpi_pci_link_entries);
972 acpi_pci_link_init_irq_penalty();
976 if (prtbuf == NULL) {
980 prtp = prtbuf->Pointer;
981 if (prtp == NULL) { /* didn't get routing table */
985 /* scan the PCI Routing Table */
987 prt = (ACPI_PCI_ROUTING_TABLE *)prtp;
989 if (prt->Length == 0) /* end of table */
992 error = acpi_pci_link_add_prt(dev, prt, busno);
993 if (ACPI_FAILURE(error)) {
994 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
995 "couldn't add PCI interrupt link entry - %s\n",
996 AcpiFormatException(error)));
999 /* skip to next entry */
1000 prtp += prt->Length;
1004 printf("---- initial configuration ------------------------\n");
1005 TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
1006 if (entry->busno != busno) {
1010 acpi_pci_link_entry_dump(entry);
1014 /* manual configuration. */
1015 TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
1019 if (entry->busno != busno) {
1023 snprintf(prthint, sizeof(prthint),
1024 "hw.acpi.pci.link.%d.%d.%d.irq", entry->busno,
1025 (int)((entry->prt.Address & 0xffff0000) >> 16),
1026 (int)entry->prt.Pin);
1028 if (getenv_int(prthint, &irq) == 0)
1031 if (acpi_pci_link_is_valid_irq(entry->pci_link, irq)) {
1032 error = acpi_pci_link_set_irq(entry->pci_link, irq);
1033 if (ACPI_FAILURE(error)) {
1034 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
1035 "couldn't set IRQ to PCI interrupt link entry %s - %s\n",
1036 acpi_name(entry->pci_link->handle),
1037 AcpiFormatException(error)));
1043 * Do auto arbitration for this device's PCI link
1044 * if hint value 0 is specified.
1047 entry->pci_link->current_irq = 0;
1051 /* auto arbitration */
1052 acpi_pci_link_update_irq_penalty(dev, busno);
1053 acpi_pci_link_set_bootdisabled_priority();
1054 acpi_pci_link_fixup_bootdisabled_link();
1057 printf("---- arbitrated configuration ---------------------\n");
1058 TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
1059 if (entry->busno != busno) {
1063 acpi_pci_link_entry_dump(entry);
1071 acpi_pci_link_resume(device_t dev, ACPI_BUFFER *prtbuf, int busno)
1073 struct acpi_prt_entry *entry;
1076 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
1078 if (acpi_disabled("pci_link")) {
1082 TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
1083 if (entry->pcidev != dev) {
1087 error = acpi_pci_link_set_irq(entry->pci_link,
1088 entry->pci_link->current_irq);
1089 if (ACPI_FAILURE(error)) {
1090 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
1091 "couldn't set IRQ to PCI interrupt link entry %s - %s\n",
1092 acpi_name(entry->pci_link->handle),
1093 AcpiFormatException(error)));