X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Facpi%2Fpci_irq.c;h=65aee79b3971fc02f25b8faa53528ece37b0fd64;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=8dbf802ee7f819d9c885247a35d0d736ca4a5979;hpb=cee37fe97739d85991964371c1f3a745c00dd236;p=linux-2.6.git diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 8dbf802ee..65aee79b3 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -38,26 +38,22 @@ #include #include - #define _COMPONENT ACPI_PCI_COMPONENT -ACPI_MODULE_NAME ("pci_irq") +ACPI_MODULE_NAME("pci_irq") -static struct acpi_prt_list acpi_prt; +static struct acpi_prt_list acpi_prt; static DEFINE_SPINLOCK(acpi_prt_lock); /* -------------------------------------------------------------------------- PCI IRQ Routing Table (PRT) Support -------------------------------------------------------------------------- */ -static struct acpi_prt_entry * -acpi_pci_irq_find_prt_entry ( - int segment, - int bus, - int device, - int pin) +static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(int segment, + int bus, + int device, int pin) { - struct list_head *node = NULL; - struct acpi_prt_entry *entry = NULL; + struct list_head *node = NULL; + struct acpi_prt_entry *entry = NULL; ACPI_FUNCTION_TRACE("acpi_pci_irq_find_prt_entry"); @@ -72,10 +68,10 @@ acpi_pci_irq_find_prt_entry ( spin_lock(&acpi_prt_lock); list_for_each(node, &acpi_prt.entries) { entry = list_entry(node, struct acpi_prt_entry, node); - if ((segment == entry->id.segment) - && (bus == entry->id.bus) - && (device == entry->id.device) - && (pin == entry->pin)) { + if ((segment == entry->id.segment) + && (bus == entry->id.bus) + && (device == entry->id.device) + && (pin == entry->pin)) { spin_unlock(&acpi_prt_lock); return_PTR(entry); } @@ -85,15 +81,11 @@ acpi_pci_irq_find_prt_entry ( return_PTR(NULL); } - static int -acpi_pci_irq_add_entry ( - acpi_handle handle, - int segment, - int bus, - struct acpi_pci_routing_table *prt) +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 = NULL; ACPI_FUNCTION_TRACE("acpi_pci_irq_add_entry"); @@ -139,9 +131,10 @@ acpi_pci_irq_add_entry ( entry->link.index = prt->source_index; ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO, - " %02X:%02X:%02X[%c] -> %s[%d]\n", - entry->id.segment, entry->id.bus, entry->id.device, - ('A' + entry->pin), prt->source, entry->link.index)); + " %02X:%02X:%02X[%c] -> %s[%d]\n", + entry->id.segment, entry->id.bus, + entry->id.device, ('A' + entry->pin), prt->source, + entry->link.index)); spin_lock(&acpi_prt_lock); list_add_tail(&entry->node, &acpi_prt.entries); @@ -151,38 +144,29 @@ acpi_pci_irq_add_entry ( return_VALUE(0); } - static void -acpi_pci_irq_del_entry ( - int segment, - int bus, - struct acpi_prt_entry *entry) +acpi_pci_irq_del_entry(int segment, int bus, struct acpi_prt_entry *entry) { - if (segment == entry->id.segment && bus == entry->id.bus){ + 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) +int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus) { - acpi_status status = AE_OK; - char *pathname = NULL; - struct acpi_buffer buffer = {0, NULL}; - struct acpi_pci_routing_table *prt = NULL; - struct acpi_pci_routing_table *entry = NULL; - static int first_time = 1; + acpi_status status = AE_OK; + char *pathname = NULL; + struct acpi_buffer buffer = { 0, NULL }; + struct acpi_pci_routing_table *prt = NULL; + struct acpi_pci_routing_table *entry = NULL; + static int first_time = 1; ACPI_FUNCTION_TRACE("acpi_pci_irq_add_prt"); - pathname = (char *) kmalloc(ACPI_PATHNAME_MAX, GFP_KERNEL); - if(!pathname) + pathname = (char *)kmalloc(ACPI_PATHNAME_MAX, GFP_KERNEL); + if (!pathname) return_VALUE(-ENOMEM); memset(pathname, 0, ACPI_PATHNAME_MAX); @@ -202,7 +186,7 @@ acpi_pci_irq_add_prt ( acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); printk(KERN_DEBUG "ACPI: PCI Interrupt Routing Table [%s._PRT]\n", - pathname); + pathname); /* * Evaluate this _PRT and add its entries to our global list (acpi_prt). @@ -214,12 +198,12 @@ acpi_pci_irq_add_prt ( status = acpi_get_irq_routing_table(handle, &buffer); if (status != AE_BUFFER_OVERFLOW) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRT [%s]\n", - acpi_format_exception(status))); + acpi_format_exception(status))); return_VALUE(-ENODEV); } prt = kmalloc(buffer.length, GFP_KERNEL); - if (!prt){ + if (!prt) { return_VALUE(-ENOMEM); } memset(prt, 0, buffer.length); @@ -228,7 +212,7 @@ acpi_pci_irq_add_prt ( status = acpi_get_irq_routing_table(handle, &buffer); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRT [%s]\n", - acpi_format_exception(status))); + acpi_format_exception(status))); kfree(buffer.pointer); return_VALUE(-ENODEV); } @@ -238,7 +222,7 @@ acpi_pci_irq_add_prt ( while (entry && (entry->length > 0)) { acpi_pci_irq_add_entry(handle, segment, bus, entry); entry = (struct acpi_pci_routing_table *) - ((unsigned long) entry + entry->length); + ((unsigned long)entry + entry->length); } kfree(prt); @@ -246,18 +230,18 @@ acpi_pci_irq_add_prt ( return_VALUE(0); } -void -acpi_pci_irq_del_prt (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; + struct list_head *node = NULL, *n = NULL; + struct acpi_prt_entry *entry = NULL; - if (!acpi_prt.count) { + if (!acpi_prt.count) { return; } - printk(KERN_DEBUG "ACPI: Delete PCI Interrupt Routing Table for %x:%x\n", - segment, bus); + printk(KERN_DEBUG + "ACPI: Delete PCI Interrupt Routing Table for %x:%x\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); @@ -266,9 +250,53 @@ acpi_pci_irq_del_prt (int segment, int bus) } spin_unlock(&acpi_prt_lock); } + /* -------------------------------------------------------------------------- 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) +{ + int irq; + + ACPI_FUNCTION_TRACE("acpi_pci_allocate_irq"); + + if (entry->link.handle) { + irq = acpi_pci_link_allocate_irq(entry->link.handle, + entry->link.index, triggering, + polarity, link); + if (irq < 0) { + ACPI_DEBUG_PRINT((ACPI_DB_WARN, + "Invalid IRQ link routing entry\n")); + return_VALUE(-1); + } + } else { + irq = entry->link.index; + *triggering = ACPI_LEVEL_SENSITIVE; + *polarity = ACPI_ACTIVE_LOW; + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IRQ %d\n", irq)); + return_VALUE(irq); +} + +static int +acpi_pci_free_irq(struct acpi_prt_entry *entry, + int *triggering, int *polarity, char **link) +{ + int irq; + + ACPI_FUNCTION_TRACE("acpi_pci_free_irq"); + if (entry->link.handle) { + irq = acpi_pci_link_free_irq(entry->link.handle); + } else { + irq = entry->link.index; + } + return_VALUE(irq); +} /* * acpi_pci_irq_lookup @@ -276,47 +304,31 @@ acpi_pci_irq_del_prt (int segment, int bus) * failure: return -1 */ static int -acpi_pci_irq_lookup ( - struct pci_bus *bus, - int device, - int pin, - int *edge_level, - int *active_high_low, - char **link) +acpi_pci_irq_lookup(struct pci_bus *bus, + int device, + int pin, + int *triggering, + int *polarity, char **link, irq_lookup_func func) { - struct acpi_prt_entry *entry = NULL; + struct acpi_prt_entry *entry = NULL; int segment = pci_domain_nr(bus); int bus_nr = bus->number; - int irq; + int ret; ACPI_FUNCTION_TRACE("acpi_pci_irq_lookup"); - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Searching for PRT entry for %02x:%02x:%02x[%c]\n", - segment, bus_nr, device, ('A' + pin))); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Searching for PRT entry for %02x:%02x:%02x[%c]\n", + segment, bus_nr, device, ('A' + pin))); - entry = acpi_pci_irq_find_prt_entry(segment, bus_nr, device, pin); + entry = acpi_pci_irq_find_prt_entry(segment, bus_nr, device, pin); if (!entry) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "PRT entry not found\n")); return_VALUE(-1); } - - if (entry->link.handle) { - irq = acpi_pci_link_get_irq(entry->link.handle, - entry->link.index, edge_level, active_high_low, link); - if (irq < 0) { - ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid IRQ link routing entry\n")); - return_VALUE(-1); - } - } else { - irq = entry->link.index; - *edge_level = ACPI_LEVEL_SENSITIVE; - *active_high_low = ACPI_ACTIVE_LOW; - } - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IRQ %d\n", irq)); - - return_VALUE(irq); + ret = func(entry, triggering, polarity, link); + return_VALUE(ret); } /* @@ -325,16 +337,14 @@ acpi_pci_irq_lookup ( * failure: return < 0 */ static int -acpi_pci_irq_derive ( - struct pci_dev *dev, - int pin, - int *edge_level, - int *active_high_low, - char **link) +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; + struct pci_dev *bridge = dev; + int irq = -1; + u8 bridge_pin = 0; ACPI_FUNCTION_TRACE("acpi_pci_irq_derive"); @@ -351,28 +361,32 @@ acpi_pci_irq_derive ( if ((bridge->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) { /* PC card has the same IRQ as its cardbridge */ - pci_read_config_byte(bridge, PCI_INTERRUPT_PIN, &bridge_pin); + bridge_pin = bridge->pin; if (!bridge_pin) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "No interrupt pin configured for device %s\n", pci_name(bridge))); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "No interrupt pin configured for device %s\n", + pci_name(bridge))); return_VALUE(-1); } /* Pin is from 0 to 3 */ - bridge_pin --; + bridge_pin--; pin = bridge_pin; } irq = acpi_pci_irq_lookup(bridge->bus, PCI_SLOT(bridge->devfn), - pin, edge_level, active_high_low, link); + pin, triggering, polarity, + link, func); } if (irq < 0) { - ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Unable to derive IRQ for device %s\n", pci_name(dev))); + ACPI_DEBUG_PRINT((ACPI_DB_WARN, + "Unable to derive IRQ for device %s\n", + pci_name(dev))); return_VALUE(-1); } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Derive IRQ %d for device %s from %s\n", - irq, pci_name(dev), pci_name(bridge))); + irq, pci_name(dev), pci_name(bridge))); return_VALUE(irq); } @@ -383,30 +397,32 @@ acpi_pci_irq_derive ( * failure: return < 0 */ -int -acpi_pci_irq_enable ( - struct pci_dev *dev) +int acpi_pci_irq_enable(struct pci_dev *dev) { - int irq = 0; - u8 pin = 0; - int edge_level = ACPI_LEVEL_SENSITIVE; - int active_high_low = ACPI_ACTIVE_LOW; - char *link = NULL; + int irq = 0; + u8 pin = 0; + int triggering = ACPI_LEVEL_SENSITIVE; + int polarity = ACPI_ACTIVE_LOW; + char *link = NULL; + int rc; ACPI_FUNCTION_TRACE("acpi_pci_irq_enable"); if (!dev) return_VALUE(-EINVAL); - - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + + pin = dev->pin; if (!pin) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No interrupt pin configured for device %s\n", pci_name(dev))); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "No interrupt pin configured for device %s\n", + pci_name(dev))); return_VALUE(0); } pin--; if (!dev->bus) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid (NULL) 'bus' field\n")); + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, + "Invalid (NULL) 'bus' field\n")); return_VALUE(-ENODEV); } @@ -414,89 +430,97 @@ acpi_pci_irq_enable ( * First we check the PCI IRQ routing table (PRT) for an IRQ. PRT * values override any BIOS-assigned IRQs set during boot. */ - irq = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin, - &edge_level, &active_high_low, &link); + irq = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), 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 (irq < 0) - irq = acpi_pci_irq_derive(dev, pin, &edge_level, - &active_high_low, &link); - + irq = acpi_pci_irq_derive(dev, pin, &triggering, + &polarity, &link, + acpi_pci_allocate_irq); + /* * No IRQ known to the ACPI subsystem - maybe the BIOS / * driver reported one, then use it. Exit in any case. */ if (irq < 0) { printk(KERN_WARNING PREFIX "PCI Interrupt %s[%c]: no GSI", - pci_name(dev), ('A' + pin)); + pci_name(dev), ('A' + pin)); /* Interrupt Line values above 0xF are forbidden */ - if (dev->irq >= 0 && (dev->irq <= 0xF)) { + if (dev->irq > 0 && (dev->irq <= 0xF)) { printk(" - using IRQ %d\n", dev->irq); - acpi_register_gsi(dev->irq, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW); + acpi_register_gsi(dev->irq, ACPI_LEVEL_SENSITIVE, + ACPI_ACTIVE_LOW); return_VALUE(0); - } - else { + } else { printk("\n"); return_VALUE(0); } - } + } - dev->irq = acpi_register_gsi(irq, edge_level, active_high_low); + rc = acpi_register_gsi(irq, triggering, polarity); + if (rc < 0) { + printk(KERN_WARNING PREFIX "PCI Interrupt %s[%c]: failed " + "to register GSI\n", pci_name(dev), ('A' + pin)); + return_VALUE(rc); + } + dev->irq = rc; printk(KERN_INFO PREFIX "PCI Interrupt %s[%c] -> ", - pci_name(dev), 'A' + pin); + pci_name(dev), 'A' + pin); if (link) printk("Link [%s] -> ", link); printk("GSI %u (%s, %s) -> IRQ %d\n", irq, - (edge_level == ACPI_LEVEL_SENSITIVE) ? "level" : "edge", - (active_high_low == ACPI_ACTIVE_LOW) ? "low" : "high", - dev->irq); + (triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge", + (polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq); return_VALUE(0); } + EXPORT_SYMBOL(acpi_pci_irq_enable); +/* FIXME: implement x86/x86_64 version */ +void __attribute__ ((weak)) acpi_unregister_gsi(u32 i) +{ +} -#ifdef CONFIG_ACPI_DEALLOCATE_IRQ -void -acpi_pci_irq_disable ( - struct pci_dev *dev) +void acpi_pci_irq_disable(struct pci_dev *dev) { - int gsi = 0; - u8 pin = 0; - int edge_level = ACPI_LEVEL_SENSITIVE; - int active_high_low = ACPI_ACTIVE_LOW; + int gsi = 0; + u8 pin = 0; + int triggering = ACPI_LEVEL_SENSITIVE; + int polarity = ACPI_ACTIVE_LOW; ACPI_FUNCTION_TRACE("acpi_pci_irq_disable"); - if (!dev) + if (!dev || !dev->bus) return_VOID; - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + pin = dev->pin; if (!pin) return_VOID; pin--; - if (!dev->bus) - return_VOID; - /* * First we check the PCI IRQ routing table (PRT) for an IRQ. */ - gsi = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin, - &edge_level, &active_high_low, NULL); + gsi = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), 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, - &edge_level, &active_high_low, NULL); + gsi = acpi_pci_irq_derive(dev, pin, + &triggering, &polarity, NULL, + acpi_pci_free_irq); if (gsi < 0) return_VOID; @@ -512,4 +536,3 @@ acpi_pci_irq_disable ( return_VOID; } -#endif /* CONFIG_ACPI_DEALLOCATE_IRQ */