aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>2005-04-28 03:25:58 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2005-06-28 00:52:44 -0400
commit0e888adc41ffc02b700ade715c182a17e766af84 (patch)
treeb3d745d7a292213daf107c690ea43e5589397867
parentb1bb248a5d2230a3d8ef42199c742194a8580b15 (diff)
[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: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--arch/ia64/kernel/acpi.c21
-rw-r--r--arch/ia64/kernel/iosapic.c134
-rw-r--r--include/asm-ia64/iosapic.h12
3 files changed, 135 insertions, 32 deletions
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
index ab798867acdf..cda06f88c66e 100644
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -236,9 +236,7 @@ acpi_parse_iosapic (acpi_table_entry_header *header, const unsigned long end)
236 if (BAD_MADT_ENTRY(iosapic, end)) 236 if (BAD_MADT_ENTRY(iosapic, end))
237 return -EINVAL; 237 return -EINVAL;
238 238
239 iosapic_init(iosapic->address, iosapic->global_irq_base); 239 return iosapic_init(iosapic->address, iosapic->global_irq_base);
240
241 return 0;
242} 240}
243 241
244 242
@@ -772,7 +770,7 @@ EXPORT_SYMBOL(acpi_unmap_lsapic);
772 770
773 771
774#ifdef CONFIG_ACPI_NUMA 772#ifdef CONFIG_ACPI_NUMA
775acpi_status __init 773acpi_status __devinit
776acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret) 774acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret)
777{ 775{
778 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; 776 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
@@ -829,16 +827,23 @@ acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret)
829int 827int
830acpi_register_ioapic (acpi_handle handle, u64 phys_addr, u32 gsi_base) 828acpi_register_ioapic (acpi_handle handle, u64 phys_addr, u32 gsi_base)
831{ 829{
832 /* TBD */ 830 int err;
833 return -EINVAL; 831
832 if ((err = iosapic_init(phys_addr, gsi_base)))
833 return err;
834
835#if CONFIG_ACPI_NUMA
836 acpi_map_iosapic(handle, 0, NULL, NULL);
837#endif /* CONFIG_ACPI_NUMA */
838
839 return 0;
834} 840}
835EXPORT_SYMBOL(acpi_register_ioapic); 841EXPORT_SYMBOL(acpi_register_ioapic);
836 842
837int 843int
838acpi_unregister_ioapic (acpi_handle handle, u32 gsi_base) 844acpi_unregister_ioapic (acpi_handle handle, u32 gsi_base)
839{ 845{
840 /* TBD */ 846 return iosapic_remove(gsi_base);
841 return -EINVAL;
842} 847}
843EXPORT_SYMBOL(acpi_unregister_ioapic); 848EXPORT_SYMBOL(acpi_unregister_ioapic);
844 849
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
index 88b014381df5..c170be095ccd 100644
--- a/arch/ia64/kernel/iosapic.c
+++ b/arch/ia64/kernel/iosapic.c
@@ -129,14 +129,13 @@ static struct iosapic {
129 char __iomem *addr; /* base address of IOSAPIC */ 129 char __iomem *addr; /* base address of IOSAPIC */
130 unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ 130 unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */
131 unsigned short num_rte; /* number of RTE in this IOSAPIC */ 131 unsigned short num_rte; /* number of RTE in this IOSAPIC */
132 int rtes_inuse; /* # of RTEs in use on this IOSAPIC */
132#ifdef CONFIG_NUMA 133#ifdef CONFIG_NUMA
133 unsigned short node; /* numa node association via pxm */ 134 unsigned short node; /* numa node association via pxm */
134#endif 135#endif
135} iosapic_lists[NR_IOSAPICS]; 136} iosapic_lists[NR_IOSAPICS];
136 137
137static int num_iosapic; 138static unsigned char pcat_compat __devinitdata; /* 8259 compatibility flag */
138
139static unsigned char pcat_compat __initdata; /* 8259 compatibility flag */
140 139
141static int iosapic_kmalloc_ok; 140static int iosapic_kmalloc_ok;
142static LIST_HEAD(free_rte_list); 141static LIST_HEAD(free_rte_list);
@@ -149,7 +148,7 @@ find_iosapic (unsigned int gsi)
149{ 148{
150 int i; 149 int i;
151 150
152 for (i = 0; i < num_iosapic; i++) { 151 for (i = 0; i < NR_IOSAPICS; i++) {
153 if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte) 152 if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte)
154 return i; 153 return i;
155 } 154 }
@@ -598,6 +597,7 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
598 rte->refcnt++; 597 rte->refcnt++;
599 list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes); 598 list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes);
600 iosapic_intr_info[vector].count++; 599 iosapic_intr_info[vector].count++;
600 iosapic_lists[index].rtes_inuse++;
601 } 601 }
602 else if (vector_is_shared(vector)) { 602 else if (vector_is_shared(vector)) {
603 struct iosapic_intr_info *info = &iosapic_intr_info[vector]; 603 struct iosapic_intr_info *info = &iosapic_intr_info[vector];
@@ -778,7 +778,7 @@ void
778iosapic_unregister_intr (unsigned int gsi) 778iosapic_unregister_intr (unsigned int gsi)
779{ 779{
780 unsigned long flags; 780 unsigned long flags;
781 int irq, vector; 781 int irq, vector, index;
782 irq_desc_t *idesc; 782 irq_desc_t *idesc;
783 u32 low32; 783 u32 low32;
784 unsigned long trigger, polarity; 784 unsigned long trigger, polarity;
@@ -819,6 +819,9 @@ iosapic_unregister_intr (unsigned int gsi)
819 list_del(&rte->rte_list); 819 list_del(&rte->rte_list);
820 iosapic_intr_info[vector].count--; 820 iosapic_intr_info[vector].count--;
821 iosapic_free_rte(rte); 821 iosapic_free_rte(rte);
822 index = find_iosapic(gsi);
823 iosapic_lists[index].rtes_inuse--;
824 WARN_ON(iosapic_lists[index].rtes_inuse < 0);
822 825
823 trigger = iosapic_intr_info[vector].trigger; 826 trigger = iosapic_intr_info[vector].trigger;
824 polarity = iosapic_intr_info[vector].polarity; 827 polarity = iosapic_intr_info[vector].polarity;
@@ -952,30 +955,86 @@ iosapic_system_init (int system_pcat_compat)
952 } 955 }
953} 956}
954 957
955void __init 958static inline int
959iosapic_alloc (void)
960{
961 int index;
962
963 for (index = 0; index < NR_IOSAPICS; index++)
964 if (!iosapic_lists[index].addr)
965 return index;
966
967 printk(KERN_WARNING "%s: failed to allocate iosapic\n", __FUNCTION__);
968 return -1;
969}
970
971static inline void
972iosapic_free (int index)
973{
974 memset(&iosapic_lists[index], 0, sizeof(iosapic_lists[0]));
975}
976
977static inline int
978iosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver)
979{
980 int index;
981 unsigned int gsi_end, base, end;
982
983 /* check gsi range */
984 gsi_end = gsi_base + ((ver >> 16) & 0xff);
985 for (index = 0; index < NR_IOSAPICS; index++) {
986 if (!iosapic_lists[index].addr)
987 continue;
988
989 base = iosapic_lists[index].gsi_base;
990 end = base + iosapic_lists[index].num_rte - 1;
991
992 if (gsi_base < base && gsi_end < base)
993 continue;/* OK */
994
995 if (gsi_base > end && gsi_end > end)
996 continue; /* OK */
997
998 return -EBUSY;
999 }
1000 return 0;
1001}
1002
1003int __devinit
956iosapic_init (unsigned long phys_addr, unsigned int gsi_base) 1004iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
957{ 1005{
958 int num_rte; 1006 int num_rte, err, index;
959 unsigned int isa_irq, ver; 1007 unsigned int isa_irq, ver;
960 char __iomem *addr; 1008 char __iomem *addr;
1009 unsigned long flags;
1010
1011 spin_lock_irqsave(&iosapic_lock, flags);
1012 {
1013 addr = ioremap(phys_addr, 0);
1014 ver = iosapic_version(addr);
961 1015
962 addr = ioremap(phys_addr, 0); 1016 if ((err = iosapic_check_gsi_range(gsi_base, ver))) {
963 ver = iosapic_version(addr); 1017 iounmap(addr);
1018 spin_unlock_irqrestore(&iosapic_lock, flags);
1019 return err;
1020 }
964 1021
965 /* 1022 /*
966 * The MAX_REDIR register holds the highest input pin 1023 * The MAX_REDIR register holds the highest input pin
967 * number (starting from 0). 1024 * number (starting from 0).
968 * We add 1 so that we can use it for number of pins (= RTEs) 1025 * We add 1 so that we can use it for number of pins (= RTEs)
969 */ 1026 */
970 num_rte = ((ver >> 16) & 0xff) + 1; 1027 num_rte = ((ver >> 16) & 0xff) + 1;
971 1028
972 iosapic_lists[num_iosapic].addr = addr; 1029 index = iosapic_alloc();
973 iosapic_lists[num_iosapic].gsi_base = gsi_base; 1030 iosapic_lists[index].addr = addr;
974 iosapic_lists[num_iosapic].num_rte = num_rte; 1031 iosapic_lists[index].gsi_base = gsi_base;
1032 iosapic_lists[index].num_rte = num_rte;
975#ifdef CONFIG_NUMA 1033#ifdef CONFIG_NUMA
976 iosapic_lists[num_iosapic].node = MAX_NUMNODES; 1034 iosapic_lists[index].node = MAX_NUMNODES;
977#endif 1035#endif
978 num_iosapic++; 1036 }
1037 spin_unlock_irqrestore(&iosapic_lock, flags);
979 1038
980 if ((gsi_base == 0) && pcat_compat) { 1039 if ((gsi_base == 0) && pcat_compat) {
981 /* 1040 /*
@@ -986,10 +1045,43 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
986 for (isa_irq = 0; isa_irq < 16; ++isa_irq) 1045 for (isa_irq = 0; isa_irq < 16; ++isa_irq)
987 iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE); 1046 iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE);
988 } 1047 }
1048 return 0;
1049}
1050
1051#ifdef CONFIG_HOTPLUG
1052int
1053iosapic_remove (unsigned int gsi_base)
1054{
1055 int index, err = 0;
1056 unsigned long flags;
1057
1058 spin_lock_irqsave(&iosapic_lock, flags);
1059 {
1060 index = find_iosapic(gsi_base);
1061 if (index < 0) {
1062 printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n",
1063 __FUNCTION__, gsi_base);
1064 goto out;
1065 }
1066
1067 if (iosapic_lists[index].rtes_inuse) {
1068 err = -EBUSY;
1069 printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n",
1070 __FUNCTION__, gsi_base);
1071 goto out;
1072 }
1073
1074 iounmap(iosapic_lists[index].addr);
1075 iosapic_free(index);
1076 }
1077 out:
1078 spin_unlock_irqrestore(&iosapic_lock, flags);
1079 return err;
989} 1080}
1081#endif /* CONFIG_HOTPLUG */
990 1082
991#ifdef CONFIG_NUMA 1083#ifdef CONFIG_NUMA
992void __init 1084void __devinit
993map_iosapic_to_node(unsigned int gsi_base, int node) 1085map_iosapic_to_node(unsigned int gsi_base, int node)
994{ 1086{
995 int index; 1087 int index;
diff --git a/include/asm-ia64/iosapic.h b/include/asm-ia64/iosapic.h
index 38a7a72791cc..1093f35b3b90 100644
--- a/include/asm-ia64/iosapic.h
+++ b/include/asm-ia64/iosapic.h
@@ -71,8 +71,11 @@ static inline void iosapic_eoi(char __iomem *iosapic, u32 vector)
71} 71}
72 72
73extern void __init iosapic_system_init (int pcat_compat); 73extern void __init iosapic_system_init (int pcat_compat);
74extern void __init iosapic_init (unsigned long address, 74extern int __devinit iosapic_init (unsigned long address,
75 unsigned int gsi_base); 75 unsigned int gsi_base);
76#ifdef CONFIG_HOTPLUG
77extern int iosapic_remove (unsigned int gsi_base);
78#endif /* CONFIG_HOTPLUG */
76extern int gsi_to_vector (unsigned int gsi); 79extern int gsi_to_vector (unsigned int gsi);
77extern int gsi_to_irq (unsigned int gsi); 80extern int gsi_to_irq (unsigned int gsi);
78extern void iosapic_enable_intr (unsigned int vector); 81extern void iosapic_enable_intr (unsigned int vector);
@@ -94,11 +97,14 @@ extern unsigned int iosapic_version (char __iomem *addr);
94 97
95extern void iosapic_pci_fixup (int); 98extern void iosapic_pci_fixup (int);
96#ifdef CONFIG_NUMA 99#ifdef CONFIG_NUMA
97extern void __init map_iosapic_to_node (unsigned int, int); 100extern void __devinit map_iosapic_to_node (unsigned int, int);
98#endif 101#endif
99#else 102#else
100#define iosapic_system_init(pcat_compat) do { } while (0) 103#define iosapic_system_init(pcat_compat) do { } while (0)
101#define iosapic_init(address,gsi_base) do { } while (0) 104#define iosapic_init(address,gsi_base) (-EINVAL)
105#ifdef CONFIG_HOTPLUG
106#define iosapic_remove(gsi_base) (-ENODEV)
107#endif /* CONFIG_HOTPLUG */
102#define iosapic_register_intr(gsi,polarity,trigger) (gsi) 108#define iosapic_register_intr(gsi,polarity,trigger) (gsi)
103#define iosapic_unregister_intr(irq) do { } while (0) 109#define iosapic_unregister_intr(irq) do { } while (0)
104#define iosapic_override_isa_irq(isa_irq,gsi,polarity,trigger) do { } while (0) 110#define iosapic_override_isa_irq(isa_irq,gsi,polarity,trigger) do { } while (0)