diff options
author | Yinghai Lu <yinghai@kernel.org> | 2013-02-16 13:58:34 -0500 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2013-02-16 13:58:34 -0500 |
commit | 181380b702eee1a9aca51354d7b87c7b08541fcf (patch) | |
tree | c95dc8c7649fe97c18a99d3ee69ad014adf8cfaa /drivers/acpi/pci_irq.c | |
parent | be6d2867b4f68a575c78fa368abd3ad49980c514 (diff) |
PCI/ACPI: Don't cache _PRT, and don't associate them with bus numbers
Previously, we cached _PRT (PCI routing table, ACPI 5.0 sec 6.2.12)
contents and associated each _PRT entry with a PCI bus number. The bus
number association means dependencies on PCI device enumeration and bus
number assignment, as well as on the PCI/ACPI binding process.
After 4f535093cf ("PCI: Put pci_dev in device tree as early as possible"),
these dependencies caused the IRQ issues reported by Peter:
pci 0000:00:1e.0: PCI bridge to [bus 09] (subtractive decode)
pci 0000:00:1e.0: can't derive routing for PCI INT A
snd_ctxfi 0000:09:02.0: PCI INT A: no GSI - using ISA IRQ 5
irq 18: nobody cared (try booting with the "irqpoll" option)
This patch removes _PRT caching. Instead, we evaluate _PRT as needed
in the pci_enable_device() path. This also removes the dependency on
PCI bus numbers: we can simply look at the _PRT associated with each
bridge as we walk upstream toward the root.
[bhelgaas: changelog]
Reference: https://bugzilla.kernel.org/show_bug.cgi?id=53561
Reported-and-tested-by: Peter Hurley <peter@hurleysoftware.com>
Suggested-by: Bjorn Helgaas <bhelgaas@google.com>
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'drivers/acpi/pci_irq.c')
-rw-r--r-- | drivers/acpi/pci_irq.c | 102 |
1 files changed, 34 insertions, 68 deletions
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 68a921d03247..41c5e1b799ef 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c | |||
@@ -53,9 +53,6 @@ struct acpi_prt_entry { | |||
53 | u32 index; /* GSI, or link _CRS index */ | 53 | u32 index; /* GSI, or link _CRS index */ |
54 | }; | 54 | }; |
55 | 55 | ||
56 | static LIST_HEAD(acpi_prt_list); | ||
57 | static DEFINE_SPINLOCK(acpi_prt_lock); | ||
58 | |||
59 | static inline char pin_name(int pin) | 56 | static inline char pin_name(int pin) |
60 | { | 57 | { |
61 | return 'A' + pin - 1; | 58 | return 'A' + pin - 1; |
@@ -65,28 +62,6 @@ static inline char pin_name(int pin) | |||
65 | PCI IRQ Routing Table (PRT) Support | 62 | PCI IRQ Routing Table (PRT) Support |
66 | -------------------------------------------------------------------------- */ | 63 | -------------------------------------------------------------------------- */ |
67 | 64 | ||
68 | static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(struct pci_dev *dev, | ||
69 | int pin) | ||
70 | { | ||
71 | struct acpi_prt_entry *entry; | ||
72 | int segment = pci_domain_nr(dev->bus); | ||
73 | int bus = dev->bus->number; | ||
74 | int device = PCI_SLOT(dev->devfn); | ||
75 | |||
76 | spin_lock(&acpi_prt_lock); | ||
77 | list_for_each_entry(entry, &acpi_prt_list, list) { | ||
78 | if ((segment == entry->id.segment) | ||
79 | && (bus == entry->id.bus) | ||
80 | && (device == entry->id.device) | ||
81 | && (pin == entry->pin)) { | ||
82 | spin_unlock(&acpi_prt_lock); | ||
83 | return entry; | ||
84 | } | ||
85 | } | ||
86 | spin_unlock(&acpi_prt_lock); | ||
87 | return NULL; | ||
88 | } | ||
89 | |||
90 | /* http://bugzilla.kernel.org/show_bug.cgi?id=4773 */ | 65 | /* http://bugzilla.kernel.org/show_bug.cgi?id=4773 */ |
91 | static const struct dmi_system_id medion_md9580[] = { | 66 | static const struct dmi_system_id medion_md9580[] = { |
92 | { | 67 | { |
@@ -184,11 +159,19 @@ static void do_prt_fixups(struct acpi_prt_entry *entry, | |||
184 | } | 159 | } |
185 | } | 160 | } |
186 | 161 | ||
187 | static int acpi_pci_irq_add_entry(acpi_handle handle, int segment, int bus, | 162 | static int acpi_pci_irq_check_entry(acpi_handle handle, struct pci_dev *dev, |
188 | struct acpi_pci_routing_table *prt) | 163 | int pin, struct acpi_pci_routing_table *prt, |
164 | struct acpi_prt_entry **entry_ptr) | ||
189 | { | 165 | { |
166 | int segment = pci_domain_nr(dev->bus); | ||
167 | int bus = dev->bus->number; | ||
168 | int device = PCI_SLOT(dev->devfn); | ||
190 | struct acpi_prt_entry *entry; | 169 | struct acpi_prt_entry *entry; |
191 | 170 | ||
171 | if (((prt->address >> 16) & 0xffff) != device || | ||
172 | prt->pin + 1 != pin) | ||
173 | return -ENODEV; | ||
174 | |||
192 | entry = kzalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL); | 175 | entry = kzalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL); |
193 | if (!entry) | 176 | if (!entry) |
194 | return -ENOMEM; | 177 | return -ENOMEM; |
@@ -237,43 +220,37 @@ static int acpi_pci_irq_add_entry(acpi_handle handle, int segment, int bus, | |||
237 | entry->id.device, pin_name(entry->pin), | 220 | entry->id.device, pin_name(entry->pin), |
238 | prt->source, entry->index)); | 221 | prt->source, entry->index)); |
239 | 222 | ||
240 | spin_lock(&acpi_prt_lock); | 223 | *entry_ptr = entry; |
241 | list_add_tail(&entry->list, &acpi_prt_list); | ||
242 | spin_unlock(&acpi_prt_lock); | ||
243 | 224 | ||
244 | return 0; | 225 | return 0; |
245 | } | 226 | } |
246 | 227 | ||
247 | int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus) | 228 | static int acpi_pci_irq_find_prt_entry(struct pci_dev *dev, |
229 | int pin, struct acpi_prt_entry **entry_ptr) | ||
248 | { | 230 | { |
249 | acpi_status status; | 231 | acpi_status status; |
250 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 232 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
251 | struct acpi_pci_routing_table *entry; | 233 | struct acpi_pci_routing_table *entry; |
234 | acpi_handle handle = NULL; | ||
252 | 235 | ||
253 | /* 'handle' is the _PRT's parent (root bridge or PCI-PCI bridge) */ | 236 | if (dev->bus->bridge) |
254 | status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); | 237 | handle = ACPI_HANDLE(dev->bus->bridge); |
255 | if (ACPI_FAILURE(status)) | ||
256 | return -ENODEV; | ||
257 | |||
258 | printk(KERN_DEBUG "ACPI: PCI Interrupt Routing Table [%s._PRT]\n", | ||
259 | (char *) buffer.pointer); | ||
260 | |||
261 | kfree(buffer.pointer); | ||
262 | 238 | ||
263 | buffer.length = ACPI_ALLOCATE_BUFFER; | 239 | if (!handle) |
264 | buffer.pointer = NULL; | 240 | return -ENODEV; |
265 | 241 | ||
242 | /* 'handle' is the _PRT's parent (root bridge or PCI-PCI bridge) */ | ||
266 | status = acpi_get_irq_routing_table(handle, &buffer); | 243 | status = acpi_get_irq_routing_table(handle, &buffer); |
267 | if (ACPI_FAILURE(status)) { | 244 | if (ACPI_FAILURE(status)) { |
268 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRT [%s]", | ||
269 | acpi_format_exception(status))); | ||
270 | kfree(buffer.pointer); | 245 | kfree(buffer.pointer); |
271 | return -ENODEV; | 246 | return -ENODEV; |
272 | } | 247 | } |
273 | 248 | ||
274 | entry = buffer.pointer; | 249 | entry = buffer.pointer; |
275 | while (entry && (entry->length > 0)) { | 250 | while (entry && (entry->length > 0)) { |
276 | acpi_pci_irq_add_entry(handle, segment, bus, entry); | 251 | if (!acpi_pci_irq_check_entry(handle, dev, pin, |
252 | entry, entry_ptr)) | ||
253 | break; | ||
277 | entry = (struct acpi_pci_routing_table *) | 254 | entry = (struct acpi_pci_routing_table *) |
278 | ((unsigned long)entry + entry->length); | 255 | ((unsigned long)entry + entry->length); |
279 | } | 256 | } |
@@ -282,23 +259,6 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus) | |||
282 | return 0; | 259 | return 0; |
283 | } | 260 | } |
284 | 261 | ||
285 | void acpi_pci_irq_del_prt(int segment, int bus) | ||
286 | { | ||
287 | struct acpi_prt_entry *entry, *tmp; | ||
288 | |||
289 | printk(KERN_DEBUG | ||
290 | "ACPI: Delete PCI Interrupt Routing Table for %04x:%02x\n", | ||
291 | segment, bus); | ||
292 | spin_lock(&acpi_prt_lock); | ||
293 | list_for_each_entry_safe(entry, tmp, &acpi_prt_list, list) { | ||
294 | if (segment == entry->id.segment && bus == entry->id.bus) { | ||
295 | list_del(&entry->list); | ||
296 | kfree(entry); | ||
297 | } | ||
298 | } | ||
299 | spin_unlock(&acpi_prt_lock); | ||
300 | } | ||
301 | |||
302 | /* -------------------------------------------------------------------------- | 262 | /* -------------------------------------------------------------------------- |
303 | PCI Interrupt Routing Support | 263 | PCI Interrupt Routing Support |
304 | -------------------------------------------------------------------------- */ | 264 | -------------------------------------------------------------------------- */ |
@@ -359,12 +319,13 @@ static int acpi_reroute_boot_interrupt(struct pci_dev *dev, | |||
359 | 319 | ||
360 | static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin) | 320 | static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin) |
361 | { | 321 | { |
362 | struct acpi_prt_entry *entry; | 322 | struct acpi_prt_entry *entry = NULL; |
363 | struct pci_dev *bridge; | 323 | struct pci_dev *bridge; |
364 | u8 bridge_pin, orig_pin = pin; | 324 | u8 bridge_pin, orig_pin = pin; |
325 | int ret; | ||
365 | 326 | ||
366 | entry = acpi_pci_irq_find_prt_entry(dev, pin); | 327 | ret = acpi_pci_irq_find_prt_entry(dev, pin, &entry); |
367 | if (entry) { | 328 | if (!ret && entry) { |
368 | #ifdef CONFIG_X86_IO_APIC | 329 | #ifdef CONFIG_X86_IO_APIC |
369 | acpi_reroute_boot_interrupt(dev, entry); | 330 | acpi_reroute_boot_interrupt(dev, entry); |
370 | #endif /* CONFIG_X86_IO_APIC */ | 331 | #endif /* CONFIG_X86_IO_APIC */ |
@@ -373,7 +334,7 @@ static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin) | |||
373 | return entry; | 334 | return entry; |
374 | } | 335 | } |
375 | 336 | ||
376 | /* | 337 | /* |
377 | * Attempt to derive an IRQ for this device from a parent bridge's | 338 | * Attempt to derive an IRQ for this device from a parent bridge's |
378 | * PCI interrupt routing entry (eg. yenta bridge and add-in card bridge). | 339 | * PCI interrupt routing entry (eg. yenta bridge and add-in card bridge). |
379 | */ | 340 | */ |
@@ -393,8 +354,8 @@ static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin) | |||
393 | pin = bridge_pin; | 354 | pin = bridge_pin; |
394 | } | 355 | } |
395 | 356 | ||
396 | entry = acpi_pci_irq_find_prt_entry(bridge, pin); | 357 | ret = acpi_pci_irq_find_prt_entry(bridge, pin, &entry); |
397 | if (entry) { | 358 | if (!ret && entry) { |
398 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 359 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
399 | "Derived GSI for %s INT %c from %s\n", | 360 | "Derived GSI for %s INT %c from %s\n", |
400 | pci_name(dev), pin_name(orig_pin), | 361 | pci_name(dev), pin_name(orig_pin), |
@@ -470,6 +431,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev) | |||
470 | dev_warn(&dev->dev, "PCI INT %c: no GSI\n", | 431 | dev_warn(&dev->dev, "PCI INT %c: no GSI\n", |
471 | pin_name(pin)); | 432 | pin_name(pin)); |
472 | } | 433 | } |
434 | |||
473 | return 0; | 435 | return 0; |
474 | } | 436 | } |
475 | 437 | ||
@@ -477,6 +439,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev) | |||
477 | if (rc < 0) { | 439 | if (rc < 0) { |
478 | dev_warn(&dev->dev, "PCI INT %c: failed to register GSI\n", | 440 | dev_warn(&dev->dev, "PCI INT %c: failed to register GSI\n", |
479 | pin_name(pin)); | 441 | pin_name(pin)); |
442 | kfree(entry); | ||
480 | return rc; | 443 | return rc; |
481 | } | 444 | } |
482 | dev->irq = rc; | 445 | dev->irq = rc; |
@@ -491,6 +454,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev) | |||
491 | (triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge", | 454 | (triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge", |
492 | (polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq); | 455 | (polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq); |
493 | 456 | ||
457 | kfree(entry); | ||
494 | return 0; | 458 | return 0; |
495 | } | 459 | } |
496 | 460 | ||
@@ -513,6 +477,8 @@ void acpi_pci_irq_disable(struct pci_dev *dev) | |||
513 | else | 477 | else |
514 | gsi = entry->index; | 478 | gsi = entry->index; |
515 | 479 | ||
480 | kfree(entry); | ||
481 | |||
516 | /* | 482 | /* |
517 | * TBD: It might be worth clearing dev->irq by magic constant | 483 | * TBD: It might be worth clearing dev->irq by magic constant |
518 | * (e.g. PCI_UNDEFINED_IRQ). | 484 | * (e.g. PCI_UNDEFINED_IRQ). |