Add flag to indicate that the NIC does not have power control capability.
[dragonfly.git] / sys / dev / acpica5 / acpi_pci_link.c
blob856b9101fbbf0be4246258d0bba93a1572712b31
1 /*-
2 * Copyright (c) 2002 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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
24 * SUCH DAMAGE.
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 $
30 #include "opt_acpi.h"
31 #include <sys/param.h>
32 #include <sys/kernel.h>
33 #include <sys/bus.h>
35 #include "acpi.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;
49 ACPI_HANDLE handle;
50 UINT8 current_irq;
51 UINT8 initial_irq;
52 ACPI_RESOURCE possible_resources;
53 UINT8 number_of_interrupts;
54 UINT8 interrupts[MAX_POSSIBLE_INTERRUPTS];
55 UINT8 sorted_irq[MAX_POSSIBLE_INTERRUPTS];
56 int references;
57 int priority;
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;
65 device_t pcidev;
66 int busno;
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
85 static void
86 acpi_pci_link_dump_polarity(UINT32 ActiveHighLow)
89 switch (ActiveHighLow) {
90 case ACPI_ACTIVE_HIGH:
91 kprintf("high,");
92 break;
93 case ACPI_ACTIVE_LOW:
94 kprintf("low,");
95 break;
96 default:
97 kprintf("unknown,");
98 break;
102 static void
103 acpi_pci_link_dump_trigger(UINT32 EdgeLevel)
106 switch (EdgeLevel) {
107 case ACPI_EDGE_SENSITIVE:
108 kprintf("edge,");
109 break;
110 case ACPI_LEVEL_SENSITIVE:
111 kprintf("level,");
112 break;
113 default:
114 kprintf("unknown,");
115 break;
119 static void
120 acpi_pci_link_dump_sharemode(UINT32 SharedExclusive)
123 switch (SharedExclusive) {
124 case ACPI_EXCLUSIVE:
125 kprintf("exclusive");
126 break;
127 case ACPI_SHARED:
128 kprintf("sharable");
129 break;
130 default:
131 kprintf("unknown");
132 break;
136 static void
137 acpi_pci_link_entry_dump(struct acpi_prt_entry *entry)
139 UINT8 i;
140 ACPI_RESOURCE_IRQ *Irq;
141 ACPI_RESOURCE_EXT_IRQ *ExtIrq;
143 if (entry == NULL || entry->pci_link == NULL)
144 return;
146 kprintf("%s irq %3d: ", acpi_name(entry->pci_link->handle),
147 entry->pci_link->current_irq);
149 kprintf("[");
150 for (i = 0; i < entry->pci_link->number_of_interrupts; i++)
151 kprintf("%3d", entry->pci_link->interrupts[i]);
152 kprintf("] ");
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);
160 break;
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);
166 break;
169 kprintf(" %d.%d.%d\n", entry->busno,
170 (int)((entry->prt.Address & 0xffff0000) >> 16),
171 (int)entry->prt.Pin);
174 static ACPI_STATUS
175 acpi_pci_link_get_object_status(ACPI_HANDLE handle, UINT32 *sta)
177 ACPI_DEVICE_INFO *devinfo;
178 ACPI_BUFFER buf;
179 ACPI_STATUS error;
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);
188 buf.Pointer = NULL;
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",
202 acpi_name(handle)));
203 AcpiOsFree(buf.Pointer);
204 return_ACPI_STATUS (AE_TYPE);
207 if ((devinfo->Valid & ACPI_VALID_STA) != 0) {
208 *sta = devinfo->CurrentStatus;
209 } else {
210 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "invalid status - %s\n",
211 acpi_name(handle)));
212 *sta = 0;
215 AcpiOsFree(buf.Pointer);
216 return_ACPI_STATUS (AE_OK);
219 static ACPI_STATUS
220 acpi_pci_link_get_irq_resources(ACPI_RESOURCE *resources,
221 UINT8 *number_of_interrupts, UINT8 interrupts[])
223 UINT8 count;
224 UINT8 i;
225 UINT32 NumberOfInterrupts;
226 UINT32 *Interrupts;
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;
237 Interrupts = NULL;
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;
253 break;
254 case ACPI_RSTYPE_EXT_IRQ:
255 NumberOfInterrupts =
256 resources->Data.ExtendedIrq.NumberOfInterrupts;
257 Interrupts = resources->Data.ExtendedIrq.Interrupts;
258 break;
261 if (NumberOfInterrupts == 0) {
262 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Blank IRQ resource\n"));
263 return_ACPI_STATUS (AE_NULL_ENTRY);
266 count = 0;
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",
270 i));
271 break;
273 if (Interrupts[i] == 0) {
274 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "invalid IRQ %d\n",
275 Interrupts[i]));
276 continue;
278 interrupts[count] = Interrupts[i];
279 count++;
281 *number_of_interrupts = count;
283 return_ACPI_STATUS (AE_OK);
286 static ACPI_STATUS
287 acpi_pci_link_get_current_irq(struct acpi_pci_link_entry *link, UINT8 *irq)
289 ACPI_STATUS error;
290 ACPI_BUFFER buf;
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);
302 *irq = 0;
303 buf.Pointer = NULL;
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);
345 static ACPI_STATUS
346 acpi_pci_link_add_link(ACPI_HANDLE handle, struct acpi_prt_entry *entry)
348 ACPI_STATUS error;
349 ACPI_BUFFER buf;
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;
359 link->references++;
360 return_ACPI_STATUS (AE_OK);
364 link = AcpiOsAllocate(sizeof(struct acpi_pci_link_entry));
365 if (link == NULL) {
366 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
367 "couldn't allocate memory - %s\n", acpi_name(handle)));
368 return_ACPI_STATUS (AE_NO_MEMORY);
371 buf.Pointer = NULL;
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)));
392 goto out;
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;
398 goto out;
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)));
411 goto out;
414 if (link->number_of_interrupts == 0) {
415 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
416 "interrupt link device _PRS data is corrupted - %s\n",
417 acpi_name(handle)));
418 error = AE_NULL_ENTRY;
419 goto out;
422 link->references++;
424 TAILQ_INSERT_TAIL(&acpi_pci_link_entries, link, links);
425 entry->pci_link = link;
427 error = AE_OK;
428 out:
429 if (buf.Pointer != NULL)
430 AcpiOsFree(buf.Pointer);
431 if (error != AE_OK && link != NULL)
432 AcpiOsFree(link);
434 return_ACPI_STATUS (error);
437 static ACPI_STATUS
438 acpi_pci_link_add_prt(device_t pcidev, ACPI_PCI_ROUTING_TABLE *prt, int busno)
440 ACPI_HANDLE handle;
441 ACPI_STATUS error;
442 UINT32 sta;
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",
471 acpi_name(handle)));
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",
481 acpi_name(handle)));
482 return_ACPI_STATUS (AE_ALREADY_EXISTS);
486 entry = AcpiOsAllocate(sizeof(struct acpi_prt_entry));
487 if (entry == NULL) {
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)));
503 goto out;
506 TAILQ_INSERT_TAIL(&acpi_prt_entries, entry, links);
507 error = AE_OK;
509 out:
510 if (error != AE_OK && entry != NULL)
511 AcpiOsFree(entry);
513 return_ACPI_STATUS (error);
516 static int
517 acpi_pci_link_is_valid_irq(struct acpi_pci_link_entry *link, UINT8 irq)
519 UINT8 i;
521 if (irq == 0)
522 return (0);
524 for (i = 0; i < link->number_of_interrupts; i++) {
525 if (link->interrupts[i] == irq)
526 return (1);
529 /* allow initial IRQ as valid one. */
530 if (link->initial_irq == irq)
531 return (1);
533 return (0);
536 static ACPI_STATUS
537 acpi_pci_link_set_irq(struct acpi_pci_link_entry *link, UINT8 irq)
539 ACPI_STATUS error;
540 ACPI_RESOURCE resbuf;
541 ACPI_BUFFER crsbuf;
542 UINT32 sta;
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;
575 break;
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;
585 break;
586 default:
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) {
642 error = AE_OK;
643 } else {
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;
648 error = AE_ERROR;
651 return_ACPI_STATUS (error);
655 * Auto arbitration for boot-disabled devices
658 static void
659 acpi_pci_link_bootdisabled_dump(void)
661 int i;
662 int irq;
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)
668 continue;
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];
674 kprintf("%6d", irq);
676 kprintf("\n");
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]);
682 kprintf("\n");
683 kprintf(" references: %d\n", link->references);
684 kprintf(" priority: %d\n", link->priority);
688 static void
689 acpi_pci_link_init_irq_penalty(void)
691 int irq;
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;
698 continue;
701 /* 13, 14, 15: npx, ATA controllers */
702 if (irq == 13 || irq == 14 || irq == 15) {
703 irq_penalty[irq] = 10000;
704 continue;
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;
710 continue;
715 static int
716 link_exclusive(ACPI_RESOURCE *res)
718 if (res == NULL ||
719 (res->Id != ACPI_RSTYPE_IRQ &&
720 res->Id != ACPI_RSTYPE_EXT_IRQ))
721 return (0);
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))
727 return (1);
729 return (0);
732 static void
733 acpi_pci_link_update_irq_penalty(device_t dev, int busno)
735 int i;
736 int irq;
737 int rid;
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)
744 continue;
746 /* Impossible? */
747 link = entry->pci_link;
748 if (link == NULL)
749 continue;
751 if (link->current_irq != 0) {
752 /* not boot-disabled link, we will use this IRQ. */
753 irq_penalty[link->current_irq] += 100;
754 continue;
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. */
768 rid = 0;
769 res = bus_alloc_resource(dev, SYS_RES_IRQ,
770 &rid, irq, irq, 1, 0);
771 if (res != NULL) {
772 bus_release_resource(dev, SYS_RES_IRQ,
773 rid, res);
774 } else {
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));
786 static void
787 acpi_pci_link_set_bootdisabled_priority(void)
789 int sum_penalty;
790 int i;
791 int irq;
792 struct acpi_pci_link_entry *link, *link_pri;
793 TAILQ_HEAD(, acpi_pci_link_entry) sorted_list;
795 if (bootverbose) {
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)
802 link->priority = 0;
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) {
807 link->priority = 0;
808 continue;
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.
817 sum_penalty = 0;
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)
837 link = link_pri;
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);
852 static void
853 acpi_pci_link_fixup_bootdisabled_link(void)
855 int i, j;
856 int irq1, irq2;
857 struct acpi_pci_link_entry *link;
858 ACPI_STATUS error;
860 if (bootverbose) {
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)
868 continue;
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]) {
876 continue;
878 link->sorted_irq[i] = irq2;
879 link->sorted_irq[j] = irq1;
880 irq1 = irq2;
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;
891 break;
896 if (bootverbose) {
897 kprintf("ACPI PCI link after fixup for boot-disabled links:\n");
898 acpi_pci_link_bootdisabled_dump();
903 * Public interface
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;
911 u_int8_t *prtp;
912 ACPI_STATUS error;
913 static int first_time =1;
915 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
917 if (acpi_disabled("pci_link"))
918 return (0);
920 if (first_time) {
921 TAILQ_INIT(&acpi_prt_entries);
922 TAILQ_INIT(&acpi_pci_link_entries);
923 acpi_pci_link_init_irq_penalty();
924 first_time = 0;
927 if (prtbuf == NULL)
928 return (-1);
930 prtp = prtbuf->Pointer;
931 if (prtp == NULL) /* didn't get routing table */
932 return (-1);
934 /* scan the PCI Routing Table */
935 for (;;) {
936 prt = (ACPI_PCI_ROUTING_TABLE *)prtp;
938 if (prt->Length == 0) /* end of table */
939 break;
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 */
949 prtp += prt->Length;
952 if (bootverbose) {
953 kprintf("ACPI PCI link initial configuration:\n");
954 TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
955 if (entry->busno != busno)
956 continue;
957 acpi_pci_link_entry_dump(entry);
961 /* manual configuration. */
962 TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
963 int irq;
964 char prthint[32];
966 if (entry->busno != busno)
967 continue;
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)
975 continue;
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)));
985 continue;
989 * Do auto arbitration for this device's PCI link
990 * if hint value 0 is specified.
992 if (irq == 0)
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();
1001 if (bootverbose) {
1002 kprintf("ACPI PCI link arbitrated configuration:\n");
1003 TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
1004 if (entry->busno != busno)
1005 continue;
1006 acpi_pci_link_entry_dump(entry);
1010 return (0);
1014 acpi_pci_link_resume(device_t dev, ACPI_BUFFER *prtbuf, int busno)
1016 struct acpi_prt_entry *entry;
1017 ACPI_STATUS error;
1019 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
1021 if (acpi_disabled("pci_link"))
1022 return (0);
1024 TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
1025 if (entry->pcidev != dev)
1026 continue;
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)));
1038 return (0);