diff options
Diffstat (limited to 'drivers/acpi/pci_irq.c')
| -rw-r--r-- | drivers/acpi/pci_irq.c | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 7f19859580c7..7af414a3c63e 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | */ | 25 | */ |
| 26 | 26 | ||
| 27 | 27 | ||
| 28 | #include <linux/dmi.h> | ||
| 28 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
| 29 | #include <linux/module.h> | 30 | #include <linux/module.h> |
| 30 | #include <linux/init.h> | 31 | #include <linux/init.h> |
| @@ -76,6 +77,101 @@ static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(int segment, | |||
| 76 | return NULL; | 77 | return NULL; |
| 77 | } | 78 | } |
| 78 | 79 | ||
| 80 | /* http://bugzilla.kernel.org/show_bug.cgi?id=4773 */ | ||
| 81 | static struct dmi_system_id medion_md9580[] = { | ||
| 82 | { | ||
| 83 | .ident = "Medion MD9580-F laptop", | ||
| 84 | .matches = { | ||
| 85 | DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"), | ||
| 86 | DMI_MATCH(DMI_PRODUCT_NAME, "A555"), | ||
| 87 | }, | ||
| 88 | }, | ||
| 89 | { } | ||
| 90 | }; | ||
| 91 | |||
| 92 | /* http://bugzilla.kernel.org/show_bug.cgi?id=5044 */ | ||
| 93 | static struct dmi_system_id dell_optiplex[] = { | ||
| 94 | { | ||
| 95 | .ident = "Dell Optiplex GX1", | ||
| 96 | .matches = { | ||
| 97 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), | ||
| 98 | DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex GX1 600S+"), | ||
| 99 | }, | ||
| 100 | }, | ||
| 101 | { } | ||
| 102 | }; | ||
| 103 | |||
| 104 | /* http://bugzilla.kernel.org/show_bug.cgi?id=10138 */ | ||
| 105 | static struct dmi_system_id hp_t5710[] = { | ||
| 106 | { | ||
| 107 | .ident = "HP t5710", | ||
| 108 | .matches = { | ||
| 109 | DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), | ||
| 110 | DMI_MATCH(DMI_PRODUCT_NAME, "hp t5000 series"), | ||
| 111 | DMI_MATCH(DMI_BOARD_NAME, "098Ch"), | ||
| 112 | }, | ||
| 113 | }, | ||
| 114 | { } | ||
| 115 | }; | ||
| 116 | |||
| 117 | struct prt_quirk { | ||
| 118 | struct dmi_system_id *system; | ||
| 119 | unsigned int segment; | ||
| 120 | unsigned int bus; | ||
| 121 | unsigned int device; | ||
| 122 | unsigned char pin; | ||
| 123 | char *source; /* according to BIOS */ | ||
| 124 | char *actual_source; | ||
| 125 | }; | ||
| 126 | |||
| 127 | /* | ||
| 128 | * These systems have incorrect _PRT entries. The BIOS claims the PCI | ||
| 129 | * interrupt at the listed segment/bus/device/pin is connected to the first | ||
| 130 | * link device, but it is actually connected to the second. | ||
| 131 | */ | ||
| 132 | static struct prt_quirk prt_quirks[] = { | ||
| 133 | { medion_md9580, 0, 0, 9, 'A', | ||
| 134 | "\\_SB_.PCI0.ISA.LNKA", | ||
| 135 | "\\_SB_.PCI0.ISA.LNKB"}, | ||
| 136 | { dell_optiplex, 0, 0, 0xd, 'A', | ||
| 137 | "\\_SB_.LNKB", | ||
| 138 | "\\_SB_.LNKA"}, | ||
| 139 | { hp_t5710, 0, 0, 1, 'A', | ||
| 140 | "\\_SB_.PCI0.LNK1", | ||
| 141 | "\\_SB_.PCI0.LNK3"}, | ||
| 142 | }; | ||
| 143 | |||
| 144 | static void | ||
| 145 | do_prt_fixups(struct acpi_prt_entry *entry, struct acpi_pci_routing_table *prt) | ||
| 146 | { | ||
| 147 | int i; | ||
| 148 | struct prt_quirk *quirk; | ||
| 149 | |||
| 150 | for (i = 0; i < ARRAY_SIZE(prt_quirks); i++) { | ||
| 151 | quirk = &prt_quirks[i]; | ||
| 152 | |||
| 153 | /* All current quirks involve link devices, not GSIs */ | ||
| 154 | if (!prt->source) | ||
| 155 | continue; | ||
| 156 | |||
| 157 | if (dmi_check_system(quirk->system) && | ||
| 158 | entry->id.segment == quirk->segment && | ||
| 159 | entry->id.bus == quirk->bus && | ||
| 160 | entry->id.device == quirk->device && | ||
| 161 | entry->pin + 'A' == quirk->pin && | ||
| 162 | !strcmp(prt->source, quirk->source) && | ||
| 163 | strlen(prt->source) >= strlen(quirk->actual_source)) { | ||
| 164 | printk(KERN_WARNING PREFIX "firmware reports " | ||
| 165 | "%04x:%02x:%02x[%c] connected to %s; " | ||
| 166 | "changing to %s\n", | ||
| 167 | entry->id.segment, entry->id.bus, | ||
| 168 | entry->id.device, 'A' + entry->pin, | ||
| 169 | prt->source, quirk->actual_source); | ||
| 170 | strcpy(prt->source, quirk->actual_source); | ||
| 171 | } | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 79 | static int | 175 | static int |
| 80 | acpi_pci_irq_add_entry(acpi_handle handle, | 176 | acpi_pci_irq_add_entry(acpi_handle handle, |
| 81 | int segment, int bus, struct acpi_pci_routing_table *prt) | 177 | int segment, int bus, struct acpi_pci_routing_table *prt) |
| @@ -96,6 +192,8 @@ acpi_pci_irq_add_entry(acpi_handle handle, | |||
| 96 | entry->id.function = prt->address & 0xFFFF; | 192 | entry->id.function = prt->address & 0xFFFF; |
| 97 | entry->pin = prt->pin; | 193 | entry->pin = prt->pin; |
| 98 | 194 | ||
| 195 | do_prt_fixups(entry, prt); | ||
| 196 | |||
| 99 | /* | 197 | /* |
| 100 | * Type 1: Dynamic | 198 | * Type 1: Dynamic |
| 101 | * --------------- | 199 | * --------------- |
