|
@@ -53,9 +53,6 @@ struct acpi_prt_entry {
|
|
|
u32 index; /* GSI, or link _CRS index */
|
|
|
};
|
|
|
|
|
|
-static LIST_HEAD(acpi_prt_list);
|
|
|
-static DEFINE_SPINLOCK(acpi_prt_lock);
|
|
|
-
|
|
|
static inline char pin_name(int pin)
|
|
|
{
|
|
|
return 'A' + pin - 1;
|
|
@@ -65,28 +62,6 @@ static inline char pin_name(int pin)
|
|
|
PCI IRQ Routing Table (PRT) Support
|
|
|
-------------------------------------------------------------------------- */
|
|
|
|
|
|
-static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(struct pci_dev *dev,
|
|
|
- int pin)
|
|
|
-{
|
|
|
- struct acpi_prt_entry *entry;
|
|
|
- int segment = pci_domain_nr(dev->bus);
|
|
|
- int bus = dev->bus->number;
|
|
|
- int device = PCI_SLOT(dev->devfn);
|
|
|
-
|
|
|
- spin_lock(&acpi_prt_lock);
|
|
|
- list_for_each_entry(entry, &acpi_prt_list, list) {
|
|
|
- if ((segment == entry->id.segment)
|
|
|
- && (bus == entry->id.bus)
|
|
|
- && (device == entry->id.device)
|
|
|
- && (pin == entry->pin)) {
|
|
|
- spin_unlock(&acpi_prt_lock);
|
|
|
- return entry;
|
|
|
- }
|
|
|
- }
|
|
|
- spin_unlock(&acpi_prt_lock);
|
|
|
- return NULL;
|
|
|
-}
|
|
|
-
|
|
|
/* http://bugzilla.kernel.org/show_bug.cgi?id=4773 */
|
|
|
static const struct dmi_system_id medion_md9580[] = {
|
|
|
{
|
|
@@ -184,11 +159,19 @@ static void do_prt_fixups(struct acpi_prt_entry *entry,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-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_check_entry(acpi_handle handle, struct pci_dev *dev,
|
|
|
+ int pin, struct acpi_pci_routing_table *prt,
|
|
|
+ struct acpi_prt_entry **entry_ptr)
|
|
|
{
|
|
|
+ int segment = pci_domain_nr(dev->bus);
|
|
|
+ int bus = dev->bus->number;
|
|
|
+ int device = PCI_SLOT(dev->devfn);
|
|
|
struct acpi_prt_entry *entry;
|
|
|
|
|
|
+ if (((prt->address >> 16) & 0xffff) != device ||
|
|
|
+ prt->pin + 1 != pin)
|
|
|
+ return -ENODEV;
|
|
|
+
|
|
|
entry = kzalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL);
|
|
|
if (!entry)
|
|
|
return -ENOMEM;
|
|
@@ -237,43 +220,37 @@ static int acpi_pci_irq_add_entry(acpi_handle handle, int segment, int bus,
|
|
|
entry->id.device, pin_name(entry->pin),
|
|
|
prt->source, entry->index));
|
|
|
|
|
|
- spin_lock(&acpi_prt_lock);
|
|
|
- list_add_tail(&entry->list, &acpi_prt_list);
|
|
|
- spin_unlock(&acpi_prt_lock);
|
|
|
+ *entry_ptr = entry;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus)
|
|
|
+static int acpi_pci_irq_find_prt_entry(struct pci_dev *dev,
|
|
|
+ int pin, struct acpi_prt_entry **entry_ptr)
|
|
|
{
|
|
|
acpi_status status;
|
|
|
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
|
|
struct acpi_pci_routing_table *entry;
|
|
|
+ acpi_handle handle = NULL;
|
|
|
|
|
|
- /* 'handle' is the _PRT's parent (root bridge or PCI-PCI bridge) */
|
|
|
- status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
|
|
|
- if (ACPI_FAILURE(status))
|
|
|
- return -ENODEV;
|
|
|
-
|
|
|
- printk(KERN_DEBUG "ACPI: PCI Interrupt Routing Table [%s._PRT]\n",
|
|
|
- (char *) buffer.pointer);
|
|
|
-
|
|
|
- kfree(buffer.pointer);
|
|
|
+ if (dev->bus->bridge)
|
|
|
+ handle = ACPI_HANDLE(dev->bus->bridge);
|
|
|
|
|
|
- buffer.length = ACPI_ALLOCATE_BUFFER;
|
|
|
- buffer.pointer = NULL;
|
|
|
+ if (!handle)
|
|
|
+ return -ENODEV;
|
|
|
|
|
|
+ /* 'handle' is the _PRT's parent (root bridge or PCI-PCI bridge) */
|
|
|
status = acpi_get_irq_routing_table(handle, &buffer);
|
|
|
if (ACPI_FAILURE(status)) {
|
|
|
- ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRT [%s]",
|
|
|
- acpi_format_exception(status)));
|
|
|
kfree(buffer.pointer);
|
|
|
return -ENODEV;
|
|
|
}
|
|
|
|
|
|
entry = buffer.pointer;
|
|
|
while (entry && (entry->length > 0)) {
|
|
|
- acpi_pci_irq_add_entry(handle, segment, bus, entry);
|
|
|
+ if (!acpi_pci_irq_check_entry(handle, dev, pin,
|
|
|
+ entry, entry_ptr))
|
|
|
+ break;
|
|
|
entry = (struct acpi_pci_routing_table *)
|
|
|
((unsigned long)entry + entry->length);
|
|
|
}
|
|
@@ -282,23 +259,6 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-void acpi_pci_irq_del_prt(int segment, int bus)
|
|
|
-{
|
|
|
- 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_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);
|
|
|
-}
|
|
|
-
|
|
|
/* --------------------------------------------------------------------------
|
|
|
PCI Interrupt Routing Support
|
|
|
-------------------------------------------------------------------------- */
|
|
@@ -359,12 +319,13 @@ static int acpi_reroute_boot_interrupt(struct pci_dev *dev,
|
|
|
|
|
|
static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin)
|
|
|
{
|
|
|
- struct acpi_prt_entry *entry;
|
|
|
+ struct acpi_prt_entry *entry = NULL;
|
|
|
struct pci_dev *bridge;
|
|
|
u8 bridge_pin, orig_pin = pin;
|
|
|
+ int ret;
|
|
|
|
|
|
- entry = acpi_pci_irq_find_prt_entry(dev, pin);
|
|
|
- if (entry) {
|
|
|
+ ret = acpi_pci_irq_find_prt_entry(dev, pin, &entry);
|
|
|
+ if (!ret && entry) {
|
|
|
#ifdef CONFIG_X86_IO_APIC
|
|
|
acpi_reroute_boot_interrupt(dev, entry);
|
|
|
#endif /* CONFIG_X86_IO_APIC */
|
|
@@ -373,7 +334,7 @@ static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin)
|
|
|
return entry;
|
|
|
}
|
|
|
|
|
|
- /*
|
|
|
+ /*
|
|
|
* 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).
|
|
|
*/
|
|
@@ -393,8 +354,8 @@ static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin)
|
|
|
pin = bridge_pin;
|
|
|
}
|
|
|
|
|
|
- entry = acpi_pci_irq_find_prt_entry(bridge, pin);
|
|
|
- if (entry) {
|
|
|
+ ret = acpi_pci_irq_find_prt_entry(bridge, pin, &entry);
|
|
|
+ if (!ret && entry) {
|
|
|
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
|
|
"Derived GSI for %s INT %c from %s\n",
|
|
|
pci_name(dev), pin_name(orig_pin),
|
|
@@ -470,6 +431,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
|
|
|
dev_warn(&dev->dev, "PCI INT %c: no GSI\n",
|
|
|
pin_name(pin));
|
|
|
}
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -477,6 +439,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
|
|
|
if (rc < 0) {
|
|
|
dev_warn(&dev->dev, "PCI INT %c: failed to register GSI\n",
|
|
|
pin_name(pin));
|
|
|
+ kfree(entry);
|
|
|
return rc;
|
|
|
}
|
|
|
dev->irq = rc;
|
|
@@ -491,6 +454,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
|
|
|
(triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge",
|
|
|
(polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq);
|
|
|
|
|
|
+ kfree(entry);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -513,6 +477,8 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
|
|
|
else
|
|
|
gsi = entry->index;
|
|
|
|
|
|
+ kfree(entry);
|
|
|
+
|
|
|
/*
|
|
|
* TBD: It might be worth clearing dev->irq by magic constant
|
|
|
* (e.g. PCI_UNDEFINED_IRQ).
|