33 #include <linux/kernel.h>
34 #include <linux/module.h>
36 #include <linux/types.h>
39 #include <linux/pci.h>
41 #include <linux/slab.h>
46 #define PREFIX "ACPI: "
48 #define _COMPONENT ACPI_PCI_COMPONENT
50 #define ACPI_PCI_LINK_CLASS "pci_irq_routing"
51 #define ACPI_PCI_LINK_DEVICE_NAME "PCI Interrupt Link"
52 #define ACPI_PCI_LINK_FILE_INFO "info"
53 #define ACPI_PCI_LINK_FILE_STATUS "state"
54 #define ACPI_PCI_LINK_MAX_POSSIBLE 16
56 static int acpi_pci_link_add(
struct acpi_device *
device);
57 static int acpi_pci_link_remove(
struct acpi_device *
device,
int type);
65 static struct acpi_driver acpi_pci_link_driver = {
68 .ids = link_device_ids,
70 .add = acpi_pci_link_add,
71 .remove = acpi_pci_link_remove,
113 switch (resource->
type) {
122 "Blank _PRS IRQ resource\n"));
130 "Invalid _PRS IRQ %d\n",
135 link->
irq.possible_count++;
148 "Blank _PRS EXT IRQ resource\n");
156 "Invalid _PRS IRQ %d\n",
161 link->
irq.possible_count++;
177 static int acpi_pci_link_get_possible(
struct acpi_pci_link *link)
182 acpi_pci_link_check_possible, link);
189 "Found %d possible IRQs\n",
190 link->
irq.possible_count));
200 switch (resource->
type) {
213 "Blank _CRS IRQ resource\n"));
229 "Blank _CRS EXT IRQ resource\n");
252 static int acpi_pci_link_get_current(
struct acpi_pci_link *link)
258 link->
irq.active = 0;
269 if (!link->
device->status.enabled) {
280 acpi_pci_link_check_current, &irq);
292 link->
irq.active = irq;
300 static int acpi_pci_link_set(
struct acpi_pci_link *link,
int irq)
317 buffer.
length =
sizeof(*resource) + 1;
320 switch (link->
irq.resource_type) {
324 resource->res.
data.
irq.triggering = link->
irq.triggering;
325 resource->res.
data.
irq.polarity =
328 resource->res.
data.
irq.sharable =
332 resource->res.
data.
irq.interrupt_count = 1;
333 resource->res.
data.
irq.interrupts[0] = irq;
342 link->
irq.triggering;
346 resource->res.
data.
irq.sharable =
378 if (!link->
device->status.enabled) {
380 "%s [%s] disabled and referenced, BIOS bug\n",
381 acpi_device_name(link->
device),
382 acpi_device_bid(link->
device));
386 result = acpi_pci_link_get_current(link);
395 if (link->
irq.active != irq) {
401 "%s [%s] BIOS reported IRQ %d, using IRQ %d\n",
402 acpi_device_name(link->
device),
403 acpi_device_bid(link->
device), link->
irq.active, irq);
404 link->
irq.active = irq;
449 #define ACPI_MAX_IRQS 256
450 #define ACPI_MAX_ISA_IRQ 16
452 #define PIRQ_PENALTY_PCI_AVAILABLE (0)
453 #define PIRQ_PENALTY_PCI_POSSIBLE (16*16)
454 #define PIRQ_PENALTY_PCI_USING (16*16*16)
455 #define PIRQ_PENALTY_ISA_TYPICAL (16*16*16*16)
456 #define PIRQ_PENALTY_ISA_USED (16*16*16*16*16)
457 #define PIRQ_PENALTY_ISA_ALWAYS (16*16*16*16*16*16)
493 if (link->
irq.possible_count) {
496 link->
irq.possible_count;
498 for (i = 0; i < link->
irq.possible_count; i++) {
500 acpi_irq_penalty[link->
irq.
505 }
else if (link->
irq.active) {
506 acpi_irq_penalty[link->
irq.active] +=
515 static int acpi_irq_balance = -1;
517 static int acpi_pci_link_allocate(
struct acpi_pci_link *link)
522 if (link->
irq.initialized) {
525 acpi_pci_link_set(link, link->
irq.active);
532 for (i = 0; i < link->
irq.possible_count; ++
i) {
533 if (link->
irq.active == link->
irq.possible[i])
539 if (i == link->
irq.possible_count) {
542 " in _PRS\n", link->
irq.active);
543 link->
irq.active = 0;
549 if (link->
irq.active)
550 irq = link->
irq.active;
552 irq = link->
irq.possible[link->
irq.possible_count - 1];
554 if (acpi_irq_balance || !link->
irq.active) {
559 for (i = (link->
irq.possible_count - 1); i >= 0; i--) {
560 if (acpi_irq_penalty[irq] >
561 acpi_irq_penalty[link->
irq.possible[i]])
562 irq = link->
irq.possible[
i];
567 if (acpi_pci_link_set(link, irq)) {
569 "Try pci=noacpi or acpi=off\n",
570 acpi_device_name(link->
device),
571 acpi_device_bid(link->
device));
576 acpi_device_name(link->
device),
577 acpi_device_bid(link->
device), link->
irq.active);
580 link->
irq.initialized = 1;
593 struct acpi_device *
device;
602 link = acpi_driver_data(device);
615 if (acpi_pci_link_allocate(link)) {
620 if (!link->
irq.active) {
629 *triggering = link->
irq.triggering;
631 *polarity = link->
irq.polarity;
633 *name = acpi_device_bid(link->
device);
635 "Link %s is referenced\n",
636 acpi_device_bid(link->
device)));
637 return (link->
irq.active);
646 struct acpi_device *
device;
656 link = acpi_driver_data(device);
663 if (!link->
irq.initialized) {
681 "Link %s is dereferenced\n",
682 acpi_device_bid(link->
device)));
688 return (link->
irq.active);
695 static int acpi_pci_link_add(
struct acpi_device *
device)
709 device->driver_data =
link;
712 result = acpi_pci_link_get_possible(link);
717 acpi_pci_link_get_current(link);
720 acpi_device_bid(device));
721 for (i = 0; i < link->
irq.possible_count; i++) {
722 if (link->
irq.active == link->
irq.possible[i]) {
734 if (!link->
device->status.enabled)
754 if (link->
refcnt && link->
irq.active && link->
irq.initialized)
755 return (acpi_pci_link_set(link, link->
irq.active));
760 static void irqrouter_resume(
void)
765 acpi_pci_link_resume(link);
769 static int acpi_pci_link_remove(
struct acpi_device *device,
int type)
773 link = acpi_driver_data(device);
786 static int __init acpi_irq_penalty_update(
char *
str,
int used)
790 for (i = 0; i < 16; i++) {
825 if (irq >= 0 && irq <
ARRAY_SIZE(acpi_irq_penalty)) {
838 static int __init acpi_irq_isa(
char *str)
840 return acpi_irq_penalty_update(str, 1);
843 __setup(
"acpi_irq_isa=", acpi_irq_isa);
850 static int __init acpi_irq_pci(
char *str)
852 return acpi_irq_penalty_update(str, 0);
855 __setup(
"acpi_irq_pci=", acpi_irq_pci);
857 static int __init acpi_irq_nobalance_set(
char *str)
859 acpi_irq_balance = 0;
863 __setup(
"acpi_irq_nobalance", acpi_irq_nobalance_set);
865 static int __init acpi_irq_balance_set(
char *str)
867 acpi_irq_balance = 1;
871 __setup(
"acpi_irq_balance", acpi_irq_balance_set);
873 static struct syscore_ops irqrouter_syscore_ops = {
874 .resume = irqrouter_resume,
877 static int __init irqrouter_init_ops(
void)
887 static int __init acpi_pci_link_init(
void)
892 if (acpi_irq_balance == -1) {
895 acpi_irq_balance = 1;
897 acpi_irq_balance = 0;