diff options
author | Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> | 2005-04-28 03:25:58 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-06-28 00:52:44 -0400 |
commit | 0e888adc41ffc02b700ade715c182a17e766af84 (patch) | |
tree | b3d745d7a292213daf107c690ea43e5589397867 /arch | |
parent | b1bb248a5d2230a3d8ef42199c742194a8580b15 (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>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/ia64/kernel/acpi.c | 21 | ||||
-rw-r--r-- | arch/ia64/kernel/iosapic.c | 134 |
2 files changed, 126 insertions, 29 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 |
775 | acpi_status __init | 773 | acpi_status __devinit |
776 | acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret) | 774 | acpi_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) | |||
829 | int | 827 | int |
830 | acpi_register_ioapic (acpi_handle handle, u64 phys_addr, u32 gsi_base) | 828 | acpi_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 | } |
835 | EXPORT_SYMBOL(acpi_register_ioapic); | 841 | EXPORT_SYMBOL(acpi_register_ioapic); |
836 | 842 | ||
837 | int | 843 | int |
838 | acpi_unregister_ioapic (acpi_handle handle, u32 gsi_base) | 844 | acpi_unregister_ioapic (acpi_handle handle, u32 gsi_base) |
839 | { | 845 | { |
840 | /* TBD */ | 846 | return iosapic_remove(gsi_base); |
841 | return -EINVAL; | ||
842 | } | 847 | } |
843 | EXPORT_SYMBOL(acpi_unregister_ioapic); | 848 | EXPORT_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 | ||
137 | static int num_iosapic; | 138 | static unsigned char pcat_compat __devinitdata; /* 8259 compatibility flag */ |
138 | |||
139 | static unsigned char pcat_compat __initdata; /* 8259 compatibility flag */ | ||
140 | 139 | ||
141 | static int iosapic_kmalloc_ok; | 140 | static int iosapic_kmalloc_ok; |
142 | static LIST_HEAD(free_rte_list); | 141 | static 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 | |||
778 | iosapic_unregister_intr (unsigned int gsi) | 778 | iosapic_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 | ||
955 | void __init | 958 | static inline int |
959 | iosapic_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 | |||
971 | static inline void | ||
972 | iosapic_free (int index) | ||
973 | { | ||
974 | memset(&iosapic_lists[index], 0, sizeof(iosapic_lists[0])); | ||
975 | } | ||
976 | |||
977 | static inline int | ||
978 | iosapic_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 | |||
1003 | int __devinit | ||
956 | iosapic_init (unsigned long phys_addr, unsigned int gsi_base) | 1004 | iosapic_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 | ||
1052 | int | ||
1053 | iosapic_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 |
992 | void __init | 1084 | void __devinit |
993 | map_iosapic_to_node(unsigned int gsi_base, int node) | 1085 | map_iosapic_to_node(unsigned int gsi_base, int node) |
994 | { | 1086 | { |
995 | int index; | 1087 | int index; |