* [PATCH]ACPI pcibios_disable_device implementation for x86
@ 2005-05-17 5:57 Shaohua Li
0 siblings, 0 replies; only message in thread
From: Shaohua Li @ 2005-05-17 5:57 UTC (permalink / raw)
To: acpi-dev; +Cc: Len, Greg KH, kaneshige
Hi,
This an implementation of pcibios_disable_device for x86. It's porting
from current ia64 implementation, but more sample. The design of
pcibios_disable_device is for ioapic hotplug, but here we used it for
suspend/resume, since we must disable PIC/IOAPIC/irq router at suspend.
Most changes are in ACPI part. It's against -mm tree.
Thanks,
Shaohua
---
linux-2.6.11-root/arch/i386/kernel/acpi/boot.c | 11 +++
linux-2.6.11-root/arch/i386/kernel/mpparse.c | 45 +++++++++++--
linux-2.6.11-root/arch/i386/pci/acpi.c | 1
linux-2.6.11-root/arch/i386/pci/common.c | 6 +
linux-2.6.11-root/arch/i386/pci/irq.c | 1
linux-2.6.11-root/arch/i386/pci/pci.h | 1
linux-2.6.11-root/arch/x86_64/kernel/mpparse.c | 43 ++++++++++---
linux-2.6.11-root/drivers/acpi/pci_irq.c | 82 +++++++++++++++++--------
linux-2.6.11-root/drivers/acpi/pci_link.c | 76 +++++++++++++++++++----
linux-2.6.11-root/include/acpi/acpi_drivers.h | 3
linux-2.6.11-root/include/asm-i386/mpspec.h | 1
linux-2.6.11-root/include/asm-x86_64/mpspec.h | 1
linux-2.6.11-root/include/linux/acpi.h | 4 -
13 files changed, 216 insertions(+), 59 deletions(-)
diff -puN arch/i386/kernel/acpi/boot.c~suspend_resume_irq arch/i386/kernel/acpi/boot.c
--- linux-2.6.11/arch/i386/kernel/acpi/boot.c~suspend_resume_irq 2005-05-10 15:59:52.000000000 +0800
+++ linux-2.6.11-root/arch/i386/kernel/acpi/boot.c 2005-05-10 15:59:52.000000000 +0800
@@ -484,6 +484,17 @@ unsigned int acpi_register_gsi(u32 gsi,
}
EXPORT_SYMBOL(acpi_register_gsi);
+void acpi_unregister_gsi(u32 gsi)
+{
+ /* ELCR set to edge? seems not required */
+#ifdef CONFIG_X86_IO_APIC
+ if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC) {
+ mp_unregister_gsi(gsi);
+ }
+#endif
+}
+EXPORT_SYMBOL(acpi_unregister_gsi);
+
/*
* ACPI based hotplug support for CPU
*/
diff -puN arch/i386/kernel/mpparse.c~suspend_resume_irq arch/i386/kernel/mpparse.c
--- linux-2.6.11/arch/i386/kernel/mpparse.c~suspend_resume_irq 2005-05-10 15:59:52.000000000 +0800
+++ linux-2.6.11-root/arch/i386/kernel/mpparse.c 2005-05-10 16:22:32.000000000 +0800
@@ -865,7 +865,7 @@ static struct mp_ioapic_routing {
int apic_id;
int gsi_base;
int gsi_end;
- u32 pin_programmed[4];
+ int refcnts[MP_MAX_IOAPIC_PIN];
} mp_ioapic_routing[MAX_IO_APICS];
@@ -1057,7 +1057,6 @@ int mp_register_gsi (u32 gsi, int edge_l
{
int ioapic = -1;
int ioapic_pin = 0;
- int idx, bit = 0;
#ifdef CONFIG_ACPI_BUS
/* Don't set up the ACPI SCI because it's already set up */
@@ -1081,27 +1080,57 @@ int mp_register_gsi (u32 gsi, int edge_l
* with redundant pin->gsi mappings (but unique PCI devices);
* we only program the IOAPIC on the first.
*/
- bit = ioapic_pin % 32;
- idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32);
- if (idx > 3) {
+ if (ioapic_pin > MP_MAX_IOAPIC_PIN) {
printk(KERN_ERR "Invalid reference to IOAPIC pin "
"%d-%d\n", mp_ioapic_routing[ioapic].apic_id,
ioapic_pin);
return gsi;
}
- if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
+
+ if (mp_ioapic_routing[ioapic].refcnts[ioapic_pin] ++ ) {
Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
return gsi;
}
- mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
-
io_apic_set_pci_routing(ioapic, ioapic_pin, gsi,
edge_level == ACPI_EDGE_SENSITIVE ? 0 : 1,
active_high_low == ACPI_ACTIVE_HIGH ? 0 : 1);
return gsi;
}
+void mp_unregister_gsi(u32 gsi)
+{
+ int ioapic = -1;
+ int ioapic_pin = 0;
+
+#ifdef CONFIG_ACPI_BUS
+ /* we don't touch SCI */
+ if (acpi_fadt.sci_int == gsi)
+ return;
+#endif
+
+ ioapic = mp_find_ioapic(gsi);
+ if (ioapic < 0) {
+ printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi);
+ return;
+ }
+
+ ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_base;
+
+ mp_ioapic_routing[ioapic].refcnts[ioapic_pin] --;
+ if (mp_ioapic_routing[ioapic].refcnts[ioapic_pin])
+ return;
+
+ /*
+ * TBD: we do nothing here so the vector of a pin isn't changed. This
+ * is quite useful for suspend/resume. IOAPIC hotplug should clear the
+ * interrupt gate and free vector, since i386 doesn't support IOAPIC
+ * hotplug, we temporarily ignore it.
+ */
+ printk(KERN_INFO "Pin %d-%d is unregistered\n",
+ mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
+}
+
#endif /*CONFIG_X86_IO_APIC && (CONFIG_ACPI_INTERPRETER || CONFIG_ACPI_BOOT)*/
#endif /*CONFIG_ACPI_BOOT*/
diff -puN arch/i386/pci/acpi.c~suspend_resume_irq arch/i386/pci/acpi.c
--- linux-2.6.11/arch/i386/pci/acpi.c~suspend_resume_irq 2005-05-10 15:59:52.000000000 +0800
+++ linux-2.6.11-root/arch/i386/pci/acpi.c 2005-05-10 15:59:52.000000000 +0800
@@ -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) {
/*
diff -puN arch/i386/pci/common.c~suspend_resume_irq arch/i386/pci/common.c
--- linux-2.6.11/arch/i386/pci/common.c~suspend_resume_irq 2005-05-10 15:59:52.000000000 +0800
+++ linux-2.6.11-root/arch/i386/pci/common.c 2005-05-10 15:59:52.000000000 +0800
@@ -253,3 +253,9 @@ int pcibios_enable_device(struct pci_dev
return pcibios_enable_irq(dev);
}
+
+void pcibios_disable_device (struct pci_dev *dev)
+{
+ if (pcibios_disable_irq)
+ pcibios_disable_irq(dev);
+}
diff -puN arch/i386/pci/irq.c~suspend_resume_irq arch/i386/pci/irq.c
--- linux-2.6.11/arch/i386/pci/irq.c~suspend_resume_irq 2005-05-10 15:59:52.000000000 +0800
+++ linux-2.6.11-root/arch/i386/pci/irq.c 2005-05-10 15:59:52.000000000 +0800
@@ -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;
/*
* Check passed address for the PCI IRQ Routing Table signature
diff -puN arch/i386/pci/pci.h~suspend_resume_irq arch/i386/pci/pci.h
--- linux-2.6.11/arch/i386/pci/pci.h~suspend_resume_irq 2005-05-10 15:59:52.000000000 +0800
+++ linux-2.6.11-root/arch/i386/pci/pci.h 2005-05-10 15:59:52.000000000 +0800
@@ -73,3 +73,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);
diff -puN drivers/acpi/pci_irq.c~suspend_resume_irq drivers/acpi/pci_irq.c
--- linux-2.6.11/drivers/acpi/pci_irq.c~suspend_resume_irq 2005-05-10 15:59:52.000000000 +0800
+++ linux-2.6.11-root/drivers/acpi/pci_irq.c 2005-05-12 16:59:51.000000000 +0800
@@ -269,7 +269,51 @@ acpi_pci_irq_del_prt (int segment, int b
/* --------------------------------------------------------------------------
PCI Interrupt Routing Support
-------------------------------------------------------------------------- */
+typedef int (*acpi_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
@@ -282,12 +326,13 @@ acpi_pci_irq_lookup (
int pin,
int *edge_level,
int *active_high_low,
- char **link)
+ char **link,
+ acpi_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");
@@ -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);
}
/*
@@ -330,7 +361,8 @@ acpi_pci_irq_derive (
int pin,
int *edge_level,
int *active_high_low,
- char **link)
+ char **link,
+ acpi_irq_lookup_func func)
{
struct pci_dev *bridge = dev;
int irq = -1;
@@ -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) {
@@ -415,7 +447,7 @@ 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
@@ -423,7 +455,7 @@ acpi_pci_irq_enable (
*/
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 /
@@ -461,7 +493,6 @@ acpi_pci_irq_enable (
EXPORT_SYMBOL(acpi_pci_irq_enable);
-#ifdef CONFIG_ACPI_DEALLOCATE_IRQ
void
acpi_pci_irq_disable (
struct pci_dev *dev)
@@ -488,14 +519,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;
@@ -511,4 +542,3 @@ acpi_pci_irq_disable (
return_VOID;
}
-#endif /* CONFIG_ACPI_DEALLOCATE_IRQ */
diff -puN drivers/acpi/pci_link.c~suspend_resume_irq drivers/acpi/pci_link.c
--- linux-2.6.11/drivers/acpi/pci_link.c~suspend_resume_irq 2005-05-10 15:59:52.000000000 +0800
+++ linux-2.6.11-root/drivers/acpi/pci_link.c 2005-05-10 17:05:28.000000000 +0800
@@ -68,6 +68,12 @@ static struct acpi_driver acpi_pci_link_
},
};
+/*
+ * If a link is initialized but disabled since no device uses it any more
+ * (because of hotplug or suspend/resume), we keep its active irq number and
+ * reuse it when other device uses it again. This way, link's active irq
+ * always isn't changed after it's initialized once.
+ */
struct acpi_pci_link_irq {
u8 active; /* Current IRQ */
u8 edge_level; /* All IRQs */
@@ -76,8 +82,7 @@ struct acpi_pci_link_irq {
u8 possible_count;
u8 possible[ACPI_PCI_LINK_MAX_POSSIBLE];
u8 initialized:1;
- u8 suspend_resume:1;
- u8 reserved:6;
+ u8 reserved:7;
};
struct acpi_pci_link {
@@ -85,6 +90,7 @@ struct acpi_pci_link {
struct acpi_device *device;
acpi_handle handle;
struct acpi_pci_link_irq irq;
+ int refcnt;
};
static struct {
@@ -532,12 +538,16 @@ static int acpi_pci_link_allocate(
ACPI_FUNCTION_TRACE("acpi_pci_link_allocate");
- if (link->irq.suspend_resume) {
- acpi_pci_link_set(link, link->irq.active);
- link->irq.suspend_resume = 0;
- }
- if (link->irq.initialized)
+ if (link->irq.initialized) {
+ if (link->refcnt == 0)
+ /*
+ * This means the link is initialized but disabled.
+ * Just reuse the active irq number.
+ * TBD: should we reevaluate _PRS after resume?
+ */
+ acpi_pci_link_set(link, link->irq.active);
return_VALUE(0);
+ }
/*
* search for active IRQ in list of possible IRQs.
@@ -596,13 +606,13 @@ static int acpi_pci_link_allocate(
}
/*
- * acpi_pci_link_get_irq
+ * acpi_pci_link_allocate_irq
* success: return IRQ >= 0
* failure: return -1
*/
int
-acpi_pci_link_get_irq (
+acpi_pci_link_allocate_irq (
acpi_handle handle,
int index,
int *edge_level,
@@ -613,7 +623,7 @@ acpi_pci_link_get_irq (
struct acpi_device *device = NULL;
struct acpi_pci_link *link = NULL;
- ACPI_FUNCTION_TRACE("acpi_pci_link_get_irq");
+ ACPI_FUNCTION_TRACE("acpi_pci_link_allocate_irq");
result = acpi_bus_get_device(handle, &device);
if (result) {
@@ -644,10 +654,47 @@ acpi_pci_link_get_irq (
if (edge_level) *edge_level = link->irq.edge_level;
if (active_high_low) *active_high_low = link->irq.active_high_low;
if (name) *name = acpi_device_bid(link->device);
+
+ link->refcnt ++;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Link %s is referenced\n", acpi_device_bid(link->device)));
return_VALUE(link->irq.active);
}
+/* Disable link device if no reference on it. */
+int
+acpi_pci_link_free_irq(acpi_handle handle)
+{
+ struct acpi_device *device = NULL;
+ struct acpi_pci_link *link = NULL;
+ acpi_status result;
+
+ ACPI_FUNCTION_TRACE("acpi_pci_link_free_irq");
+
+ result = acpi_bus_get_device(handle, &device);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link device\n"));
+ return_VALUE(-1);
+ }
+
+ link = (struct acpi_pci_link *) acpi_driver_data(device);
+ if (!link) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n"));
+ return_VALUE(-1);
+ }
+ if (!link->irq.initialized) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link isn't initialized\n"));
+ return_VALUE(-1);
+ }
+
+ link->refcnt --;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Link %s is dereferenced\n", acpi_device_bid(link->device)));
+ if (link->refcnt == 0)
+ acpi_ut_evaluate_object(link->handle, "_DIS", 0, NULL);
+ return_VALUE(link->irq.active);
+}
/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
@@ -735,8 +782,13 @@ irqrouter_suspend(
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n"));
continue;
}
- if (link->irq.active && link->irq.initialized)
- link->irq.suspend_resume = 1;
+ if (link->irq.initialized && link->refcnt != 0) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Link device [%s] refrerence isn't 0\n",
+ acpi_device_bid(link->device)));
+ link->refcnt = 0;
+ /* We can't call _DIS method here */
+ }
}
return_VALUE(0);
}
diff -puN include/acpi/acpi_drivers.h~suspend_resume_irq include/acpi/acpi_drivers.h
--- linux-2.6.11/include/acpi/acpi_drivers.h~suspend_resume_irq 2005-05-10 15:59:52.000000000 +0800
+++ linux-2.6.11-root/include/acpi/acpi_drivers.h 2005-05-10 15:59:52.000000000 +0800
@@ -56,8 +56,9 @@
/* ACPI PCI Interrupt Link (pci_link.c) */
int acpi_irq_penalty_init (void);
-int acpi_pci_link_get_irq (acpi_handle handle, int index, int *edge_level,
+int acpi_pci_link_allocate_irq (acpi_handle handle, int index, int *edge_level,
int *active_high_low, char **name);
+int acpi_pci_link_free_irq(acpi_handle handle);
/* ACPI PCI Interrupt Routing (pci_irq.c) */
diff -puN include/asm-i386/mpspec.h~suspend_resume_irq include/asm-i386/mpspec.h
--- linux-2.6.11/include/asm-i386/mpspec.h~suspend_resume_irq 2005-05-10 15:59:52.000000000 +0800
+++ linux-2.6.11-root/include/asm-i386/mpspec.h 2005-05-10 15:59:52.000000000 +0800
@@ -33,6 +33,7 @@ extern void mp_register_ioapic (u8 id, u
extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity, u8 trigger, u32 gsi);
extern void mp_config_acpi_legacy_irqs (void);
extern int mp_register_gsi (u32 gsi, int edge_level, int active_high_low);
+extern void mp_unregister_gsi (u32 gsi);
#endif /*CONFIG_ACPI_BOOT*/
#define PHYSID_ARRAY_SIZE BITS_TO_LONGS(MAX_APICS)
diff -puN include/linux/acpi.h~suspend_resume_irq include/linux/acpi.h
--- linux-2.6.11/include/linux/acpi.h~suspend_resume_irq 2005-05-10 15:59:52.000000000 +0800
+++ linux-2.6.11-root/include/linux/acpi.h 2005-05-10 15:59:52.000000000 +0800
@@ -431,9 +431,7 @@ int acpi_gsi_to_irq (u32 gsi, unsigned i
* If this matches the last registration, any IRQ resources for gsi
* are freed.
*/
-#ifdef CONFIG_ACPI_DEALLOCATE_IRQ
void acpi_unregister_gsi (u32 gsi);
-#endif
#ifdef CONFIG_ACPI_PCI
@@ -458,9 +456,7 @@ struct pci_dev;
int acpi_pci_irq_enable (struct pci_dev *dev);
void acpi_penalize_isa_irq(int irq, int active);
-#ifdef CONFIG_ACPI_DEALLOCATE_IRQ
void acpi_pci_irq_disable (struct pci_dev *dev);
-#endif
struct acpi_pci_driver {
struct acpi_pci_driver *next;
diff -puN arch/x86_64/kernel/mpparse.c~suspend_resume_irq arch/x86_64/kernel/mpparse.c
--- linux-2.6.11/arch/x86_64/kernel/mpparse.c~suspend_resume_irq 2005-05-12 16:37:51.000000000 +0800
+++ linux-2.6.11-root/arch/x86_64/kernel/mpparse.c 2005-05-13 11:06:23.486693288 +0800
@@ -724,7 +724,7 @@ static struct mp_ioapic_routing {
int apic_id;
int gsi_start;
int gsi_end;
- u32 pin_programmed[4];
+ int refcnts[MP_MAX_IOAPIC_PIN];
} mp_ioapic_routing[MAX_IO_APICS];
@@ -911,7 +911,6 @@ int mp_register_gsi(u32 gsi, int edge_le
{
int ioapic = -1;
int ioapic_pin = 0;
- int idx, bit = 0;
if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
return gsi;
@@ -935,27 +934,55 @@ int mp_register_gsi(u32 gsi, int edge_le
* with redundant pin->gsi mappings (but unique PCI devices);
* we only program the IOAPIC on the first.
*/
- bit = ioapic_pin % 32;
- idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32);
- if (idx > 3) {
+ if (ioapic_pin > MP_MAX_IOAPIC_PIN) {
printk(KERN_ERR "Invalid reference to IOAPIC pin "
"%d-%d\n", mp_ioapic_routing[ioapic].apic_id,
ioapic_pin);
return gsi;
}
- if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
+ if (mp_ioapic_routing[ioapic].refcnts[ioapic_pin] ++ ) {
Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
return gsi;
}
- mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
-
io_apic_set_pci_routing(ioapic, ioapic_pin, gsi,
edge_level == ACPI_EDGE_SENSITIVE ? 0 : 1,
active_high_low == ACPI_ACTIVE_HIGH ? 0 : 1);
return gsi;
}
+void mp_unregister_gsi(u32 gsi)
+{
+ int ioapic = -1;
+ int ioapic_pin = 0;
+
+#ifdef CONFIG_ACPI_BUS
+ /* we don't touch SCI */
+ if (acpi_fadt.sci_int == gsi)
+ return;
+#endif
+
+ ioapic = mp_find_ioapic(gsi);
+ if (ioapic < 0) {
+ printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi);
+ return;
+ }
+
+ ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_start;
+
+ mp_ioapic_routing[ioapic].refcnts[ioapic_pin] --;
+ if (mp_ioapic_routing[ioapic].refcnts[ioapic_pin])
+ return;
+ /*
+ * TBD: we do nothing here so the vector of a pin isn't changed. This
+ * is quite useful for suspend/resume. IOAPIC hotplug should clear the
+ * interrupt gate and free vector, since x64 doesn't support IOAPIC
+ * hotplug, we temporarily ignore it.
+ */
+ printk(KERN_INFO "Pin %d-%d is unregistered\n",
+ mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
+}
+
#endif /*CONFIG_X86_IO_APIC*/
#endif /*CONFIG_ACPI_BOOT*/
diff -puN include/asm-x86_64/mpspec.h~suspend_resume_irq include/asm-x86_64/mpspec.h
--- linux-2.6.11/include/asm-x86_64/mpspec.h~suspend_resume_irq 2005-05-12 16:38:55.000000000 +0800
+++ linux-2.6.11-root/include/asm-x86_64/mpspec.h 2005-05-12 16:39:53.000000000 +0800
@@ -188,6 +188,7 @@ extern void mp_register_ioapic (u8 id, u
extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity, u8 trigger, u32 gsi);
extern void mp_config_acpi_legacy_irqs (void);
extern int mp_register_gsi (u32 gsi, int edge_level, int active_high_low);
+extern void mp_unregister_gsi (u32 gsi);
#endif /*CONFIG_X86_IO_APIC*/
#endif
_
-------------------------------------------------------
This SF.Net email is sponsored by Oracle Space Sweepstakes
Want to be the first software developer in space?
Enter now for the Oracle Space Sweepstakes!
http://ads.osdn.com/?ad_id=7412&alloc_id=16344&op=click
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2005-05-17 5:57 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-05-17 5:57 [PATCH]ACPI pcibios_disable_device implementation for x86 Shaohua Li
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox