Skip to content

Commit

Permalink
[ACPI] suspend/resume ACPI PCI Interrupt Links
Browse files Browse the repository at this point in the history
Add reference count and disable ACPI PCI Interrupt Link
when no device still uses it.

Warn when drivers have not released Link at suspend time.

http://bugzilla.kernel.org/show_bug.cgi?id=3469

Signed-off-by: David Shaohua Li <shaohua.li@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
  • Loading branch information
David Shaohua Li authored and Len Brown committed Jul 30, 2005
1 parent 68ac767 commit 87bec66
Show file tree
Hide file tree
Showing 8 changed files with 157 additions and 47 deletions.
1 change: 1 addition & 0 deletions arch/i386/pci/acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ static int __init pci_acpi_init(void)
acpi_irq_penalty_init();
pcibios_scanned++;
pcibios_enable_irq = acpi_pci_irq_enable;
pcibios_disable_irq = acpi_pci_irq_disable;

if (pci_routeirq) {
/*
Expand Down
6 changes: 6 additions & 0 deletions arch/i386/pci/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -249,3 +249,9 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)

return pcibios_enable_irq(dev);
}

void pcibios_disable_device (struct pci_dev *dev)
{
if (pcibios_disable_irq)
pcibios_disable_irq(dev);
}
1 change: 1 addition & 0 deletions arch/i386/pci/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ struct irq_router_handler {
};

int (*pcibios_enable_irq)(struct pci_dev *dev) = NULL;
void (*pcibios_disable_irq)(struct pci_dev *dev) = NULL;

/*
* Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table.
Expand Down
1 change: 1 addition & 0 deletions arch/i386/pci/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,4 @@ extern int pcibios_scanned;
extern spinlock_t pci_config_lock;

extern int (*pcibios_enable_irq)(struct pci_dev *dev);
extern void (*pcibios_disable_irq)(struct pci_dev *dev);
85 changes: 59 additions & 26 deletions drivers/acpi/pci_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,51 @@ 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 *edge_level,
int *active_high_low,
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, 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);
}

static int
acpi_pci_free_irq(struct acpi_prt_entry *entry,
int *edge_level,
int *active_high_low,
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
* success: return IRQ >= 0
Expand All @@ -282,12 +326,13 @@ acpi_pci_irq_lookup (
int pin,
int *edge_level,
int *active_high_low,
char **link)
char **link,
irq_lookup_func func)
{
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");

Expand All @@ -301,22 +346,8 @@ acpi_pci_irq_lookup (
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, edge_level, active_high_low, link);
return_VALUE(ret);
}

/*
Expand All @@ -330,7 +361,8 @@ acpi_pci_irq_derive (
int pin,
int *edge_level,
int *active_high_low,
char **link)
char **link,
irq_lookup_func func)
{
struct pci_dev *bridge = dev;
int irq = -1;
Expand Down Expand Up @@ -363,7 +395,7 @@ acpi_pci_irq_derive (
}

irq = acpi_pci_irq_lookup(bridge->bus, PCI_SLOT(bridge->devfn),
pin, edge_level, active_high_low, link);
pin, edge_level, active_high_low, link, func);
}

if (irq < 0) {
Expand Down Expand Up @@ -415,15 +447,15 @@ acpi_pci_irq_enable (
* 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);
&edge_level, &active_high_low, &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);
&active_high_low, &link, acpi_pci_allocate_irq);

/*
* No IRQ known to the ACPI subsystem - maybe the BIOS /
Expand Down Expand Up @@ -461,7 +493,9 @@ acpi_pci_irq_enable (
EXPORT_SYMBOL(acpi_pci_irq_enable);


#ifdef CONFIG_ACPI_DEALLOCATE_IRQ
/* FIXME: implement x86/x86_64 version */
void __attribute__((weak)) acpi_unregister_gsi(u32 i) {}

void
acpi_pci_irq_disable (
struct pci_dev *dev)
Expand All @@ -488,14 +522,14 @@ acpi_pci_irq_disable (
* 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);
&edge_level, &active_high_low, 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);
&edge_level, &active_high_low, NULL, acpi_pci_free_irq);
if (gsi < 0)
return_VOID;

Expand All @@ -511,4 +545,3 @@ acpi_pci_irq_disable (

return_VOID;
}
#endif /* CONFIG_ACPI_DEALLOCATE_IRQ */
Loading

0 comments on commit 87bec66

Please sign in to comment.