diff options
author | Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com> | 2007-07-17 08:22:23 -0400 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2007-07-17 12:51:49 -0400 |
commit | e1b30a392835e92581db09a4e8b4b2ad53a0c370 (patch) | |
tree | 1a0dacd37e682dc4c2222f415f8035057d6bbc30 /arch/ia64/kernel/irq_ia64.c | |
parent | f8c087f31e1d3fbf1f7d0b3ea5e643f535e7de04 (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/kernel/irq_ia64.c')
-rw-r--r-- | arch/ia64/kernel/irq_ia64.c | 201 |
1 files changed, 166 insertions, 35 deletions
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 */ |
50 | int ia64_first_device_vector = IA64_DEF_FIRST_DEVICE_VECTOR; | 56 | int ia64_first_device_vector = IA64_DEF_FIRST_DEVICE_VECTOR; |
51 | int ia64_last_device_vector = IA64_DEF_LAST_DEVICE_VECTOR; | 57 | int ia64_last_device_vector = IA64_DEF_LAST_DEVICE_VECTOR; |
@@ -64,46 +70,161 @@ __u8 isa_irq_to_vector_map[16] = { | |||
64 | }; | 70 | }; |
65 | EXPORT_SYMBOL(isa_irq_to_vector_map); | 71 | EXPORT_SYMBOL(isa_irq_to_vector_map); |
66 | 72 | ||
67 | static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_MAX_DEVICE_VECTORS)]; | 73 | DEFINE_SPINLOCK(vector_lock); |
74 | |||
75 | struct irq_cfg irq_cfg[NR_IRQS] __read_mostly = { | ||
76 | [0 ... NR_IRQS - 1] = { .vector = IRQ_VECTOR_UNASSIGNED } | ||
77 | }; | ||
78 | |||
79 | DEFINE_PER_CPU(int[IA64_NUM_VECTORS], vector_irq) = { | ||
80 | [0 ... IA64_NUM_VECTORS - 1] = IA64_SPURIOUS_INT_VECTOR | ||
81 | }; | ||
82 | |||
83 | static int irq_status[NR_IRQS] = { | ||
84 | [0 ... NR_IRQS -1] = IRQ_UNUSED | ||
85 | }; | ||
86 | |||
87 | int check_irq_used(int irq) | ||
88 | { | ||
89 | if (irq_status[irq] == IRQ_USED) | ||
90 | return 1; | ||
91 | |||
92 | return -1; | ||
93 | } | ||
94 | |||
95 | static 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 | |||
104 | static 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 | |||
114 | static 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 | |||
125 | static 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 | |||
140 | int 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 | |||
151 | static 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 | ||
69 | int | 167 | int |
70 | assign_irq_vector (int irq) | 168 | assign_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 | ||
83 | void | 186 | void |
84 | free_irq_vector (int vector) | 187 | free_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 | ||
96 | int | 195 | int |
97 | reserve_irq_vector (int vector) | 196 | reserve_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 | */ | ||
208 | void __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 | |||
222 | void 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 | */ |
112 | int create_irq(void) | 233 | int 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 | ||
122 | void destroy_irq(unsigned int irq) | 254 | void 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 | ||
314 | void __init | 445 | void __init |