diff options
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 68a921d0324..41c5e1b799e 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -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).  |