Commit 5d25c798 authored by Kenji Kaneshige's avatar Kenji Kaneshige Committed by Linus Torvalds

[PATCH] IRQ resource deallocation: ia64

This is an ia64 portion of IRQ resource deallocation. It implements
pcibios_disable_device() and acpi_unregister_gsi() for ia64.

    o acpi_unregister_gsi()

        Summary of changes for implementing this interface:

        - Add new function iosapic_unregister_intr() into
          arch/ia64/kernel/iosapic.c. This function frees an interrupt
          vector and related data structures.

        - Add new function free_irq_vector() into
          arch/ia64/kernel/irq_ia64.c. This frees an unused vector.

        - Change assign_irq_vector() to be able to support
          free_irq_vector().

    o pcibios_disable_device()

        This calls acpi_pci_irq_disable() to deallocate IRQ resources.
Signed-off-by: default avatarKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 0090012b
...@@ -306,6 +306,11 @@ config IA64_PALINFO ...@@ -306,6 +306,11 @@ config IA64_PALINFO
To use this option, you have to ensure that the "/proc file system To use this option, you have to ensure that the "/proc file system
support" (CONFIG_PROC_FS) is enabled, too. support" (CONFIG_PROC_FS) is enabled, too.
config ACPI_DEALLOCATE_IRQ
bool
depends on IOSAPIC && EXPERIMENTAL
default y
source "drivers/firmware/Kconfig" source "drivers/firmware/Kconfig"
source "fs/Kconfig.binfmt" source "fs/Kconfig.binfmt"
......
...@@ -517,6 +517,15 @@ acpi_register_gsi (u32 gsi, int edge_level, int active_high_low) ...@@ -517,6 +517,15 @@ acpi_register_gsi (u32 gsi, int edge_level, int active_high_low)
} }
EXPORT_SYMBOL(acpi_register_gsi); EXPORT_SYMBOL(acpi_register_gsi);
#ifdef CONFIG_ACPI_DEALLOCATE_IRQ
void
acpi_unregister_gsi (u32 gsi)
{
iosapic_unregister_intr(gsi);
}
EXPORT_SYMBOL(acpi_unregister_gsi);
#endif /* CONFIG_ACPI_DEALLOCATE_IRQ */
static int __init static int __init
acpi_parse_fadt (unsigned long phys_addr, unsigned long size) acpi_parse_fadt (unsigned long phys_addr, unsigned long size)
{ {
......
...@@ -111,6 +111,7 @@ static struct iosapic_intr_info { ...@@ -111,6 +111,7 @@ static struct iosapic_intr_info {
unsigned char dmode : 3; /* delivery mode (see iosapic.h) */ unsigned char dmode : 3; /* delivery mode (see iosapic.h) */
unsigned char polarity: 1; /* interrupt polarity (see iosapic.h) */ unsigned char polarity: 1; /* interrupt polarity (see iosapic.h) */
unsigned char trigger : 1; /* trigger mode (see iosapic.h) */ unsigned char trigger : 1; /* trigger mode (see iosapic.h) */
int refcnt; /* reference counter */
} iosapic_intr_info[IA64_NUM_VECTORS]; } iosapic_intr_info[IA64_NUM_VECTORS];
static struct iosapic { static struct iosapic {
...@@ -177,7 +178,7 @@ gsi_to_irq (unsigned int gsi) ...@@ -177,7 +178,7 @@ gsi_to_irq (unsigned int gsi)
static void static void
set_rte (unsigned int vector, unsigned int dest, int mask) set_rte (unsigned int vector, unsigned int dest, int mask)
{ {
unsigned long pol, trigger, dmode, flags; unsigned long pol, trigger, dmode;
u32 low32, high32; u32 low32, high32;
char __iomem *addr; char __iomem *addr;
int rte_index; int rte_index;
...@@ -218,13 +219,9 @@ set_rte (unsigned int vector, unsigned int dest, int mask) ...@@ -218,13 +219,9 @@ set_rte (unsigned int vector, unsigned int dest, int mask)
/* dest contains both id and eid */ /* dest contains both id and eid */
high32 = (dest << IOSAPIC_DEST_SHIFT); high32 = (dest << IOSAPIC_DEST_SHIFT);
spin_lock_irqsave(&iosapic_lock, flags);
{
iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32); iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32);
iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32); iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
iosapic_intr_info[vector].low32 = low32; iosapic_intr_info[vector].low32 = low32;
}
spin_unlock_irqrestore(&iosapic_lock, flags);
} }
static void static void
...@@ -475,6 +472,7 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery, ...@@ -475,6 +472,7 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
iosapic_intr_info[vector].addr = iosapic_address; iosapic_intr_info[vector].addr = iosapic_address;
iosapic_intr_info[vector].gsi_base = gsi_base; iosapic_intr_info[vector].gsi_base = gsi_base;
iosapic_intr_info[vector].trigger = trigger; iosapic_intr_info[vector].trigger = trigger;
iosapic_intr_info[vector].refcnt++;
if (trigger == IOSAPIC_EDGE) if (trigger == IOSAPIC_EDGE)
irq_type = &irq_type_iosapic_edge; irq_type = &irq_type_iosapic_edge;
...@@ -581,6 +579,7 @@ iosapic_register_intr (unsigned int gsi, ...@@ -581,6 +579,7 @@ iosapic_register_intr (unsigned int gsi,
{ {
vector = gsi_to_vector(gsi); vector = gsi_to_vector(gsi);
if (vector > 0) { if (vector > 0) {
iosapic_intr_info[vector].refcnt++;
spin_unlock_irqrestore(&iosapic_lock, flags); spin_unlock_irqrestore(&iosapic_lock, flags);
return vector; return vector;
} }
...@@ -589,6 +588,8 @@ iosapic_register_intr (unsigned int gsi, ...@@ -589,6 +588,8 @@ iosapic_register_intr (unsigned int gsi,
dest = get_target_cpu(gsi, vector); dest = get_target_cpu(gsi, vector);
register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
polarity, trigger); polarity, trigger);
set_rte(vector, dest, 1);
} }
spin_unlock_irqrestore(&iosapic_lock, flags); spin_unlock_irqrestore(&iosapic_lock, flags);
...@@ -597,10 +598,87 @@ iosapic_register_intr (unsigned int gsi, ...@@ -597,10 +598,87 @@ iosapic_register_intr (unsigned int gsi,
(polarity == IOSAPIC_POL_HIGH ? "high" : "low"), (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
cpu_logical_id(dest), dest, vector); cpu_logical_id(dest), dest, vector);
set_rte(vector, dest, 1);
return vector; return vector;
} }
#ifdef CONFIG_ACPI_DEALLOCATE_IRQ
void
iosapic_unregister_intr (unsigned int gsi)
{
unsigned long flags;
int irq, vector;
irq_desc_t *idesc;
int rte_index;
unsigned long trigger, polarity;
/*
* If the irq associated with the gsi is not found,
* iosapic_unregister_intr() is unbalanced. We need to check
* this again after getting locks.
*/
irq = gsi_to_irq(gsi);
if (irq < 0) {
printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi);
WARN_ON(1);
return;
}
vector = irq_to_vector(irq);
idesc = irq_descp(irq);
spin_lock_irqsave(&idesc->lock, flags);
spin_lock(&iosapic_lock);
{
rte_index = iosapic_intr_info[vector].rte_index;
if (rte_index < 0) {
spin_unlock(&iosapic_lock);
spin_unlock_irqrestore(&idesc->lock, flags);
printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n", gsi);
WARN_ON(1);
return;
}
if (--iosapic_intr_info[vector].refcnt > 0) {
spin_unlock(&iosapic_lock);
spin_unlock_irqrestore(&idesc->lock, flags);
return;
}
/*
* If interrupt handlers still exist on the irq
* associated with the gsi, don't unregister the
* interrupt.
*/
if (idesc->action) {
iosapic_intr_info[vector].refcnt++;
spin_unlock(&iosapic_lock);
spin_unlock_irqrestore(&idesc->lock, flags);
printk(KERN_WARNING "Cannot unregister GSI. IRQ %u is still in use.\n", irq);
return;
}
/* Clear the interrupt controller descriptor. */
idesc->handler = &no_irq_type;
trigger = iosapic_intr_info[vector].trigger;
polarity = iosapic_intr_info[vector].polarity;
/* Clear the interrupt information. */
memset(&iosapic_intr_info[vector], 0, sizeof(struct iosapic_intr_info));
iosapic_intr_info[vector].rte_index = -1; /* mark as unused */
}
spin_unlock(&iosapic_lock);
spin_unlock_irqrestore(&idesc->lock, flags);
/* Free the interrupt vector */
free_irq_vector(vector);
printk(KERN_INFO "GSI %u (%s, %s) -> vector %d unregisterd.\n",
gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
(polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
vector);
}
#endif /* CONFIG_ACPI_DEALLOCATE_IRQ */
/* /*
* ACPI calls this when it finds an entry for a platform interrupt. * ACPI calls this when it finds an entry for a platform interrupt.
* Note that the irq_base and IOSAPIC address must be set in iosapic_init(). * Note that the irq_base and IOSAPIC address must be set in iosapic_init().
......
...@@ -1030,6 +1030,9 @@ void move_irq(int irq) ...@@ -1030,6 +1030,9 @@ void move_irq(int irq)
irq_desc_t *desc = irq_descp(irq); irq_desc_t *desc = irq_descp(irq);
int redir = test_bit(irq, pending_irq_redir); int redir = test_bit(irq, pending_irq_redir);
if (unlikely(!desc->handler->set_affinity))
return;
if (!cpus_empty(pending_irq_cpumask[irq])) { if (!cpus_empty(pending_irq_cpumask[irq])) {
cpus_and(tmp, pending_irq_cpumask[irq], cpu_online_map); cpus_and(tmp, pending_irq_cpumask[irq], cpu_online_map);
if (unlikely(!cpus_empty(tmp))) { if (unlikely(!cpus_empty(tmp))) {
......
...@@ -60,15 +60,34 @@ __u8 isa_irq_to_vector_map[16] = { ...@@ -60,15 +60,34 @@ __u8 isa_irq_to_vector_map[16] = {
}; };
EXPORT_SYMBOL(isa_irq_to_vector_map); EXPORT_SYMBOL(isa_irq_to_vector_map);
static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_NUM_DEVICE_VECTORS)];
int int
assign_irq_vector (int irq) assign_irq_vector (int irq)
{ {
static int next_vector = IA64_FIRST_DEVICE_VECTOR; int pos, vector;
again:
if (next_vector > IA64_LAST_DEVICE_VECTOR) pos = find_first_zero_bit(ia64_vector_mask, IA64_NUM_DEVICE_VECTORS);
vector = IA64_FIRST_DEVICE_VECTOR + pos;
if (vector > IA64_LAST_DEVICE_VECTOR)
/* XXX could look for sharable vectors instead of panic'ing... */ /* XXX could look for sharable vectors instead of panic'ing... */
panic("assign_irq_vector: out of interrupt vectors!"); panic("assign_irq_vector: out of interrupt vectors!");
return next_vector++; if (test_and_set_bit(pos, ia64_vector_mask))
goto again;
return vector;
}
void
free_irq_vector (int vector)
{
int pos;
if (vector < IA64_FIRST_DEVICE_VECTOR || vector > IA64_LAST_DEVICE_VECTOR)
return;
pos = vector - IA64_FIRST_DEVICE_VECTOR;
if (!test_and_clear_bit(pos, ia64_vector_mask))
printk(KERN_WARNING "%s: double free!\n", __FUNCTION__);
} }
extern unsigned int do_IRQ(unsigned long irq, struct pt_regs *regs); extern unsigned int do_IRQ(unsigned long irq, struct pt_regs *regs);
......
...@@ -480,6 +480,14 @@ pcibios_enable_device (struct pci_dev *dev, int mask) ...@@ -480,6 +480,14 @@ pcibios_enable_device (struct pci_dev *dev, int mask)
return acpi_pci_irq_enable(dev); return acpi_pci_irq_enable(dev);
} }
#ifdef CONFIG_ACPI_DEALLOCATE_IRQ
void
pcibios_disable_device (struct pci_dev *dev)
{
acpi_pci_irq_disable(dev);
}
#endif /* CONFIG_ACPI_DEALLOCATE_IRQ */
void void
pcibios_align_resource (void *data, struct resource *res, pcibios_align_resource (void *data, struct resource *res,
unsigned long size, unsigned long align) unsigned long size, unsigned long align)
......
...@@ -50,6 +50,7 @@ typedef u8 ia64_vector; ...@@ -50,6 +50,7 @@ typedef u8 ia64_vector;
*/ */
#define IA64_FIRST_DEVICE_VECTOR 0x30 #define IA64_FIRST_DEVICE_VECTOR 0x30
#define IA64_LAST_DEVICE_VECTOR 0xe7 #define IA64_LAST_DEVICE_VECTOR 0xe7
#define IA64_NUM_DEVICE_VECTORS (IA64_LAST_DEVICE_VECTOR - IA64_FIRST_DEVICE_VECTOR + 1)
#define IA64_MCA_RENDEZ_VECTOR 0xe8 /* MCA rendez interrupt */ #define IA64_MCA_RENDEZ_VECTOR 0xe8 /* MCA rendez interrupt */
#define IA64_PERFMON_VECTOR 0xee /* performanc monitor interrupt vector */ #define IA64_PERFMON_VECTOR 0xee /* performanc monitor interrupt vector */
...@@ -81,6 +82,7 @@ extern __u8 isa_irq_to_vector_map[16]; ...@@ -81,6 +82,7 @@ extern __u8 isa_irq_to_vector_map[16];
extern struct hw_interrupt_type irq_type_ia64_lsapic; /* CPU-internal interrupt controller */ extern struct hw_interrupt_type irq_type_ia64_lsapic; /* CPU-internal interrupt controller */
extern int assign_irq_vector (int irq); /* allocate a free vector */ extern int assign_irq_vector (int irq); /* allocate a free vector */
extern void free_irq_vector (int vector);
extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect); extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect);
extern void register_percpu_irq (ia64_vector vec, struct irqaction *action); extern void register_percpu_irq (ia64_vector vec, struct irqaction *action);
......
...@@ -78,6 +78,9 @@ extern int gsi_to_irq (unsigned int gsi); ...@@ -78,6 +78,9 @@ extern int gsi_to_irq (unsigned int gsi);
extern void iosapic_enable_intr (unsigned int vector); extern void iosapic_enable_intr (unsigned int vector);
extern int iosapic_register_intr (unsigned int gsi, unsigned long polarity, extern int iosapic_register_intr (unsigned int gsi, unsigned long polarity,
unsigned long trigger); unsigned long trigger);
#ifdef CONFIG_ACPI_DEALLOCATE_IRQ
extern void iosapic_unregister_intr (unsigned int irq);
#endif
extern void __init iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi, extern void __init iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
unsigned long polarity, unsigned long polarity,
unsigned long trigger); unsigned long trigger);
...@@ -97,6 +100,7 @@ extern void __init map_iosapic_to_node (unsigned int, int); ...@@ -97,6 +100,7 @@ extern void __init map_iosapic_to_node (unsigned int, int);
#define iosapic_system_init(pcat_compat) do { } while (0) #define iosapic_system_init(pcat_compat) do { } while (0)
#define iosapic_init(address,gsi_base) do { } while (0) #define iosapic_init(address,gsi_base) do { } while (0)
#define iosapic_register_intr(gsi,polarity,trigger) (gsi) #define iosapic_register_intr(gsi,polarity,trigger) (gsi)
#define iosapic_unregister_intr(irq) do { } while (0)
#define iosapic_override_isa_irq(isa_irq,gsi,polarity,trigger) do { } while (0) #define iosapic_override_isa_irq(isa_irq,gsi,polarity,trigger) do { } while (0)
#define iosapic_register_platform_intr(type,gsi,pmi,eid,id, \ #define iosapic_register_platform_intr(type,gsi,pmi,eid,id, \
polarity,trigger) (gsi) polarity,trigger) (gsi)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment