X-Git-Url: http://git.cascardo.info/?a=blobdiff_plain;f=drivers%2Facpi%2Fpci_irq.c;h=891bdf6679f3ea6a21e8ab5a94db27a04b20c0e6;hb=a3a798c88a14b35e5d4ca30716dbc9eb9a1ddfe2;hp=7978c97afb0a7eaba267ab7ca32b3aa61a4274b5;hpb=1350487eeb616889f589e9b8c06bd5077452b7e3;p=cascardo%2Flinux.git diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 7978c97afb0a..891bdf6679f3 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -4,6 +4,8 @@ * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh * Copyright (C) 2002 Dominik Brodowski + * (c) Copyright 2008 Hewlett-Packard Development Company, L.P. + * Bjorn Helgaas * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -42,22 +44,14 @@ ACPI_MODULE_NAME("pci_irq"); struct acpi_prt_entry { - struct list_head node; + struct list_head list; struct acpi_pci_id id; u8 pin; - struct { - acpi_handle handle; - u32 index; - } link; - u32 irq; + acpi_handle link; + u32 index; /* GSI, or link _CRS index */ }; -struct acpi_prt_list { - int count; - struct list_head entries; -}; - -static struct acpi_prt_list acpi_prt; +static LIST_HEAD(acpi_prt_list); static DEFINE_SPINLOCK(acpi_prt_lock); static inline char pin_name(int pin) @@ -72,21 +66,13 @@ static inline char pin_name(int pin) static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(struct pci_dev *dev, int pin) { - struct acpi_prt_entry *entry = NULL; + struct acpi_prt_entry *entry; int segment = pci_domain_nr(dev->bus); int bus = dev->bus->number; int device = PCI_SLOT(dev->devfn); - if (!acpi_prt.count) - return NULL; - - /* - * Parse through all PRT entries looking for a match on the specified - * PCI device's segment, bus, device, and pin (don't care about func). - * - */ spin_lock(&acpi_prt_lock); - list_for_each_entry(entry, &acpi_prt.entries, node) { + list_for_each_entry(entry, &acpi_prt_list, list) { if ((segment == entry->id.segment) && (bus == entry->id.bus) && (device == entry->id.device) @@ -95,7 +81,6 @@ static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(struct pci_dev *dev, return entry; } } - spin_unlock(&acpi_prt_lock); return NULL; } @@ -166,8 +151,8 @@ static struct prt_quirk prt_quirks[] = { "\\_SB_.PCI0.LNK3"}, }; -static void -do_prt_fixups(struct acpi_prt_entry *entry, struct acpi_pci_routing_table *prt) +static void do_prt_fixups(struct acpi_prt_entry *entry, + struct acpi_pci_routing_table *prt) { int i; struct prt_quirk *quirk; @@ -197,11 +182,10 @@ do_prt_fixups(struct acpi_prt_entry *entry, struct acpi_pci_routing_table *prt) } } -static int -acpi_pci_irq_add_entry(acpi_handle handle, - int segment, int bus, struct acpi_pci_routing_table *prt) +static int acpi_pci_irq_add_entry(acpi_handle handle, int segment, int bus, + struct acpi_pci_routing_table *prt) { - struct acpi_prt_entry *entry = NULL; + struct acpi_prt_entry *entry; entry = kzalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL); if (!entry) @@ -219,6 +203,8 @@ acpi_pci_irq_add_entry(acpi_handle handle, do_prt_fixups(entry, prt); + entry->index = prt->source_index; + /* * Type 1: Dynamic * --------------- @@ -232,10 +218,9 @@ acpi_pci_irq_add_entry(acpi_handle handle, * (e.g. exists somewhere 'below' this _PRT entry in the ACPI * namespace). */ - if (prt->source[0]) { - acpi_get_handle(handle, prt->source, &entry->link.handle); - entry->link.index = prt->source_index; - } + if (prt->source[0]) + acpi_get_handle(handle, prt->source, &entry->link); + /* * Type 2: Static * -------------- @@ -243,45 +228,25 @@ acpi_pci_irq_add_entry(acpi_handle handle, * the IRQ value, which is hardwired to specific interrupt inputs on * the interrupt controller. */ - else - entry->link.index = prt->source_index; ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO, " %04x:%02x:%02x[%c] -> %s[%d]\n", entry->id.segment, entry->id.bus, entry->id.device, pin_name(entry->pin), - prt->source, entry->link.index)); + prt->source, entry->index)); spin_lock(&acpi_prt_lock); - list_add_tail(&entry->node, &acpi_prt.entries); - acpi_prt.count++; + list_add_tail(&entry->list, &acpi_prt_list); spin_unlock(&acpi_prt_lock); return 0; } -static void -acpi_pci_irq_del_entry(int segment, int bus, struct acpi_prt_entry *entry) -{ - if (segment == entry->id.segment && bus == entry->id.bus) { - acpi_prt.count--; - list_del(&entry->node); - kfree(entry); - } -} - int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus) { acpi_status status; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_pci_routing_table *entry; - static int first_time = 1; - - if (first_time) { - acpi_prt.count = 0; - INIT_LIST_HEAD(&acpi_prt.entries); - first_time = 0; - } /* 'handle' is the _PRT's parent (root bridge or PCI-PCI bridge) */ status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); @@ -317,21 +282,17 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus) void acpi_pci_irq_del_prt(int segment, int bus) { - struct list_head *node = NULL, *n = NULL; - struct acpi_prt_entry *entry = NULL; - - if (!acpi_prt.count) { - return; - } + struct acpi_prt_entry *entry, *tmp; printk(KERN_DEBUG "ACPI: Delete PCI Interrupt Routing Table for %04x:%02x\n", segment, bus); spin_lock(&acpi_prt_lock); - list_for_each_safe(node, n, &acpi_prt.entries) { - entry = list_entry(node, struct acpi_prt_entry, node); - - acpi_pci_irq_del_entry(segment, bus, entry); + list_for_each_entry_safe(entry, tmp, &acpi_prt_list, list) { + if (segment == entry->id.segment && bus == entry->id.bus) { + list_del(&entry->list); + kfree(entry); + } } spin_unlock(&acpi_prt_lock); } @@ -339,99 +300,26 @@ void acpi_pci_irq_del_prt(int segment, int bus) /* -------------------------------------------------------------------------- PCI Interrupt Routing Support -------------------------------------------------------------------------- */ -typedef int (*irq_lookup_func) (struct acpi_prt_entry *, int *, int *, char **); - -static int -acpi_pci_allocate_irq(struct acpi_prt_entry *entry, - int *triggering, int *polarity, char **link) +static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin) { - int irq; - - - if (entry->link.handle) { - irq = acpi_pci_link_allocate_irq(entry->link.handle, - entry->link.index, triggering, - polarity, link); - if (irq < 0) { - printk(KERN_WARNING PREFIX - "Invalid IRQ link routing entry\n"); - return -1; - } - } else { - irq = entry->link.index; - *triggering = ACPI_LEVEL_SENSITIVE; - *polarity = ACPI_ACTIVE_LOW; - } - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found GSI %d\n", irq)); - return irq; -} - -static int -acpi_pci_free_irq(struct acpi_prt_entry *entry, - int *triggering, int *polarity, char **link) -{ - int irq; - - if (entry->link.handle) { - irq = acpi_pci_link_free_irq(entry->link.handle); - } else { - irq = entry->link.index; - } - return irq; -} - -/* - * acpi_pci_irq_lookup - * success: return IRQ >= 0 - * failure: return -1 - */ -static int -acpi_pci_irq_lookup(struct pci_dev *dev, int pin, - int *triggering, - int *polarity, char **link, irq_lookup_func func) -{ - struct acpi_prt_entry *entry = NULL; - int ret; - + struct acpi_prt_entry *entry; + struct pci_dev *bridge; + u8 bridge_pin, orig_pin = pin; entry = acpi_pci_irq_find_prt_entry(dev, pin); - if (!entry) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No %s[%c] _PRT entry\n", + if (entry) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %s[%c] _PRT entry\n", pci_name(dev), pin_name(pin))); - return -1; + return entry; } - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %s[%c] _PRT entry\n", - pci_name(dev), pin_name(pin))); - - ret = func(entry, triggering, polarity, link); - return ret; -} - -/* - * acpi_pci_irq_derive - * success: return IRQ >= 0 - * failure: return < 0 - */ -static int -acpi_pci_irq_derive(struct pci_dev *dev, - int pin, - int *triggering, - int *polarity, char **link, irq_lookup_func func) -{ - struct pci_dev *bridge = dev; - int irq = -1; - u8 bridge_pin = 0, orig_pin = pin; - - /* * Attempt to derive an IRQ for this device from a parent bridge's * PCI interrupt routing entry (eg. yenta bridge and add-in card bridge). */ - while (irq < 0 && bridge->bus->self) { - pin = (((pin - 1) + PCI_SLOT(bridge->devfn)) % 4) + 1; - bridge = bridge->bus->self; + bridge = dev->bus->self; + while (bridge) { + pin = (((pin - 1) + PCI_SLOT(dev->devfn)) % 4) + 1; if ((bridge->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) { /* PC card has the same IRQ as its cardbridge */ @@ -440,45 +328,40 @@ acpi_pci_irq_derive(struct pci_dev *dev, ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No interrupt pin configured for device %s\n", pci_name(bridge))); - return -1; + return NULL; } pin = bridge_pin; } - irq = acpi_pci_irq_lookup(bridge, - pin, triggering, polarity, - link, func); - } + entry = acpi_pci_irq_find_prt_entry(bridge, pin); + if (entry) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Derived GSI for %s INT %c from %s\n", + pci_name(dev), pin_name(orig_pin), + pci_name(bridge))); + return entry; + } - if (irq < 0) { - dev_warn(&dev->dev, "can't derive routing for PCI INT %c\n", - pin_name(orig_pin)); - return -1; + dev = bridge; + bridge = dev->bus->self; } - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Derived GSI %d for %s INT %c from %s\n", - irq, pci_name(dev), pin_name(orig_pin), pci_name(bridge))); - - return irq; + dev_warn(&dev->dev, "can't derive routing for PCI INT %c\n", + pin_name(orig_pin)); + return NULL; } -/* - * acpi_pci_irq_enable - * success: return 0 - * failure: return < 0 - */ - int acpi_pci_irq_enable(struct pci_dev *dev) { - int gsi = 0; - u8 pin = 0; + struct acpi_prt_entry *entry; + int gsi; + u8 pin; int triggering = ACPI_LEVEL_SENSITIVE; int polarity = ACPI_ACTIVE_LOW; char *link = NULL; char link_desc[16]; int rc; - pin = dev->pin; if (!pin) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, @@ -487,24 +370,8 @@ int acpi_pci_irq_enable(struct pci_dev *dev) return 0; } - /* - * First we check the PCI IRQ routing table (PRT) for an IRQ. PRT - * values override any BIOS-assigned IRQs set during boot. - */ - gsi = acpi_pci_irq_lookup(dev, pin, - &triggering, &polarity, &link, - acpi_pci_allocate_irq); - - /* - * If no PRT entry was found, we'll try to derive an IRQ from the - * device's parent bridge. - */ - if (gsi < 0) - gsi = acpi_pci_irq_derive(dev, pin, &triggering, - &polarity, &link, - acpi_pci_allocate_irq); - - if (gsi < 0) { + entry = acpi_pci_irq_lookup(dev, pin); + if (!entry) { /* * IDE legacy mode controller IRQs are magic. Why do compat * extensions always make such a nasty mess. @@ -513,6 +380,18 @@ int acpi_pci_irq_enable(struct pci_dev *dev) (dev->class & 0x05) == 0) return 0; } + + if (entry) { + if (entry->link) + gsi = acpi_pci_link_allocate_irq(entry->link, + entry->index, + &triggering, &polarity, + &link); + else + gsi = entry->index; + } else + gsi = -1; + /* * No IRQ known to the ACPI subsystem - maybe the BIOS / * driver reported one, then use it. Exit in any case. @@ -559,33 +438,23 @@ void __attribute__ ((weak)) acpi_unregister_gsi(u32 i) void acpi_pci_irq_disable(struct pci_dev *dev) { - int gsi = 0; - u8 pin = 0; - int triggering = ACPI_LEVEL_SENSITIVE; - int polarity = ACPI_ACTIVE_LOW; - + struct acpi_prt_entry *entry; + int gsi; + u8 pin; pin = dev->pin; if (!pin) return; - /* - * First we check the PCI IRQ routing table (PRT) for an IRQ. - */ - gsi = acpi_pci_irq_lookup(dev, pin, - &triggering, &polarity, NULL, - acpi_pci_free_irq); - /* - * If no PRT entry was found, we'll try to derive an IRQ from the - * device's parent bridge. - */ - if (gsi < 0) - gsi = acpi_pci_irq_derive(dev, pin, - &triggering, &polarity, NULL, - acpi_pci_free_irq); - if (gsi < 0) + entry = acpi_pci_irq_lookup(dev, pin); + if (!entry) return; + if (entry->link) + gsi = acpi_pci_link_free_irq(entry->link); + else + gsi = entry->index; + /* * TBD: It might be worth clearing dev->irq by magic constant * (e.g. PCI_UNDEFINED_IRQ).