Commit 0e888adc authored by Kenji Kaneshige's avatar Kenji Kaneshige Committed by Greg Kroah-Hartman

[PATCH] ACPI based I/O APIC hot-plug: ia64 support

This is an ia64 implementation of acpi_register_ioapic() and
acpi_unregister_ioapic() interfaces.
Signed-off-by: default avatarKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent b1bb248a
...@@ -236,9 +236,7 @@ acpi_parse_iosapic (acpi_table_entry_header *header, const unsigned long end) ...@@ -236,9 +236,7 @@ acpi_parse_iosapic (acpi_table_entry_header *header, const unsigned long end)
if (BAD_MADT_ENTRY(iosapic, end)) if (BAD_MADT_ENTRY(iosapic, end))
return -EINVAL; return -EINVAL;
iosapic_init(iosapic->address, iosapic->global_irq_base); return iosapic_init(iosapic->address, iosapic->global_irq_base);
return 0;
} }
...@@ -772,7 +770,7 @@ EXPORT_SYMBOL(acpi_unmap_lsapic); ...@@ -772,7 +770,7 @@ EXPORT_SYMBOL(acpi_unmap_lsapic);
#ifdef CONFIG_ACPI_NUMA #ifdef CONFIG_ACPI_NUMA
acpi_status __init acpi_status __devinit
acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret) acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret)
{ {
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
...@@ -829,16 +827,23 @@ acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret) ...@@ -829,16 +827,23 @@ acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret)
int int
acpi_register_ioapic (acpi_handle handle, u64 phys_addr, u32 gsi_base) acpi_register_ioapic (acpi_handle handle, u64 phys_addr, u32 gsi_base)
{ {
/* TBD */ int err;
return -EINVAL;
if ((err = iosapic_init(phys_addr, gsi_base)))
return err;
#if CONFIG_ACPI_NUMA
acpi_map_iosapic(handle, 0, NULL, NULL);
#endif /* CONFIG_ACPI_NUMA */
return 0;
} }
EXPORT_SYMBOL(acpi_register_ioapic); EXPORT_SYMBOL(acpi_register_ioapic);
int int
acpi_unregister_ioapic (acpi_handle handle, u32 gsi_base) acpi_unregister_ioapic (acpi_handle handle, u32 gsi_base)
{ {
/* TBD */ return iosapic_remove(gsi_base);
return -EINVAL;
} }
EXPORT_SYMBOL(acpi_unregister_ioapic); EXPORT_SYMBOL(acpi_unregister_ioapic);
......
...@@ -129,14 +129,13 @@ static struct iosapic { ...@@ -129,14 +129,13 @@ static struct iosapic {
char __iomem *addr; /* base address of IOSAPIC */ char __iomem *addr; /* base address of IOSAPIC */
unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */
unsigned short num_rte; /* number of RTE in this IOSAPIC */ unsigned short num_rte; /* number of RTE in this IOSAPIC */
int rtes_inuse; /* # of RTEs in use on this IOSAPIC */
#ifdef CONFIG_NUMA #ifdef CONFIG_NUMA
unsigned short node; /* numa node association via pxm */ unsigned short node; /* numa node association via pxm */
#endif #endif
} iosapic_lists[NR_IOSAPICS]; } iosapic_lists[NR_IOSAPICS];
static int num_iosapic; static unsigned char pcat_compat __devinitdata; /* 8259 compatibility flag */
static unsigned char pcat_compat __initdata; /* 8259 compatibility flag */
static int iosapic_kmalloc_ok; static int iosapic_kmalloc_ok;
static LIST_HEAD(free_rte_list); static LIST_HEAD(free_rte_list);
...@@ -149,7 +148,7 @@ find_iosapic (unsigned int gsi) ...@@ -149,7 +148,7 @@ find_iosapic (unsigned int gsi)
{ {
int i; int i;
for (i = 0; i < num_iosapic; i++) { for (i = 0; i < NR_IOSAPICS; i++) {
if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte) if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte)
return i; return i;
} }
...@@ -598,6 +597,7 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery, ...@@ -598,6 +597,7 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
rte->refcnt++; rte->refcnt++;
list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes); list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes);
iosapic_intr_info[vector].count++; iosapic_intr_info[vector].count++;
iosapic_lists[index].rtes_inuse++;
} }
else if (vector_is_shared(vector)) { else if (vector_is_shared(vector)) {
struct iosapic_intr_info *info = &iosapic_intr_info[vector]; struct iosapic_intr_info *info = &iosapic_intr_info[vector];
...@@ -778,7 +778,7 @@ void ...@@ -778,7 +778,7 @@ void
iosapic_unregister_intr (unsigned int gsi) iosapic_unregister_intr (unsigned int gsi)
{ {
unsigned long flags; unsigned long flags;
int irq, vector; int irq, vector, index;
irq_desc_t *idesc; irq_desc_t *idesc;
u32 low32; u32 low32;
unsigned long trigger, polarity; unsigned long trigger, polarity;
...@@ -819,6 +819,9 @@ iosapic_unregister_intr (unsigned int gsi) ...@@ -819,6 +819,9 @@ iosapic_unregister_intr (unsigned int gsi)
list_del(&rte->rte_list); list_del(&rte->rte_list);
iosapic_intr_info[vector].count--; iosapic_intr_info[vector].count--;
iosapic_free_rte(rte); iosapic_free_rte(rte);
index = find_iosapic(gsi);
iosapic_lists[index].rtes_inuse--;
WARN_ON(iosapic_lists[index].rtes_inuse < 0);
trigger = iosapic_intr_info[vector].trigger; trigger = iosapic_intr_info[vector].trigger;
polarity = iosapic_intr_info[vector].polarity; polarity = iosapic_intr_info[vector].polarity;
...@@ -952,16 +955,70 @@ iosapic_system_init (int system_pcat_compat) ...@@ -952,16 +955,70 @@ iosapic_system_init (int system_pcat_compat)
} }
} }
void __init static inline int
iosapic_alloc (void)
{
int index;
for (index = 0; index < NR_IOSAPICS; index++)
if (!iosapic_lists[index].addr)
return index;
printk(KERN_WARNING "%s: failed to allocate iosapic\n", __FUNCTION__);
return -1;
}
static inline void
iosapic_free (int index)
{
memset(&iosapic_lists[index], 0, sizeof(iosapic_lists[0]));
}
static inline int
iosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver)
{
int index;
unsigned int gsi_end, base, end;
/* check gsi range */
gsi_end = gsi_base + ((ver >> 16) & 0xff);
for (index = 0; index < NR_IOSAPICS; index++) {
if (!iosapic_lists[index].addr)
continue;
base = iosapic_lists[index].gsi_base;
end = base + iosapic_lists[index].num_rte - 1;
if (gsi_base < base && gsi_end < base)
continue;/* OK */
if (gsi_base > end && gsi_end > end)
continue; /* OK */
return -EBUSY;
}
return 0;
}
int __devinit
iosapic_init (unsigned long phys_addr, unsigned int gsi_base) iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
{ {
int num_rte; int num_rte, err, index;
unsigned int isa_irq, ver; unsigned int isa_irq, ver;
char __iomem *addr; char __iomem *addr;
unsigned long flags;
spin_lock_irqsave(&iosapic_lock, flags);
{
addr = ioremap(phys_addr, 0); addr = ioremap(phys_addr, 0);
ver = iosapic_version(addr); ver = iosapic_version(addr);
if ((err = iosapic_check_gsi_range(gsi_base, ver))) {
iounmap(addr);
spin_unlock_irqrestore(&iosapic_lock, flags);
return err;
}
/* /*
* The MAX_REDIR register holds the highest input pin * The MAX_REDIR register holds the highest input pin
* number (starting from 0). * number (starting from 0).
...@@ -969,13 +1026,15 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base) ...@@ -969,13 +1026,15 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
*/ */
num_rte = ((ver >> 16) & 0xff) + 1; num_rte = ((ver >> 16) & 0xff) + 1;
iosapic_lists[num_iosapic].addr = addr; index = iosapic_alloc();
iosapic_lists[num_iosapic].gsi_base = gsi_base; iosapic_lists[index].addr = addr;
iosapic_lists[num_iosapic].num_rte = num_rte; iosapic_lists[index].gsi_base = gsi_base;
iosapic_lists[index].num_rte = num_rte;
#ifdef CONFIG_NUMA #ifdef CONFIG_NUMA
iosapic_lists[num_iosapic].node = MAX_NUMNODES; iosapic_lists[index].node = MAX_NUMNODES;
#endif #endif
num_iosapic++; }
spin_unlock_irqrestore(&iosapic_lock, flags);
if ((gsi_base == 0) && pcat_compat) { if ((gsi_base == 0) && pcat_compat) {
/* /*
...@@ -986,10 +1045,43 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base) ...@@ -986,10 +1045,43 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
for (isa_irq = 0; isa_irq < 16; ++isa_irq) for (isa_irq = 0; isa_irq < 16; ++isa_irq)
iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE); iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE);
} }
return 0;
}
#ifdef CONFIG_HOTPLUG
int
iosapic_remove (unsigned int gsi_base)
{
int index, err = 0;
unsigned long flags;
spin_lock_irqsave(&iosapic_lock, flags);
{
index = find_iosapic(gsi_base);
if (index < 0) {
printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n",
__FUNCTION__, gsi_base);
goto out;
}
if (iosapic_lists[index].rtes_inuse) {
err = -EBUSY;
printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n",
__FUNCTION__, gsi_base);
goto out;
}
iounmap(iosapic_lists[index].addr);
iosapic_free(index);
}
out:
spin_unlock_irqrestore(&iosapic_lock, flags);
return err;
} }
#endif /* CONFIG_HOTPLUG */
#ifdef CONFIG_NUMA #ifdef CONFIG_NUMA
void __init void __devinit
map_iosapic_to_node(unsigned int gsi_base, int node) map_iosapic_to_node(unsigned int gsi_base, int node)
{ {
int index; int index;
......
...@@ -71,8 +71,11 @@ static inline void iosapic_eoi(char __iomem *iosapic, u32 vector) ...@@ -71,8 +71,11 @@ static inline void iosapic_eoi(char __iomem *iosapic, u32 vector)
} }
extern void __init iosapic_system_init (int pcat_compat); extern void __init iosapic_system_init (int pcat_compat);
extern void __init iosapic_init (unsigned long address, extern int __devinit iosapic_init (unsigned long address,
unsigned int gsi_base); unsigned int gsi_base);
#ifdef CONFIG_HOTPLUG
extern int iosapic_remove (unsigned int gsi_base);
#endif /* CONFIG_HOTPLUG */
extern int gsi_to_vector (unsigned int gsi); extern int gsi_to_vector (unsigned int gsi);
extern int gsi_to_irq (unsigned int gsi); extern int gsi_to_irq (unsigned int gsi);
extern void iosapic_enable_intr (unsigned int vector); extern void iosapic_enable_intr (unsigned int vector);
...@@ -94,11 +97,14 @@ extern unsigned int iosapic_version (char __iomem *addr); ...@@ -94,11 +97,14 @@ extern unsigned int iosapic_version (char __iomem *addr);
extern void iosapic_pci_fixup (int); extern void iosapic_pci_fixup (int);
#ifdef CONFIG_NUMA #ifdef CONFIG_NUMA
extern void __init map_iosapic_to_node (unsigned int, int); extern void __devinit map_iosapic_to_node (unsigned int, int);
#endif #endif
#else #else
#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) (-EINVAL)
#ifdef CONFIG_HOTPLUG
#define iosapic_remove(gsi_base) (-ENODEV)
#endif /* CONFIG_HOTPLUG */
#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_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)
......
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