aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/ia64/kernel/acpi.c21
-rw-r--r--arch/ia64/kernel/iosapic.c134
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
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;