[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>

authored by Kenji Kaneshige and committed by Greg Kroah-Hartman 0e888adc b1bb248a

+135 -32
+13 -8
arch/ia64/kernel/acpi.c
··· 236 236 if (BAD_MADT_ENTRY(iosapic, end)) 237 237 return -EINVAL; 238 238 239 - iosapic_init(iosapic->address, iosapic->global_irq_base); 240 - 241 - return 0; 239 + return iosapic_init(iosapic->address, iosapic->global_irq_base); 242 240 } 243 241 244 242 ··· 770 772 771 773 772 774 #ifdef CONFIG_ACPI_NUMA 773 - acpi_status __init 775 + acpi_status __devinit 774 776 acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret) 775 777 { 776 778 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; ··· 827 829 int 828 830 acpi_register_ioapic (acpi_handle handle, u64 phys_addr, u32 gsi_base) 829 831 { 830 - /* TBD */ 831 - return -EINVAL; 832 + int err; 833 + 834 + if ((err = iosapic_init(phys_addr, gsi_base))) 835 + return err; 836 + 837 + #if CONFIG_ACPI_NUMA 838 + acpi_map_iosapic(handle, 0, NULL, NULL); 839 + #endif /* CONFIG_ACPI_NUMA */ 840 + 841 + return 0; 832 842 } 833 843 EXPORT_SYMBOL(acpi_register_ioapic); 834 844 835 845 int 836 846 acpi_unregister_ioapic (acpi_handle handle, u32 gsi_base) 837 847 { 838 - /* TBD */ 839 - return -EINVAL; 848 + return iosapic_remove(gsi_base); 840 849 } 841 850 EXPORT_SYMBOL(acpi_unregister_ioapic); 842 851
+113 -21
arch/ia64/kernel/iosapic.c
··· 129 129 char __iomem *addr; /* base address of IOSAPIC */ 130 130 unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ 131 131 unsigned short num_rte; /* number of RTE in this IOSAPIC */ 132 + int rtes_inuse; /* # of RTEs in use on this IOSAPIC */ 132 133 #ifdef CONFIG_NUMA 133 134 unsigned short node; /* numa node association via pxm */ 134 135 #endif 135 136 } iosapic_lists[NR_IOSAPICS]; 136 137 137 - static int num_iosapic; 138 - 139 - static unsigned char pcat_compat __initdata; /* 8259 compatibility flag */ 138 + static unsigned char pcat_compat __devinitdata; /* 8259 compatibility flag */ 140 139 141 140 static int iosapic_kmalloc_ok; 142 141 static LIST_HEAD(free_rte_list); ··· 148 149 { 149 150 int i; 150 151 151 - for (i = 0; i < num_iosapic; i++) { 152 + for (i = 0; i < NR_IOSAPICS; i++) { 152 153 if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte) 153 154 return i; 154 155 } ··· 597 598 rte->refcnt++; 598 599 list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes); 599 600 iosapic_intr_info[vector].count++; 601 + iosapic_lists[index].rtes_inuse++; 600 602 } 601 603 else if (vector_is_shared(vector)) { 602 604 struct iosapic_intr_info *info = &iosapic_intr_info[vector]; ··· 778 778 iosapic_unregister_intr (unsigned int gsi) 779 779 { 780 780 unsigned long flags; 781 - int irq, vector; 781 + int irq, vector, index; 782 782 irq_desc_t *idesc; 783 783 u32 low32; 784 784 unsigned long trigger, polarity; ··· 819 819 list_del(&rte->rte_list); 820 820 iosapic_intr_info[vector].count--; 821 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 826 trigger = iosapic_intr_info[vector].trigger; 824 827 polarity = iosapic_intr_info[vector].polarity; ··· 955 952 } 956 953 } 957 954 958 - void __init 955 + static inline int 956 + iosapic_alloc (void) 957 + { 958 + int index; 959 + 960 + for (index = 0; index < NR_IOSAPICS; index++) 961 + if (!iosapic_lists[index].addr) 962 + return index; 963 + 964 + printk(KERN_WARNING "%s: failed to allocate iosapic\n", __FUNCTION__); 965 + return -1; 966 + } 967 + 968 + static inline void 969 + iosapic_free (int index) 970 + { 971 + memset(&iosapic_lists[index], 0, sizeof(iosapic_lists[0])); 972 + } 973 + 974 + static inline int 975 + iosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver) 976 + { 977 + int index; 978 + unsigned int gsi_end, base, end; 979 + 980 + /* check gsi range */ 981 + gsi_end = gsi_base + ((ver >> 16) & 0xff); 982 + for (index = 0; index < NR_IOSAPICS; index++) { 983 + if (!iosapic_lists[index].addr) 984 + continue; 985 + 986 + base = iosapic_lists[index].gsi_base; 987 + end = base + iosapic_lists[index].num_rte - 1; 988 + 989 + if (gsi_base < base && gsi_end < base) 990 + continue;/* OK */ 991 + 992 + if (gsi_base > end && gsi_end > end) 993 + continue; /* OK */ 994 + 995 + return -EBUSY; 996 + } 997 + return 0; 998 + } 999 + 1000 + int __devinit 959 1001 iosapic_init (unsigned long phys_addr, unsigned int gsi_base) 960 1002 { 961 - int num_rte; 1003 + int num_rte, err, index; 962 1004 unsigned int isa_irq, ver; 963 1005 char __iomem *addr; 1006 + unsigned long flags; 964 1007 965 - addr = ioremap(phys_addr, 0); 966 - ver = iosapic_version(addr); 1008 + spin_lock_irqsave(&iosapic_lock, flags); 1009 + { 1010 + addr = ioremap(phys_addr, 0); 1011 + ver = iosapic_version(addr); 967 1012 968 - /* 969 - * The MAX_REDIR register holds the highest input pin 970 - * number (starting from 0). 971 - * We add 1 so that we can use it for number of pins (= RTEs) 972 - */ 973 - num_rte = ((ver >> 16) & 0xff) + 1; 1013 + if ((err = iosapic_check_gsi_range(gsi_base, ver))) { 1014 + iounmap(addr); 1015 + spin_unlock_irqrestore(&iosapic_lock, flags); 1016 + return err; 1017 + } 974 1018 975 - iosapic_lists[num_iosapic].addr = addr; 976 - iosapic_lists[num_iosapic].gsi_base = gsi_base; 977 - iosapic_lists[num_iosapic].num_rte = num_rte; 1019 + /* 1020 + * The MAX_REDIR register holds the highest input pin 1021 + * number (starting from 0). 1022 + * We add 1 so that we can use it for number of pins (= RTEs) 1023 + */ 1024 + num_rte = ((ver >> 16) & 0xff) + 1; 1025 + 1026 + index = iosapic_alloc(); 1027 + iosapic_lists[index].addr = addr; 1028 + iosapic_lists[index].gsi_base = gsi_base; 1029 + iosapic_lists[index].num_rte = num_rte; 978 1030 #ifdef CONFIG_NUMA 979 - iosapic_lists[num_iosapic].node = MAX_NUMNODES; 1031 + iosapic_lists[index].node = MAX_NUMNODES; 980 1032 #endif 981 - num_iosapic++; 1033 + } 1034 + spin_unlock_irqrestore(&iosapic_lock, flags); 982 1035 983 1036 if ((gsi_base == 0) && pcat_compat) { 984 1037 /* ··· 1045 986 for (isa_irq = 0; isa_irq < 16; ++isa_irq) 1046 987 iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE); 1047 988 } 989 + return 0; 1048 990 } 1049 991 992 + #ifdef CONFIG_HOTPLUG 993 + int 994 + iosapic_remove (unsigned int gsi_base) 995 + { 996 + int index, err = 0; 997 + unsigned long flags; 998 + 999 + spin_lock_irqsave(&iosapic_lock, flags); 1000 + { 1001 + index = find_iosapic(gsi_base); 1002 + if (index < 0) { 1003 + printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n", 1004 + __FUNCTION__, gsi_base); 1005 + goto out; 1006 + } 1007 + 1008 + if (iosapic_lists[index].rtes_inuse) { 1009 + err = -EBUSY; 1010 + printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n", 1011 + __FUNCTION__, gsi_base); 1012 + goto out; 1013 + } 1014 + 1015 + iounmap(iosapic_lists[index].addr); 1016 + iosapic_free(index); 1017 + } 1018 + out: 1019 + spin_unlock_irqrestore(&iosapic_lock, flags); 1020 + return err; 1021 + } 1022 + #endif /* CONFIG_HOTPLUG */ 1023 + 1050 1024 #ifdef CONFIG_NUMA 1051 - void __init 1025 + void __devinit 1052 1026 map_iosapic_to_node(unsigned int gsi_base, int node) 1053 1027 { 1054 1028 int index;
+9 -3
include/asm-ia64/iosapic.h
··· 71 71 } 72 72 73 73 extern void __init iosapic_system_init (int pcat_compat); 74 - extern void __init iosapic_init (unsigned long address, 74 + extern int __devinit iosapic_init (unsigned long address, 75 75 unsigned int gsi_base); 76 + #ifdef CONFIG_HOTPLUG 77 + extern int iosapic_remove (unsigned int gsi_base); 78 + #endif /* CONFIG_HOTPLUG */ 76 79 extern int gsi_to_vector (unsigned int gsi); 77 80 extern int gsi_to_irq (unsigned int gsi); 78 81 extern void iosapic_enable_intr (unsigned int vector); ··· 97 94 98 95 extern void iosapic_pci_fixup (int); 99 96 #ifdef CONFIG_NUMA 100 - extern void __init map_iosapic_to_node (unsigned int, int); 97 + extern void __devinit map_iosapic_to_node (unsigned int, int); 101 98 #endif 102 99 #else 103 100 #define iosapic_system_init(pcat_compat) do { } while (0) 104 - #define iosapic_init(address,gsi_base) do { } while (0) 101 + #define iosapic_init(address,gsi_base) (-EINVAL) 102 + #ifdef CONFIG_HOTPLUG 103 + #define iosapic_remove(gsi_base) (-ENODEV) 104 + #endif /* CONFIG_HOTPLUG */ 105 105 #define iosapic_register_intr(gsi,polarity,trigger) (gsi) 106 106 #define iosapic_unregister_intr(irq) do { } while (0) 107 107 #define iosapic_override_isa_irq(isa_irq,gsi,polarity,trigger) do { } while (0)