aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ia64
diff options
context:
space:
mode:
authorYasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>2007-07-17 08:22:23 -0400
committerTony Luck <tony.luck@intel.com>2007-07-17 12:51:49 -0400
commite1b30a392835e92581db09a4e8b4b2ad53a0c370 (patch)
tree1a0dacd37e682dc4c2222f415f8035057d6bbc30 /arch/ia64
parentf8c087f31e1d3fbf1f7d0b3ea5e643f535e7de04 (diff)
[IA64] Add mapping table between irq and vector
Add mapping tables between irqs and vectors, and its management code. This is necessary for supporting multiple vector domain because 1:1 mapping between irq and vector will be changed to n:1. The irq == vector relationship between irqs and vectors is explicitly remained for percpu interrupts, platform interrupts, isa IRQs and vectors assigned using assign_irq_vector() because some programs might depend on it. And I should consider the following problem. When pci drivers enabled/disabled devices dynamically, its irq number is changed to the different one. Therefore, suspend/resume code may happen problem. To fix this problem, I bound gsi to irq. Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Signed-off-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com> Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'arch/ia64')
-rw-r--r--arch/ia64/kernel/iosapic.c61
-rw-r--r--arch/ia64/kernel/irq.c2
-rw-r--r--arch/ia64/kernel/irq_ia64.c201
-rw-r--r--arch/ia64/kernel/smpboot.c4
4 files changed, 206 insertions, 62 deletions
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
index cffb443a557c..cf27cfb4d165 100644
--- a/arch/ia64/kernel/iosapic.c
+++ b/arch/ia64/kernel/iosapic.c
@@ -117,6 +117,9 @@ static DEFINE_SPINLOCK(iosapic_lock);
117 * These tables map IA-64 vectors to the IOSAPIC pin that generates this 117 * These tables map IA-64 vectors to the IOSAPIC pin that generates this
118 * vector. 118 * vector.
119 */ 119 */
120
121#define NO_REF_RTE 0
122
120static struct iosapic { 123static struct iosapic {
121 char __iomem *addr; /* base address of IOSAPIC */ 124 char __iomem *addr; /* base address of IOSAPIC */
122 unsigned int gsi_base; /* GSI base */ 125 unsigned int gsi_base; /* GSI base */
@@ -204,7 +207,7 @@ inline int
204gsi_to_vector (unsigned int gsi) 207gsi_to_vector (unsigned int gsi)
205{ 208{
206 int irq = __gsi_to_irq(gsi); 209 int irq = __gsi_to_irq(gsi);
207 if (irq < 0) 210 if (check_irq_used(irq) < 0)
208 return -1; 211 return -1;
209 return irq_to_vector(irq); 212 return irq_to_vector(irq);
210} 213}
@@ -619,14 +622,18 @@ register_intr (unsigned int gsi, int irq, unsigned char delivery,
619 iosapic_intr_info[irq].count++; 622 iosapic_intr_info[irq].count++;
620 iosapic_lists[index].rtes_inuse++; 623 iosapic_lists[index].rtes_inuse++;
621 } 624 }
622 else if (irq_is_shared(irq)) { 625 else if (rte->refcnt == NO_REF_RTE) {
623 struct iosapic_intr_info *info = &iosapic_intr_info[irq]; 626 struct iosapic_intr_info *info = &iosapic_intr_info[irq];
624 if (info->trigger != trigger || info->polarity != polarity) { 627 if (info->count > 0 &&
628 (info->trigger != trigger || info->polarity != polarity)){
625 printk (KERN_WARNING 629 printk (KERN_WARNING
626 "%s: cannot override the interrupt\n", 630 "%s: cannot override the interrupt\n",
627 __FUNCTION__); 631 __FUNCTION__);
628 return -EINVAL; 632 return -EINVAL;
629 } 633 }
634 rte->refcnt++;
635 iosapic_intr_info[irq].count++;
636 iosapic_lists[index].rtes_inuse++;
630 } 637 }
631 638
632 iosapic_intr_info[irq].polarity = polarity; 639 iosapic_intr_info[irq].polarity = polarity;
@@ -756,12 +763,17 @@ iosapic_register_intr (unsigned int gsi,
756 irq = __gsi_to_irq(gsi); 763 irq = __gsi_to_irq(gsi);
757 if (irq > 0) { 764 if (irq > 0) {
758 rte = find_rte(irq, gsi); 765 rte = find_rte(irq, gsi);
759 rte->refcnt++; 766 if(iosapic_intr_info[irq].count == 0) {
760 goto unlock_iosapic_lock; 767 assign_irq_vector(irq);
761 } 768 dynamic_irq_init(irq);
769 } else if (rte->refcnt != NO_REF_RTE) {
770 rte->refcnt++;
771 goto unlock_iosapic_lock;
772 }
773 } else
774 irq = create_irq();
762 775
763 /* If vector is running out, we try to find a sharable vector */ 776 /* If vector is running out, we try to find a sharable vector */
764 irq = create_irq();
765 if (irq < 0) { 777 if (irq < 0) {
766 irq = iosapic_find_sharable_irq(trigger, polarity); 778 irq = iosapic_find_sharable_irq(trigger, polarity);
767 if (irq < 0) 779 if (irq < 0)
@@ -832,18 +844,14 @@ iosapic_unregister_intr (unsigned int gsi)
832 if (--rte->refcnt > 0) 844 if (--rte->refcnt > 0)
833 goto out; 845 goto out;
834 846
835 /* Remove the rte entry from the list */
836 idesc = irq_desc + irq; 847 idesc = irq_desc + irq;
837 spin_lock(&idesc->lock); 848 rte->refcnt = NO_REF_RTE;
838 list_del(&rte->rte_list);
839 spin_unlock(&idesc->lock);
840 849
841 /* Mask the interrupt */ 850 /* Mask the interrupt */
842 low32 = iosapic_intr_info[irq].low32 | IOSAPIC_MASK; 851 low32 = iosapic_intr_info[irq].low32 | IOSAPIC_MASK;
843 iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte->rte_index), low32); 852 iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte->rte_index), low32);
844 853
845 iosapic_intr_info[irq].count--; 854 iosapic_intr_info[irq].count--;
846 iosapic_free_rte(rte);
847 index = find_iosapic(gsi); 855 index = find_iosapic(gsi);
848 iosapic_lists[index].rtes_inuse--; 856 iosapic_lists[index].rtes_inuse--;
849 WARN_ON(iosapic_lists[index].rtes_inuse < 0); 857 WARN_ON(iosapic_lists[index].rtes_inuse < 0);
@@ -857,21 +865,20 @@ iosapic_unregister_intr (unsigned int gsi)
857 (polarity == IOSAPIC_POL_HIGH ? "high" : "low"), 865 (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
858 cpu_logical_id(dest), dest, irq_to_vector(irq)); 866 cpu_logical_id(dest), dest, irq_to_vector(irq));
859 867
860 if (list_empty(&iosapic_intr_info[irq].rtes)) { 868 if (iosapic_intr_info[irq].count == 0) {
861 /* Sanity check */
862 BUG_ON(iosapic_intr_info[irq].count);
863#ifdef CONFIG_SMP 869#ifdef CONFIG_SMP
864 /* Clear affinity */ 870 /* Clear affinity */
865 cpus_setall(idesc->affinity); 871 cpus_setall(idesc->affinity);
866#endif 872#endif
867 /* Clear the interrupt information */ 873 /* Clear the interrupt information */
868 memset(&iosapic_intr_info[irq], 0, 874 iosapic_intr_info[irq].dest = 0;
869 sizeof(struct iosapic_intr_info)); 875 iosapic_intr_info[irq].dmode = 0;
876 iosapic_intr_info[irq].polarity = 0;
877 iosapic_intr_info[irq].trigger = 0;
870 iosapic_intr_info[irq].low32 |= IOSAPIC_MASK; 878 iosapic_intr_info[irq].low32 |= IOSAPIC_MASK;
871 INIT_LIST_HEAD(&iosapic_intr_info[irq].rtes);
872 879
873 /* Destroy IRQ */ 880 /* Destroy and reserve IRQ */
874 destroy_irq(irq); 881 destroy_and_reserve_irq(irq);
875 } 882 }
876 out: 883 out:
877 spin_unlock_irqrestore(&iosapic_lock, flags); 884 spin_unlock_irqrestore(&iosapic_lock, flags);
@@ -892,8 +899,8 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
892 899
893 switch (int_type) { 900 switch (int_type) {
894 case ACPI_INTERRUPT_PMI: 901 case ACPI_INTERRUPT_PMI:
895 vector = iosapic_vector; 902 irq = vector = iosapic_vector;
896 irq = vector; /* FIXME */ 903 bind_irq_vector(irq, vector);
897 /* 904 /*
898 * since PMI vector is alloc'd by FW(ACPI) not by kernel, 905 * since PMI vector is alloc'd by FW(ACPI) not by kernel,
899 * we need to make sure the vector is available 906 * we need to make sure the vector is available
@@ -909,8 +916,8 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
909 delivery = IOSAPIC_INIT; 916 delivery = IOSAPIC_INIT;
910 break; 917 break;
911 case ACPI_INTERRUPT_CPEI: 918 case ACPI_INTERRUPT_CPEI:
912 vector = IA64_CPE_VECTOR; 919 irq = vector = IA64_CPE_VECTOR;
913 irq = vector; /* FIXME */ 920 BUG_ON(bind_irq_vector(irq, vector));
914 delivery = IOSAPIC_LOWEST_PRIORITY; 921 delivery = IOSAPIC_LOWEST_PRIORITY;
915 mask = 1; 922 mask = 1;
916 break; 923 break;
@@ -945,8 +952,8 @@ iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
945 int vector, irq; 952 int vector, irq;
946 unsigned int dest = cpu_physical_id(smp_processor_id()); 953 unsigned int dest = cpu_physical_id(smp_processor_id());
947 954
948 vector = isa_irq_to_vector(isa_irq); 955 irq = vector = isa_irq_to_vector(isa_irq);
949 irq = vector; /* FIXME */ 956 BUG_ON(bind_irq_vector(irq, vector));
950 register_intr(gsi, irq, IOSAPIC_LOWEST_PRIORITY, polarity, trigger); 957 register_intr(gsi, irq, IOSAPIC_LOWEST_PRIORITY, polarity, trigger);
951 958
952 DBG("ISA: IRQ %u -> GSI %u (%s,%s) -> CPU %d (0x%04x) vector %d\n", 959 DBG("ISA: IRQ %u -> GSI %u (%s,%s) -> CPU %d (0x%04x) vector %d\n",
@@ -966,6 +973,8 @@ iosapic_system_init (int system_pcat_compat)
966 iosapic_intr_info[irq].low32 = IOSAPIC_MASK; 973 iosapic_intr_info[irq].low32 = IOSAPIC_MASK;
967 /* mark as unused */ 974 /* mark as unused */
968 INIT_LIST_HEAD(&iosapic_intr_info[irq].rtes); 975 INIT_LIST_HEAD(&iosapic_intr_info[irq].rtes);
976
977 iosapic_intr_info[irq].count = 0;
969 } 978 }
970 979
971 pcat_compat = system_pcat_compat; 980 pcat_compat = system_pcat_compat;
diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c
index 407b45870489..cc3ee4ef37af 100644
--- a/arch/ia64/kernel/irq.c
+++ b/arch/ia64/kernel/irq.c
@@ -35,7 +35,7 @@ void ack_bad_irq(unsigned int irq)
35#ifdef CONFIG_IA64_GENERIC 35#ifdef CONFIG_IA64_GENERIC
36unsigned int __ia64_local_vector_to_irq (ia64_vector vec) 36unsigned int __ia64_local_vector_to_irq (ia64_vector vec)
37{ 37{
38 return (unsigned int) vec; 38 return __get_cpu_var(vector_irq)[vec];
39} 39}
40#endif 40#endif
41 41
diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
index bc47049f060f..072427c2c3f6 100644
--- a/arch/ia64/kernel/irq_ia64.c
+++ b/arch/ia64/kernel/irq_ia64.c
@@ -46,6 +46,12 @@
46 46
47#define IRQ_DEBUG 0 47#define IRQ_DEBUG 0
48 48
49#define IRQ_VECTOR_UNASSIGNED (0)
50
51#define IRQ_UNUSED (0)
52#define IRQ_USED (1)
53#define IRQ_RSVD (2)
54
49/* These can be overridden in platform_irq_init */ 55/* These can be overridden in platform_irq_init */
50int ia64_first_device_vector = IA64_DEF_FIRST_DEVICE_VECTOR; 56int ia64_first_device_vector = IA64_DEF_FIRST_DEVICE_VECTOR;
51int ia64_last_device_vector = IA64_DEF_LAST_DEVICE_VECTOR; 57int ia64_last_device_vector = IA64_DEF_LAST_DEVICE_VECTOR;
@@ -64,46 +70,161 @@ __u8 isa_irq_to_vector_map[16] = {
64}; 70};
65EXPORT_SYMBOL(isa_irq_to_vector_map); 71EXPORT_SYMBOL(isa_irq_to_vector_map);
66 72
67static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_MAX_DEVICE_VECTORS)]; 73DEFINE_SPINLOCK(vector_lock);
74
75struct irq_cfg irq_cfg[NR_IRQS] __read_mostly = {
76 [0 ... NR_IRQS - 1] = { .vector = IRQ_VECTOR_UNASSIGNED }
77};
78
79DEFINE_PER_CPU(int[IA64_NUM_VECTORS], vector_irq) = {
80 [0 ... IA64_NUM_VECTORS - 1] = IA64_SPURIOUS_INT_VECTOR
81};
82
83static int irq_status[NR_IRQS] = {
84 [0 ... NR_IRQS -1] = IRQ_UNUSED
85};
86
87int check_irq_used(int irq)
88{
89 if (irq_status[irq] == IRQ_USED)
90 return 1;
91
92 return -1;
93}
94
95static void reserve_irq(unsigned int irq)
96{
97 unsigned long flags;
98
99 spin_lock_irqsave(&vector_lock, flags);
100 irq_status[irq] = IRQ_RSVD;
101 spin_unlock_irqrestore(&vector_lock, flags);
102}
103
104static inline int find_unassigned_irq(void)
105{
106 int irq;
107
108 for (irq = IA64_FIRST_DEVICE_VECTOR; irq < NR_IRQS; irq++)
109 if (irq_status[irq] == IRQ_UNUSED)
110 return irq;
111 return -ENOSPC;
112}
113
114static inline int find_unassigned_vector(void)
115{
116 int vector;
117
118 for (vector = IA64_FIRST_DEVICE_VECTOR;
119 vector <= IA64_LAST_DEVICE_VECTOR; vector++)
120 if (__get_cpu_var(vector_irq[vector]) == IA64_SPURIOUS_INT_VECTOR)
121 return vector;
122 return -ENOSPC;
123}
124
125static int __bind_irq_vector(int irq, int vector)
126{
127 int cpu;
128
129 if (irq_to_vector(irq) == vector)
130 return 0;
131 if (irq_to_vector(irq) != IRQ_VECTOR_UNASSIGNED)
132 return -EBUSY;
133 for_each_online_cpu(cpu)
134 per_cpu(vector_irq, cpu)[vector] = irq;
135 irq_cfg[irq].vector = vector;
136 irq_status[irq] = IRQ_USED;
137 return 0;
138}
139
140int bind_irq_vector(int irq, int vector)
141{
142 unsigned long flags;
143 int ret;
144
145 spin_lock_irqsave(&vector_lock, flags);
146 ret = __bind_irq_vector(irq, vector);
147 spin_unlock_irqrestore(&vector_lock, flags);
148 return ret;
149}
150
151static void clear_irq_vector(int irq)
152{
153 unsigned long flags;
154 int vector, cpu;
155
156 spin_lock_irqsave(&vector_lock, flags);
157 BUG_ON((unsigned)irq >= NR_IRQS);
158 BUG_ON(irq_cfg[irq].vector == IRQ_VECTOR_UNASSIGNED);
159 vector = irq_cfg[irq].vector;
160 for_each_online_cpu(cpu)
161 per_cpu(vector_irq, cpu)[vector] = IA64_SPURIOUS_INT_VECTOR;
162 irq_cfg[irq].vector = IRQ_VECTOR_UNASSIGNED;
163 irq_status[irq] = IRQ_UNUSED;
164 spin_unlock_irqrestore(&vector_lock, flags);
165}
68 166
69int 167int
70assign_irq_vector (int irq) 168assign_irq_vector (int irq)
71{ 169{
72 int pos, vector; 170 unsigned long flags;
73 again: 171 int vector = -ENOSPC;
74 pos = find_first_zero_bit(ia64_vector_mask, IA64_NUM_DEVICE_VECTORS); 172
75 vector = IA64_FIRST_DEVICE_VECTOR + pos; 173 if (irq < 0) {
76 if (vector > IA64_LAST_DEVICE_VECTOR) 174 goto out;
77 return -ENOSPC; 175 }
78 if (test_and_set_bit(pos, ia64_vector_mask)) 176 spin_lock_irqsave(&vector_lock, flags);
79 goto again; 177 vector = find_unassigned_vector();
178 if (vector < 0)
179 goto out;
180 BUG_ON(__bind_irq_vector(irq, vector));
181 spin_unlock_irqrestore(&vector_lock, flags);
182 out:
80 return vector; 183 return vector;
81} 184}
82 185
83void 186void
84free_irq_vector (int vector) 187free_irq_vector (int vector)
85{ 188{
86 int pos; 189 if (vector < IA64_FIRST_DEVICE_VECTOR ||
87 190 vector > IA64_LAST_DEVICE_VECTOR)
88 if (vector < IA64_FIRST_DEVICE_VECTOR || vector > IA64_LAST_DEVICE_VECTOR)
89 return; 191 return;
90 192 clear_irq_vector(vector);
91 pos = vector - IA64_FIRST_DEVICE_VECTOR;
92 if (!test_and_clear_bit(pos, ia64_vector_mask))
93 printk(KERN_WARNING "%s: double free!\n", __FUNCTION__);
94} 193}
95 194
96int 195int
97reserve_irq_vector (int vector) 196reserve_irq_vector (int vector)
98{ 197{
99 int pos;
100
101 if (vector < IA64_FIRST_DEVICE_VECTOR || 198 if (vector < IA64_FIRST_DEVICE_VECTOR ||
102 vector > IA64_LAST_DEVICE_VECTOR) 199 vector > IA64_LAST_DEVICE_VECTOR)
103 return -EINVAL; 200 return -EINVAL;
201 return !!bind_irq_vector(vector, vector);
202}
104 203
105 pos = vector - IA64_FIRST_DEVICE_VECTOR; 204/*
106 return test_and_set_bit(pos, ia64_vector_mask); 205 * Initialize vector_irq on a new cpu. This function must be called
206 * with vector_lock held.
207 */
208void __setup_vector_irq(int cpu)
209{
210 int irq, vector;
211
212 /* Clear vector_irq */
213 for (vector = 0; vector < IA64_NUM_VECTORS; ++vector)
214 per_cpu(vector_irq, cpu)[vector] = IA64_SPURIOUS_INT_VECTOR;
215 /* Mark the inuse vectors */
216 for (irq = 0; irq < NR_IRQS; ++irq) {
217 if ((vector = irq_to_vector(irq)) != IRQ_VECTOR_UNASSIGNED)
218 per_cpu(vector_irq, cpu)[vector] = irq;
219 }
220}
221
222void destroy_and_reserve_irq(unsigned int irq)
223{
224 dynamic_irq_cleanup(irq);
225
226 clear_irq_vector(irq);
227 reserve_irq(irq);
107} 228}
108 229
109/* 230/*
@@ -111,18 +232,29 @@ reserve_irq_vector (int vector)
111 */ 232 */
112int create_irq(void) 233int create_irq(void)
113{ 234{
114 int vector = assign_irq_vector(AUTO_ASSIGN); 235 unsigned long flags;
115 236 int irq, vector;
116 if (vector >= 0) 237
117 dynamic_irq_init(vector); 238 irq = -ENOSPC;
118 239 spin_lock_irqsave(&vector_lock, flags);
119 return vector; 240 vector = find_unassigned_vector();
241 if (vector < 0)
242 goto out;
243 irq = find_unassigned_irq();
244 if (irq < 0)
245 goto out;
246 BUG_ON(__bind_irq_vector(irq, vector));
247 out:
248 spin_unlock_irqrestore(&vector_lock, flags);
249 if (irq >= 0)
250 dynamic_irq_init(irq);
251 return irq;
120} 252}
121 253
122void destroy_irq(unsigned int irq) 254void destroy_irq(unsigned int irq)
123{ 255{
124 dynamic_irq_cleanup(irq); 256 dynamic_irq_cleanup(irq);
125 free_irq_vector(irq); 257 clear_irq_vector(irq);
126} 258}
127 259
128#ifdef CONFIG_SMP 260#ifdef CONFIG_SMP
@@ -301,14 +433,13 @@ register_percpu_irq (ia64_vector vec, struct irqaction *action)
301 irq_desc_t *desc; 433 irq_desc_t *desc;
302 unsigned int irq; 434 unsigned int irq;
303 435
304 for (irq = 0; irq < NR_IRQS; ++irq) 436 irq = vec;
305 if (irq_to_vector(irq) == vec) { 437 BUG_ON(bind_irq_vector(irq, vec));
306 desc = irq_desc + irq; 438 desc = irq_desc + irq;
307 desc->status |= IRQ_PER_CPU; 439 desc->status |= IRQ_PER_CPU;
308 desc->chip = &irq_type_ia64_lsapic; 440 desc->chip = &irq_type_ia64_lsapic;
309 if (action) 441 if (action)
310 setup_irq(irq, action); 442 setup_irq(irq, action);
311 }
312} 443}
313 444
314void __init 445void __init
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
index 3c9d8e6089cf..9f5c90b594b9 100644
--- a/arch/ia64/kernel/smpboot.c
+++ b/arch/ia64/kernel/smpboot.c
@@ -395,9 +395,13 @@ smp_callin (void)
395 fix_b0_for_bsp(); 395 fix_b0_for_bsp();
396 396
397 lock_ipi_calllock(); 397 lock_ipi_calllock();
398 spin_lock(&vector_lock);
399 /* Setup the per cpu irq handling data structures */
400 __setup_vector_irq(cpuid);
398 cpu_set(cpuid, cpu_online_map); 401 cpu_set(cpuid, cpu_online_map);
399 unlock_ipi_calllock(); 402 unlock_ipi_calllock();
400 per_cpu(cpu_state, cpuid) = CPU_ONLINE; 403 per_cpu(cpu_state, cpuid) = CPU_ONLINE;
404 spin_unlock(&vector_lock);
401 405
402 smp_setup_percpu_timer(); 406 smp_setup_percpu_timer();
403 407