diff options
Diffstat (limited to 'arch/sparc/kernel/irq_64.c')
-rw-r--r-- | arch/sparc/kernel/irq_64.c | 389 |
1 files changed, 165 insertions, 224 deletions
diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c index 830d70a3e20b..4e78862d12fd 100644 --- a/arch/sparc/kernel/irq_64.c +++ b/arch/sparc/kernel/irq_64.c | |||
@@ -82,7 +82,7 @@ static void bucket_clear_chain_pa(unsigned long bucket_pa) | |||
82 | "i" (ASI_PHYS_USE_EC)); | 82 | "i" (ASI_PHYS_USE_EC)); |
83 | } | 83 | } |
84 | 84 | ||
85 | static unsigned int bucket_get_virt_irq(unsigned long bucket_pa) | 85 | static unsigned int bucket_get_irq(unsigned long bucket_pa) |
86 | { | 86 | { |
87 | unsigned int ret; | 87 | unsigned int ret; |
88 | 88 | ||
@@ -90,21 +90,20 @@ static unsigned int bucket_get_virt_irq(unsigned long bucket_pa) | |||
90 | : "=&r" (ret) | 90 | : "=&r" (ret) |
91 | : "r" (bucket_pa + | 91 | : "r" (bucket_pa + |
92 | offsetof(struct ino_bucket, | 92 | offsetof(struct ino_bucket, |
93 | __virt_irq)), | 93 | __irq)), |
94 | "i" (ASI_PHYS_USE_EC)); | 94 | "i" (ASI_PHYS_USE_EC)); |
95 | 95 | ||
96 | return ret; | 96 | return ret; |
97 | } | 97 | } |
98 | 98 | ||
99 | static void bucket_set_virt_irq(unsigned long bucket_pa, | 99 | static void bucket_set_irq(unsigned long bucket_pa, unsigned int irq) |
100 | unsigned int virt_irq) | ||
101 | { | 100 | { |
102 | __asm__ __volatile__("stwa %0, [%1] %2" | 101 | __asm__ __volatile__("stwa %0, [%1] %2" |
103 | : /* no outputs */ | 102 | : /* no outputs */ |
104 | : "r" (virt_irq), | 103 | : "r" (irq), |
105 | "r" (bucket_pa + | 104 | "r" (bucket_pa + |
106 | offsetof(struct ino_bucket, | 105 | offsetof(struct ino_bucket, |
107 | __virt_irq)), | 106 | __irq)), |
108 | "i" (ASI_PHYS_USE_EC)); | 107 | "i" (ASI_PHYS_USE_EC)); |
109 | } | 108 | } |
110 | 109 | ||
@@ -114,97 +113,63 @@ static struct { | |||
114 | unsigned int dev_handle; | 113 | unsigned int dev_handle; |
115 | unsigned int dev_ino; | 114 | unsigned int dev_ino; |
116 | unsigned int in_use; | 115 | unsigned int in_use; |
117 | } virt_irq_table[NR_IRQS]; | 116 | } irq_table[NR_IRQS]; |
118 | static DEFINE_SPINLOCK(virt_irq_alloc_lock); | 117 | static DEFINE_SPINLOCK(irq_alloc_lock); |
119 | 118 | ||
120 | unsigned char virt_irq_alloc(unsigned int dev_handle, | 119 | unsigned char irq_alloc(unsigned int dev_handle, unsigned int dev_ino) |
121 | unsigned int dev_ino) | ||
122 | { | 120 | { |
123 | unsigned long flags; | 121 | unsigned long flags; |
124 | unsigned char ent; | 122 | unsigned char ent; |
125 | 123 | ||
126 | BUILD_BUG_ON(NR_IRQS >= 256); | 124 | BUILD_BUG_ON(NR_IRQS >= 256); |
127 | 125 | ||
128 | spin_lock_irqsave(&virt_irq_alloc_lock, flags); | 126 | spin_lock_irqsave(&irq_alloc_lock, flags); |
129 | 127 | ||
130 | for (ent = 1; ent < NR_IRQS; ent++) { | 128 | for (ent = 1; ent < NR_IRQS; ent++) { |
131 | if (!virt_irq_table[ent].in_use) | 129 | if (!irq_table[ent].in_use) |
132 | break; | 130 | break; |
133 | } | 131 | } |
134 | if (ent >= NR_IRQS) { | 132 | if (ent >= NR_IRQS) { |
135 | printk(KERN_ERR "IRQ: Out of virtual IRQs.\n"); | 133 | printk(KERN_ERR "IRQ: Out of virtual IRQs.\n"); |
136 | ent = 0; | 134 | ent = 0; |
137 | } else { | 135 | } else { |
138 | virt_irq_table[ent].dev_handle = dev_handle; | 136 | irq_table[ent].dev_handle = dev_handle; |
139 | virt_irq_table[ent].dev_ino = dev_ino; | 137 | irq_table[ent].dev_ino = dev_ino; |
140 | virt_irq_table[ent].in_use = 1; | 138 | irq_table[ent].in_use = 1; |
141 | } | 139 | } |
142 | 140 | ||
143 | spin_unlock_irqrestore(&virt_irq_alloc_lock, flags); | 141 | spin_unlock_irqrestore(&irq_alloc_lock, flags); |
144 | 142 | ||
145 | return ent; | 143 | return ent; |
146 | } | 144 | } |
147 | 145 | ||
148 | #ifdef CONFIG_PCI_MSI | 146 | #ifdef CONFIG_PCI_MSI |
149 | void virt_irq_free(unsigned int virt_irq) | 147 | void irq_free(unsigned int irq) |
150 | { | 148 | { |
151 | unsigned long flags; | 149 | unsigned long flags; |
152 | 150 | ||
153 | if (virt_irq >= NR_IRQS) | 151 | if (irq >= NR_IRQS) |
154 | return; | 152 | return; |
155 | 153 | ||
156 | spin_lock_irqsave(&virt_irq_alloc_lock, flags); | 154 | spin_lock_irqsave(&irq_alloc_lock, flags); |
157 | 155 | ||
158 | virt_irq_table[virt_irq].in_use = 0; | 156 | irq_table[irq].in_use = 0; |
159 | 157 | ||
160 | spin_unlock_irqrestore(&virt_irq_alloc_lock, flags); | 158 | spin_unlock_irqrestore(&irq_alloc_lock, flags); |
161 | } | 159 | } |
162 | #endif | 160 | #endif |
163 | 161 | ||
164 | /* | 162 | /* |
165 | * /proc/interrupts printing: | 163 | * /proc/interrupts printing: |
166 | */ | 164 | */ |
167 | 165 | int arch_show_interrupts(struct seq_file *p, int prec) | |
168 | int show_interrupts(struct seq_file *p, void *v) | ||
169 | { | 166 | { |
170 | int i = *(loff_t *) v, j; | 167 | int j; |
171 | struct irqaction * action; | ||
172 | unsigned long flags; | ||
173 | 168 | ||
174 | if (i == 0) { | 169 | seq_printf(p, "NMI: "); |
175 | seq_printf(p, " "); | 170 | for_each_online_cpu(j) |
176 | for_each_online_cpu(j) | 171 | seq_printf(p, "%10u ", cpu_data(j).__nmi_count); |
177 | seq_printf(p, "CPU%d ",j); | 172 | seq_printf(p, " Non-maskable interrupts\n"); |
178 | seq_putc(p, '\n'); | ||
179 | } | ||
180 | |||
181 | if (i < NR_IRQS) { | ||
182 | raw_spin_lock_irqsave(&irq_desc[i].lock, flags); | ||
183 | action = irq_desc[i].action; | ||
184 | if (!action) | ||
185 | goto skip; | ||
186 | seq_printf(p, "%3d: ",i); | ||
187 | #ifndef CONFIG_SMP | ||
188 | seq_printf(p, "%10u ", kstat_irqs(i)); | ||
189 | #else | ||
190 | for_each_online_cpu(j) | ||
191 | seq_printf(p, "%10u ", kstat_irqs_cpu(i, j)); | ||
192 | #endif | ||
193 | seq_printf(p, " %9s", irq_desc[i].chip->name); | ||
194 | seq_printf(p, " %s", action->name); | ||
195 | |||
196 | for (action=action->next; action; action = action->next) | ||
197 | seq_printf(p, ", %s", action->name); | ||
198 | |||
199 | seq_putc(p, '\n'); | ||
200 | skip: | ||
201 | raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags); | ||
202 | } else if (i == NR_IRQS) { | ||
203 | seq_printf(p, "NMI: "); | ||
204 | for_each_online_cpu(j) | ||
205 | seq_printf(p, "%10u ", cpu_data(j).__nmi_count); | ||
206 | seq_printf(p, " Non-maskable interrupts\n"); | ||
207 | } | ||
208 | return 0; | 173 | return 0; |
209 | } | 174 | } |
210 | 175 | ||
@@ -253,39 +218,38 @@ struct irq_handler_data { | |||
253 | }; | 218 | }; |
254 | 219 | ||
255 | #ifdef CONFIG_SMP | 220 | #ifdef CONFIG_SMP |
256 | static int irq_choose_cpu(unsigned int virt_irq, const struct cpumask *affinity) | 221 | static int irq_choose_cpu(unsigned int irq, const struct cpumask *affinity) |
257 | { | 222 | { |
258 | cpumask_t mask; | 223 | cpumask_t mask; |
259 | int cpuid; | 224 | int cpuid; |
260 | 225 | ||
261 | cpumask_copy(&mask, affinity); | 226 | cpumask_copy(&mask, affinity); |
262 | if (cpus_equal(mask, cpu_online_map)) { | 227 | if (cpumask_equal(&mask, cpu_online_mask)) { |
263 | cpuid = map_to_cpu(virt_irq); | 228 | cpuid = map_to_cpu(irq); |
264 | } else { | 229 | } else { |
265 | cpumask_t tmp; | 230 | cpumask_t tmp; |
266 | 231 | ||
267 | cpus_and(tmp, cpu_online_map, mask); | 232 | cpumask_and(&tmp, cpu_online_mask, &mask); |
268 | cpuid = cpus_empty(tmp) ? map_to_cpu(virt_irq) : first_cpu(tmp); | 233 | cpuid = cpumask_empty(&tmp) ? map_to_cpu(irq) : cpumask_first(&tmp); |
269 | } | 234 | } |
270 | 235 | ||
271 | return cpuid; | 236 | return cpuid; |
272 | } | 237 | } |
273 | #else | 238 | #else |
274 | #define irq_choose_cpu(virt_irq, affinity) \ | 239 | #define irq_choose_cpu(irq, affinity) \ |
275 | real_hard_smp_processor_id() | 240 | real_hard_smp_processor_id() |
276 | #endif | 241 | #endif |
277 | 242 | ||
278 | static void sun4u_irq_enable(unsigned int virt_irq) | 243 | static void sun4u_irq_enable(struct irq_data *data) |
279 | { | 244 | { |
280 | struct irq_handler_data *data = get_irq_chip_data(virt_irq); | 245 | struct irq_handler_data *handler_data = data->handler_data; |
281 | 246 | ||
282 | if (likely(data)) { | 247 | if (likely(handler_data)) { |
283 | unsigned long cpuid, imap, val; | 248 | unsigned long cpuid, imap, val; |
284 | unsigned int tid; | 249 | unsigned int tid; |
285 | 250 | ||
286 | cpuid = irq_choose_cpu(virt_irq, | 251 | cpuid = irq_choose_cpu(data->irq, data->affinity); |
287 | irq_desc[virt_irq].affinity); | 252 | imap = handler_data->imap; |
288 | imap = data->imap; | ||
289 | 253 | ||
290 | tid = sun4u_compute_tid(imap, cpuid); | 254 | tid = sun4u_compute_tid(imap, cpuid); |
291 | 255 | ||
@@ -294,21 +258,21 @@ static void sun4u_irq_enable(unsigned int virt_irq) | |||
294 | IMAP_AID_SAFARI | IMAP_NID_SAFARI); | 258 | IMAP_AID_SAFARI | IMAP_NID_SAFARI); |
295 | val |= tid | IMAP_VALID; | 259 | val |= tid | IMAP_VALID; |
296 | upa_writeq(val, imap); | 260 | upa_writeq(val, imap); |
297 | upa_writeq(ICLR_IDLE, data->iclr); | 261 | upa_writeq(ICLR_IDLE, handler_data->iclr); |
298 | } | 262 | } |
299 | } | 263 | } |
300 | 264 | ||
301 | static int sun4u_set_affinity(unsigned int virt_irq, | 265 | static int sun4u_set_affinity(struct irq_data *data, |
302 | const struct cpumask *mask) | 266 | const struct cpumask *mask, bool force) |
303 | { | 267 | { |
304 | struct irq_handler_data *data = get_irq_chip_data(virt_irq); | 268 | struct irq_handler_data *handler_data = data->handler_data; |
305 | 269 | ||
306 | if (likely(data)) { | 270 | if (likely(handler_data)) { |
307 | unsigned long cpuid, imap, val; | 271 | unsigned long cpuid, imap, val; |
308 | unsigned int tid; | 272 | unsigned int tid; |
309 | 273 | ||
310 | cpuid = irq_choose_cpu(virt_irq, mask); | 274 | cpuid = irq_choose_cpu(data->irq, mask); |
311 | imap = data->imap; | 275 | imap = handler_data->imap; |
312 | 276 | ||
313 | tid = sun4u_compute_tid(imap, cpuid); | 277 | tid = sun4u_compute_tid(imap, cpuid); |
314 | 278 | ||
@@ -317,7 +281,7 @@ static int sun4u_set_affinity(unsigned int virt_irq, | |||
317 | IMAP_AID_SAFARI | IMAP_NID_SAFARI); | 281 | IMAP_AID_SAFARI | IMAP_NID_SAFARI); |
318 | val |= tid | IMAP_VALID; | 282 | val |= tid | IMAP_VALID; |
319 | upa_writeq(val, imap); | 283 | upa_writeq(val, imap); |
320 | upa_writeq(ICLR_IDLE, data->iclr); | 284 | upa_writeq(ICLR_IDLE, handler_data->iclr); |
321 | } | 285 | } |
322 | 286 | ||
323 | return 0; | 287 | return 0; |
@@ -340,27 +304,22 @@ static int sun4u_set_affinity(unsigned int virt_irq, | |||
340 | * sees that, it also hooks up a default ->shutdown method which | 304 | * sees that, it also hooks up a default ->shutdown method which |
341 | * invokes ->mask() which we do not want. See irq_chip_set_defaults(). | 305 | * invokes ->mask() which we do not want. See irq_chip_set_defaults(). |
342 | */ | 306 | */ |
343 | static void sun4u_irq_disable(unsigned int virt_irq) | 307 | static void sun4u_irq_disable(struct irq_data *data) |
344 | { | 308 | { |
345 | } | 309 | } |
346 | 310 | ||
347 | static void sun4u_irq_eoi(unsigned int virt_irq) | 311 | static void sun4u_irq_eoi(struct irq_data *data) |
348 | { | 312 | { |
349 | struct irq_handler_data *data = get_irq_chip_data(virt_irq); | 313 | struct irq_handler_data *handler_data = data->handler_data; |
350 | struct irq_desc *desc = irq_desc + virt_irq; | ||
351 | 314 | ||
352 | if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS))) | 315 | if (likely(handler_data)) |
353 | return; | 316 | upa_writeq(ICLR_IDLE, handler_data->iclr); |
354 | |||
355 | if (likely(data)) | ||
356 | upa_writeq(ICLR_IDLE, data->iclr); | ||
357 | } | 317 | } |
358 | 318 | ||
359 | static void sun4v_irq_enable(unsigned int virt_irq) | 319 | static void sun4v_irq_enable(struct irq_data *data) |
360 | { | 320 | { |
361 | unsigned int ino = virt_irq_table[virt_irq].dev_ino; | 321 | unsigned int ino = irq_table[data->irq].dev_ino; |
362 | unsigned long cpuid = irq_choose_cpu(virt_irq, | 322 | unsigned long cpuid = irq_choose_cpu(data->irq, data->affinity); |
363 | irq_desc[virt_irq].affinity); | ||
364 | int err; | 323 | int err; |
365 | 324 | ||
366 | err = sun4v_intr_settarget(ino, cpuid); | 325 | err = sun4v_intr_settarget(ino, cpuid); |
@@ -377,11 +336,11 @@ static void sun4v_irq_enable(unsigned int virt_irq) | |||
377 | ino, err); | 336 | ino, err); |
378 | } | 337 | } |
379 | 338 | ||
380 | static int sun4v_set_affinity(unsigned int virt_irq, | 339 | static int sun4v_set_affinity(struct irq_data *data, |
381 | const struct cpumask *mask) | 340 | const struct cpumask *mask, bool force) |
382 | { | 341 | { |
383 | unsigned int ino = virt_irq_table[virt_irq].dev_ino; | 342 | unsigned int ino = irq_table[data->irq].dev_ino; |
384 | unsigned long cpuid = irq_choose_cpu(virt_irq, mask); | 343 | unsigned long cpuid = irq_choose_cpu(data->irq, mask); |
385 | int err; | 344 | int err; |
386 | 345 | ||
387 | err = sun4v_intr_settarget(ino, cpuid); | 346 | err = sun4v_intr_settarget(ino, cpuid); |
@@ -392,9 +351,9 @@ static int sun4v_set_affinity(unsigned int virt_irq, | |||
392 | return 0; | 351 | return 0; |
393 | } | 352 | } |
394 | 353 | ||
395 | static void sun4v_irq_disable(unsigned int virt_irq) | 354 | static void sun4v_irq_disable(struct irq_data *data) |
396 | { | 355 | { |
397 | unsigned int ino = virt_irq_table[virt_irq].dev_ino; | 356 | unsigned int ino = irq_table[data->irq].dev_ino; |
398 | int err; | 357 | int err; |
399 | 358 | ||
400 | err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED); | 359 | err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED); |
@@ -403,30 +362,26 @@ static void sun4v_irq_disable(unsigned int virt_irq) | |||
403 | "err(%d)\n", ino, err); | 362 | "err(%d)\n", ino, err); |
404 | } | 363 | } |
405 | 364 | ||
406 | static void sun4v_irq_eoi(unsigned int virt_irq) | 365 | static void sun4v_irq_eoi(struct irq_data *data) |
407 | { | 366 | { |
408 | unsigned int ino = virt_irq_table[virt_irq].dev_ino; | 367 | unsigned int ino = irq_table[data->irq].dev_ino; |
409 | struct irq_desc *desc = irq_desc + virt_irq; | ||
410 | int err; | 368 | int err; |
411 | 369 | ||
412 | if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
413 | return; | ||
414 | |||
415 | err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE); | 370 | err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE); |
416 | if (err != HV_EOK) | 371 | if (err != HV_EOK) |
417 | printk(KERN_ERR "sun4v_intr_setstate(%x): " | 372 | printk(KERN_ERR "sun4v_intr_setstate(%x): " |
418 | "err(%d)\n", ino, err); | 373 | "err(%d)\n", ino, err); |
419 | } | 374 | } |
420 | 375 | ||
421 | static void sun4v_virq_enable(unsigned int virt_irq) | 376 | static void sun4v_virq_enable(struct irq_data *data) |
422 | { | 377 | { |
423 | unsigned long cpuid, dev_handle, dev_ino; | 378 | unsigned long cpuid, dev_handle, dev_ino; |
424 | int err; | 379 | int err; |
425 | 380 | ||
426 | cpuid = irq_choose_cpu(virt_irq, irq_desc[virt_irq].affinity); | 381 | cpuid = irq_choose_cpu(data->irq, data->affinity); |
427 | 382 | ||
428 | dev_handle = virt_irq_table[virt_irq].dev_handle; | 383 | dev_handle = irq_table[data->irq].dev_handle; |
429 | dev_ino = virt_irq_table[virt_irq].dev_ino; | 384 | dev_ino = irq_table[data->irq].dev_ino; |
430 | 385 | ||
431 | err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid); | 386 | err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid); |
432 | if (err != HV_EOK) | 387 | if (err != HV_EOK) |
@@ -447,16 +402,16 @@ static void sun4v_virq_enable(unsigned int virt_irq) | |||
447 | dev_handle, dev_ino, err); | 402 | dev_handle, dev_ino, err); |
448 | } | 403 | } |
449 | 404 | ||
450 | static int sun4v_virt_set_affinity(unsigned int virt_irq, | 405 | static int sun4v_virt_set_affinity(struct irq_data *data, |
451 | const struct cpumask *mask) | 406 | const struct cpumask *mask, bool force) |
452 | { | 407 | { |
453 | unsigned long cpuid, dev_handle, dev_ino; | 408 | unsigned long cpuid, dev_handle, dev_ino; |
454 | int err; | 409 | int err; |
455 | 410 | ||
456 | cpuid = irq_choose_cpu(virt_irq, mask); | 411 | cpuid = irq_choose_cpu(data->irq, mask); |
457 | 412 | ||
458 | dev_handle = virt_irq_table[virt_irq].dev_handle; | 413 | dev_handle = irq_table[data->irq].dev_handle; |
459 | dev_ino = virt_irq_table[virt_irq].dev_ino; | 414 | dev_ino = irq_table[data->irq].dev_ino; |
460 | 415 | ||
461 | err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid); | 416 | err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid); |
462 | if (err != HV_EOK) | 417 | if (err != HV_EOK) |
@@ -467,13 +422,13 @@ static int sun4v_virt_set_affinity(unsigned int virt_irq, | |||
467 | return 0; | 422 | return 0; |
468 | } | 423 | } |
469 | 424 | ||
470 | static void sun4v_virq_disable(unsigned int virt_irq) | 425 | static void sun4v_virq_disable(struct irq_data *data) |
471 | { | 426 | { |
472 | unsigned long dev_handle, dev_ino; | 427 | unsigned long dev_handle, dev_ino; |
473 | int err; | 428 | int err; |
474 | 429 | ||
475 | dev_handle = virt_irq_table[virt_irq].dev_handle; | 430 | dev_handle = irq_table[data->irq].dev_handle; |
476 | dev_ino = virt_irq_table[virt_irq].dev_ino; | 431 | dev_ino = irq_table[data->irq].dev_ino; |
477 | 432 | ||
478 | err = sun4v_vintr_set_valid(dev_handle, dev_ino, | 433 | err = sun4v_vintr_set_valid(dev_handle, dev_ino, |
479 | HV_INTR_DISABLED); | 434 | HV_INTR_DISABLED); |
@@ -483,17 +438,13 @@ static void sun4v_virq_disable(unsigned int virt_irq) | |||
483 | dev_handle, dev_ino, err); | 438 | dev_handle, dev_ino, err); |
484 | } | 439 | } |
485 | 440 | ||
486 | static void sun4v_virq_eoi(unsigned int virt_irq) | 441 | static void sun4v_virq_eoi(struct irq_data *data) |
487 | { | 442 | { |
488 | struct irq_desc *desc = irq_desc + virt_irq; | ||
489 | unsigned long dev_handle, dev_ino; | 443 | unsigned long dev_handle, dev_ino; |
490 | int err; | 444 | int err; |
491 | 445 | ||
492 | if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS))) | 446 | dev_handle = irq_table[data->irq].dev_handle; |
493 | return; | 447 | dev_ino = irq_table[data->irq].dev_ino; |
494 | |||
495 | dev_handle = virt_irq_table[virt_irq].dev_handle; | ||
496 | dev_ino = virt_irq_table[virt_irq].dev_ino; | ||
497 | 448 | ||
498 | err = sun4v_vintr_set_state(dev_handle, dev_ino, | 449 | err = sun4v_vintr_set_state(dev_handle, dev_ino, |
499 | HV_INTR_STATE_IDLE); | 450 | HV_INTR_STATE_IDLE); |
@@ -504,132 +455,128 @@ static void sun4v_virq_eoi(unsigned int virt_irq) | |||
504 | } | 455 | } |
505 | 456 | ||
506 | static struct irq_chip sun4u_irq = { | 457 | static struct irq_chip sun4u_irq = { |
507 | .name = "sun4u", | 458 | .name = "sun4u", |
508 | .enable = sun4u_irq_enable, | 459 | .irq_enable = sun4u_irq_enable, |
509 | .disable = sun4u_irq_disable, | 460 | .irq_disable = sun4u_irq_disable, |
510 | .eoi = sun4u_irq_eoi, | 461 | .irq_eoi = sun4u_irq_eoi, |
511 | .set_affinity = sun4u_set_affinity, | 462 | .irq_set_affinity = sun4u_set_affinity, |
463 | .flags = IRQCHIP_EOI_IF_HANDLED, | ||
512 | }; | 464 | }; |
513 | 465 | ||
514 | static struct irq_chip sun4v_irq = { | 466 | static struct irq_chip sun4v_irq = { |
515 | .name = "sun4v", | 467 | .name = "sun4v", |
516 | .enable = sun4v_irq_enable, | 468 | .irq_enable = sun4v_irq_enable, |
517 | .disable = sun4v_irq_disable, | 469 | .irq_disable = sun4v_irq_disable, |
518 | .eoi = sun4v_irq_eoi, | 470 | .irq_eoi = sun4v_irq_eoi, |
519 | .set_affinity = sun4v_set_affinity, | 471 | .irq_set_affinity = sun4v_set_affinity, |
472 | .flags = IRQCHIP_EOI_IF_HANDLED, | ||
520 | }; | 473 | }; |
521 | 474 | ||
522 | static struct irq_chip sun4v_virq = { | 475 | static struct irq_chip sun4v_virq = { |
523 | .name = "vsun4v", | 476 | .name = "vsun4v", |
524 | .enable = sun4v_virq_enable, | 477 | .irq_enable = sun4v_virq_enable, |
525 | .disable = sun4v_virq_disable, | 478 | .irq_disable = sun4v_virq_disable, |
526 | .eoi = sun4v_virq_eoi, | 479 | .irq_eoi = sun4v_virq_eoi, |
527 | .set_affinity = sun4v_virt_set_affinity, | 480 | .irq_set_affinity = sun4v_virt_set_affinity, |
481 | .flags = IRQCHIP_EOI_IF_HANDLED, | ||
528 | }; | 482 | }; |
529 | 483 | ||
530 | static void pre_flow_handler(unsigned int virt_irq, | 484 | static void pre_flow_handler(struct irq_data *d) |
531 | struct irq_desc *desc) | ||
532 | { | 485 | { |
533 | struct irq_handler_data *data = get_irq_chip_data(virt_irq); | 486 | struct irq_handler_data *handler_data = irq_data_get_irq_handler_data(d); |
534 | unsigned int ino = virt_irq_table[virt_irq].dev_ino; | 487 | unsigned int ino = irq_table[d->irq].dev_ino; |
535 | 488 | ||
536 | data->pre_handler(ino, data->arg1, data->arg2); | 489 | handler_data->pre_handler(ino, handler_data->arg1, handler_data->arg2); |
537 | |||
538 | handle_fasteoi_irq(virt_irq, desc); | ||
539 | } | 490 | } |
540 | 491 | ||
541 | void irq_install_pre_handler(int virt_irq, | 492 | void irq_install_pre_handler(int irq, |
542 | void (*func)(unsigned int, void *, void *), | 493 | void (*func)(unsigned int, void *, void *), |
543 | void *arg1, void *arg2) | 494 | void *arg1, void *arg2) |
544 | { | 495 | { |
545 | struct irq_handler_data *data = get_irq_chip_data(virt_irq); | 496 | struct irq_handler_data *handler_data = irq_get_handler_data(irq); |
546 | struct irq_desc *desc = irq_desc + virt_irq; | ||
547 | 497 | ||
548 | data->pre_handler = func; | 498 | handler_data->pre_handler = func; |
549 | data->arg1 = arg1; | 499 | handler_data->arg1 = arg1; |
550 | data->arg2 = arg2; | 500 | handler_data->arg2 = arg2; |
551 | 501 | ||
552 | desc->handle_irq = pre_flow_handler; | 502 | __irq_set_preflow_handler(irq, pre_flow_handler); |
553 | } | 503 | } |
554 | 504 | ||
555 | unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap) | 505 | unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap) |
556 | { | 506 | { |
557 | struct ino_bucket *bucket; | 507 | struct ino_bucket *bucket; |
558 | struct irq_handler_data *data; | 508 | struct irq_handler_data *handler_data; |
559 | unsigned int virt_irq; | 509 | unsigned int irq; |
560 | int ino; | 510 | int ino; |
561 | 511 | ||
562 | BUG_ON(tlb_type == hypervisor); | 512 | BUG_ON(tlb_type == hypervisor); |
563 | 513 | ||
564 | ino = (upa_readq(imap) & (IMAP_IGN | IMAP_INO)) + inofixup; | 514 | ino = (upa_readq(imap) & (IMAP_IGN | IMAP_INO)) + inofixup; |
565 | bucket = &ivector_table[ino]; | 515 | bucket = &ivector_table[ino]; |
566 | virt_irq = bucket_get_virt_irq(__pa(bucket)); | 516 | irq = bucket_get_irq(__pa(bucket)); |
567 | if (!virt_irq) { | 517 | if (!irq) { |
568 | virt_irq = virt_irq_alloc(0, ino); | 518 | irq = irq_alloc(0, ino); |
569 | bucket_set_virt_irq(__pa(bucket), virt_irq); | 519 | bucket_set_irq(__pa(bucket), irq); |
570 | set_irq_chip_and_handler_name(virt_irq, | 520 | irq_set_chip_and_handler_name(irq, &sun4u_irq, |
571 | &sun4u_irq, | 521 | handle_fasteoi_irq, "IVEC"); |
572 | handle_fasteoi_irq, | ||
573 | "IVEC"); | ||
574 | } | 522 | } |
575 | 523 | ||
576 | data = get_irq_chip_data(virt_irq); | 524 | handler_data = irq_get_handler_data(irq); |
577 | if (unlikely(data)) | 525 | if (unlikely(handler_data)) |
578 | goto out; | 526 | goto out; |
579 | 527 | ||
580 | data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC); | 528 | handler_data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC); |
581 | if (unlikely(!data)) { | 529 | if (unlikely(!handler_data)) { |
582 | prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n"); | 530 | prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n"); |
583 | prom_halt(); | 531 | prom_halt(); |
584 | } | 532 | } |
585 | set_irq_chip_data(virt_irq, data); | 533 | irq_set_handler_data(irq, handler_data); |
586 | 534 | ||
587 | data->imap = imap; | 535 | handler_data->imap = imap; |
588 | data->iclr = iclr; | 536 | handler_data->iclr = iclr; |
589 | 537 | ||
590 | out: | 538 | out: |
591 | return virt_irq; | 539 | return irq; |
592 | } | 540 | } |
593 | 541 | ||
594 | static unsigned int sun4v_build_common(unsigned long sysino, | 542 | static unsigned int sun4v_build_common(unsigned long sysino, |
595 | struct irq_chip *chip) | 543 | struct irq_chip *chip) |
596 | { | 544 | { |
597 | struct ino_bucket *bucket; | 545 | struct ino_bucket *bucket; |
598 | struct irq_handler_data *data; | 546 | struct irq_handler_data *handler_data; |
599 | unsigned int virt_irq; | 547 | unsigned int irq; |
600 | 548 | ||
601 | BUG_ON(tlb_type != hypervisor); | 549 | BUG_ON(tlb_type != hypervisor); |
602 | 550 | ||
603 | bucket = &ivector_table[sysino]; | 551 | bucket = &ivector_table[sysino]; |
604 | virt_irq = bucket_get_virt_irq(__pa(bucket)); | 552 | irq = bucket_get_irq(__pa(bucket)); |
605 | if (!virt_irq) { | 553 | if (!irq) { |
606 | virt_irq = virt_irq_alloc(0, sysino); | 554 | irq = irq_alloc(0, sysino); |
607 | bucket_set_virt_irq(__pa(bucket), virt_irq); | 555 | bucket_set_irq(__pa(bucket), irq); |
608 | set_irq_chip_and_handler_name(virt_irq, chip, | 556 | irq_set_chip_and_handler_name(irq, chip, handle_fasteoi_irq, |
609 | handle_fasteoi_irq, | ||
610 | "IVEC"); | 557 | "IVEC"); |
611 | } | 558 | } |
612 | 559 | ||
613 | data = get_irq_chip_data(virt_irq); | 560 | handler_data = irq_get_handler_data(irq); |
614 | if (unlikely(data)) | 561 | if (unlikely(handler_data)) |
615 | goto out; | 562 | goto out; |
616 | 563 | ||
617 | data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC); | 564 | handler_data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC); |
618 | if (unlikely(!data)) { | 565 | if (unlikely(!handler_data)) { |
619 | prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n"); | 566 | prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n"); |
620 | prom_halt(); | 567 | prom_halt(); |
621 | } | 568 | } |
622 | set_irq_chip_data(virt_irq, data); | 569 | irq_set_handler_data(irq, handler_data); |
623 | 570 | ||
624 | /* Catch accidental accesses to these things. IMAP/ICLR handling | 571 | /* Catch accidental accesses to these things. IMAP/ICLR handling |
625 | * is done by hypervisor calls on sun4v platforms, not by direct | 572 | * is done by hypervisor calls on sun4v platforms, not by direct |
626 | * register accesses. | 573 | * register accesses. |
627 | */ | 574 | */ |
628 | data->imap = ~0UL; | 575 | handler_data->imap = ~0UL; |
629 | data->iclr = ~0UL; | 576 | handler_data->iclr = ~0UL; |
630 | 577 | ||
631 | out: | 578 | out: |
632 | return virt_irq; | 579 | return irq; |
633 | } | 580 | } |
634 | 581 | ||
635 | unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino) | 582 | unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino) |
@@ -641,11 +588,10 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino) | |||
641 | 588 | ||
642 | unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino) | 589 | unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino) |
643 | { | 590 | { |
644 | struct irq_handler_data *data; | 591 | struct irq_handler_data *handler_data; |
645 | unsigned long hv_err, cookie; | 592 | unsigned long hv_err, cookie; |
646 | struct ino_bucket *bucket; | 593 | struct ino_bucket *bucket; |
647 | struct irq_desc *desc; | 594 | unsigned int irq; |
648 | unsigned int virt_irq; | ||
649 | 595 | ||
650 | bucket = kzalloc(sizeof(struct ino_bucket), GFP_ATOMIC); | 596 | bucket = kzalloc(sizeof(struct ino_bucket), GFP_ATOMIC); |
651 | if (unlikely(!bucket)) | 597 | if (unlikely(!bucket)) |
@@ -662,32 +608,29 @@ unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino) | |||
662 | ((unsigned long) bucket + | 608 | ((unsigned long) bucket + |
663 | sizeof(struct ino_bucket))); | 609 | sizeof(struct ino_bucket))); |
664 | 610 | ||
665 | virt_irq = virt_irq_alloc(devhandle, devino); | 611 | irq = irq_alloc(devhandle, devino); |
666 | bucket_set_virt_irq(__pa(bucket), virt_irq); | 612 | bucket_set_irq(__pa(bucket), irq); |
667 | 613 | ||
668 | set_irq_chip_and_handler_name(virt_irq, &sun4v_virq, | 614 | irq_set_chip_and_handler_name(irq, &sun4v_virq, handle_fasteoi_irq, |
669 | handle_fasteoi_irq, | ||
670 | "IVEC"); | 615 | "IVEC"); |
671 | 616 | ||
672 | data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC); | 617 | handler_data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC); |
673 | if (unlikely(!data)) | 618 | if (unlikely(!handler_data)) |
674 | return 0; | 619 | return 0; |
675 | 620 | ||
676 | /* In order to make the LDC channel startup sequence easier, | 621 | /* In order to make the LDC channel startup sequence easier, |
677 | * especially wrt. locking, we do not let request_irq() enable | 622 | * especially wrt. locking, we do not let request_irq() enable |
678 | * the interrupt. | 623 | * the interrupt. |
679 | */ | 624 | */ |
680 | desc = irq_desc + virt_irq; | 625 | irq_set_status_flags(irq, IRQ_NOAUTOEN); |
681 | desc->status |= IRQ_NOAUTOEN; | 626 | irq_set_handler_data(irq, handler_data); |
682 | |||
683 | set_irq_chip_data(virt_irq, data); | ||
684 | 627 | ||
685 | /* Catch accidental accesses to these things. IMAP/ICLR handling | 628 | /* Catch accidental accesses to these things. IMAP/ICLR handling |
686 | * is done by hypervisor calls on sun4v platforms, not by direct | 629 | * is done by hypervisor calls on sun4v platforms, not by direct |
687 | * register accesses. | 630 | * register accesses. |
688 | */ | 631 | */ |
689 | data->imap = ~0UL; | 632 | handler_data->imap = ~0UL; |
690 | data->iclr = ~0UL; | 633 | handler_data->iclr = ~0UL; |
691 | 634 | ||
692 | cookie = ~__pa(bucket); | 635 | cookie = ~__pa(bucket); |
693 | hv_err = sun4v_vintr_set_cookie(devhandle, devino, cookie); | 636 | hv_err = sun4v_vintr_set_cookie(devhandle, devino, cookie); |
@@ -697,30 +640,30 @@ unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino) | |||
697 | prom_halt(); | 640 | prom_halt(); |
698 | } | 641 | } |
699 | 642 | ||
700 | return virt_irq; | 643 | return irq; |
701 | } | 644 | } |
702 | 645 | ||
703 | void ack_bad_irq(unsigned int virt_irq) | 646 | void ack_bad_irq(unsigned int irq) |
704 | { | 647 | { |
705 | unsigned int ino = virt_irq_table[virt_irq].dev_ino; | 648 | unsigned int ino = irq_table[irq].dev_ino; |
706 | 649 | ||
707 | if (!ino) | 650 | if (!ino) |
708 | ino = 0xdeadbeef; | 651 | ino = 0xdeadbeef; |
709 | 652 | ||
710 | printk(KERN_CRIT "Unexpected IRQ from ino[%x] virt_irq[%u]\n", | 653 | printk(KERN_CRIT "Unexpected IRQ from ino[%x] irq[%u]\n", |
711 | ino, virt_irq); | 654 | ino, irq); |
712 | } | 655 | } |
713 | 656 | ||
714 | void *hardirq_stack[NR_CPUS]; | 657 | void *hardirq_stack[NR_CPUS]; |
715 | void *softirq_stack[NR_CPUS]; | 658 | void *softirq_stack[NR_CPUS]; |
716 | 659 | ||
717 | void __irq_entry handler_irq(int irq, struct pt_regs *regs) | 660 | void __irq_entry handler_irq(int pil, struct pt_regs *regs) |
718 | { | 661 | { |
719 | unsigned long pstate, bucket_pa; | 662 | unsigned long pstate, bucket_pa; |
720 | struct pt_regs *old_regs; | 663 | struct pt_regs *old_regs; |
721 | void *orig_sp; | 664 | void *orig_sp; |
722 | 665 | ||
723 | clear_softint(1 << irq); | 666 | clear_softint(1 << pil); |
724 | 667 | ||
725 | old_regs = set_irq_regs(regs); | 668 | old_regs = set_irq_regs(regs); |
726 | irq_enter(); | 669 | irq_enter(); |
@@ -739,18 +682,14 @@ void __irq_entry handler_irq(int irq, struct pt_regs *regs) | |||
739 | orig_sp = set_hardirq_stack(); | 682 | orig_sp = set_hardirq_stack(); |
740 | 683 | ||
741 | while (bucket_pa) { | 684 | while (bucket_pa) { |
742 | struct irq_desc *desc; | ||
743 | unsigned long next_pa; | 685 | unsigned long next_pa; |
744 | unsigned int virt_irq; | 686 | unsigned int irq; |
745 | 687 | ||
746 | next_pa = bucket_get_chain_pa(bucket_pa); | 688 | next_pa = bucket_get_chain_pa(bucket_pa); |
747 | virt_irq = bucket_get_virt_irq(bucket_pa); | 689 | irq = bucket_get_irq(bucket_pa); |
748 | bucket_clear_chain_pa(bucket_pa); | 690 | bucket_clear_chain_pa(bucket_pa); |
749 | 691 | ||
750 | desc = irq_desc + virt_irq; | 692 | generic_handle_irq(irq); |
751 | |||
752 | if (!(desc->status & IRQ_DISABLED)) | ||
753 | desc->handle_irq(virt_irq, desc); | ||
754 | 693 | ||
755 | bucket_pa = next_pa; | 694 | bucket_pa = next_pa; |
756 | } | 695 | } |
@@ -793,16 +732,18 @@ void fixup_irqs(void) | |||
793 | unsigned int irq; | 732 | unsigned int irq; |
794 | 733 | ||
795 | for (irq = 0; irq < NR_IRQS; irq++) { | 734 | for (irq = 0; irq < NR_IRQS; irq++) { |
735 | struct irq_desc *desc = irq_to_desc(irq); | ||
736 | struct irq_data *data = irq_desc_get_irq_data(desc); | ||
796 | unsigned long flags; | 737 | unsigned long flags; |
797 | 738 | ||
798 | raw_spin_lock_irqsave(&irq_desc[irq].lock, flags); | 739 | raw_spin_lock_irqsave(&desc->lock, flags); |
799 | if (irq_desc[irq].action && | 740 | if (desc->action && !irqd_is_per_cpu(data)) { |
800 | !(irq_desc[irq].status & IRQ_PER_CPU)) { | 741 | if (data->chip->irq_set_affinity) |
801 | if (irq_desc[irq].chip->set_affinity) | 742 | data->chip->irq_set_affinity(data, |
802 | irq_desc[irq].chip->set_affinity(irq, | 743 | data->affinity, |
803 | irq_desc[irq].affinity); | 744 | false); |
804 | } | 745 | } |
805 | raw_spin_unlock_irqrestore(&irq_desc[irq].lock, flags); | 746 | raw_spin_unlock_irqrestore(&desc->lock, flags); |
806 | } | 747 | } |
807 | 748 | ||
808 | tick_ops->disable_irq(); | 749 | tick_ops->disable_irq(); |
@@ -1040,5 +981,5 @@ void __init init_IRQ(void) | |||
1040 | : "i" (PSTATE_IE) | 981 | : "i" (PSTATE_IE) |
1041 | : "g1"); | 982 | : "g1"); |
1042 | 983 | ||
1043 | irq_desc[0].action = &timer_irq_action; | 984 | irq_to_desc(0)->action = &timer_irq_action; |
1044 | } | 985 | } |