aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/kernel/irq.c')
-rw-r--r--arch/sparc64/kernel/irq.c146
1 files changed, 115 insertions, 31 deletions
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index c3d068c7a412..c443db184371 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -22,6 +22,7 @@
22#include <linux/seq_file.h> 22#include <linux/seq_file.h>
23#include <linux/bootmem.h> 23#include <linux/bootmem.h>
24#include <linux/irq.h> 24#include <linux/irq.h>
25#include <linux/msi.h>
25 26
26#include <asm/ptrace.h> 27#include <asm/ptrace.h>
27#include <asm/processor.h> 28#include <asm/processor.h>
@@ -87,7 +88,6 @@ struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BY
87#define irq_work(__cpu) &(trap_block[(__cpu)].irq_worklist) 88#define irq_work(__cpu) &(trap_block[(__cpu)].irq_worklist)
88 89
89static unsigned int virt_to_real_irq_table[NR_IRQS]; 90static unsigned int virt_to_real_irq_table[NR_IRQS];
90static unsigned char virt_irq_cur = 1;
91 91
92static unsigned char virt_irq_alloc(unsigned int real_irq) 92static unsigned char virt_irq_alloc(unsigned int real_irq)
93{ 93{
@@ -95,24 +95,32 @@ static unsigned char virt_irq_alloc(unsigned int real_irq)
95 95
96 BUILD_BUG_ON(NR_IRQS >= 256); 96 BUILD_BUG_ON(NR_IRQS >= 256);
97 97
98 ent = virt_irq_cur; 98 for (ent = 1; ent < NR_IRQS; ent++) {
99 if (!virt_to_real_irq_table[ent])
100 break;
101 }
99 if (ent >= NR_IRQS) { 102 if (ent >= NR_IRQS) {
100 printk(KERN_ERR "IRQ: Out of virtual IRQs.\n"); 103 printk(KERN_ERR "IRQ: Out of virtual IRQs.\n");
101 return 0; 104 return 0;
102 } 105 }
103 106
104 virt_irq_cur = ent + 1;
105 virt_to_real_irq_table[ent] = real_irq; 107 virt_to_real_irq_table[ent] = real_irq;
106 108
107 return ent; 109 return ent;
108} 110}
109 111
110#if 0 /* Currently unused. */ 112#ifdef CONFIG_PCI_MSI
111static unsigned char real_to_virt_irq(unsigned int real_irq) 113static void virt_irq_free(unsigned int virt_irq)
112{ 114{
113 struct ino_bucket *bucket = __bucket(real_irq); 115 unsigned int real_irq;
114 116
115 return bucket->virt_irq; 117 if (virt_irq >= NR_IRQS)
118 return;
119
120 real_irq = virt_to_real_irq_table[virt_irq];
121 virt_to_real_irq_table[virt_irq] = 0;
122
123 __bucket(real_irq)->virt_irq = 0;
116} 124}
117#endif 125#endif
118 126
@@ -268,8 +276,7 @@ static int irq_choose_cpu(unsigned int virt_irq)
268 276
269static void sun4u_irq_enable(unsigned int virt_irq) 277static void sun4u_irq_enable(unsigned int virt_irq)
270{ 278{
271 irq_desc_t *desc = irq_desc + virt_irq; 279 struct irq_handler_data *data = get_irq_chip_data(virt_irq);
272 struct irq_handler_data *data = desc->handler_data;
273 280
274 if (likely(data)) { 281 if (likely(data)) {
275 unsigned long cpuid, imap; 282 unsigned long cpuid, imap;
@@ -286,8 +293,7 @@ static void sun4u_irq_enable(unsigned int virt_irq)
286 293
287static void sun4u_irq_disable(unsigned int virt_irq) 294static void sun4u_irq_disable(unsigned int virt_irq)
288{ 295{
289 irq_desc_t *desc = irq_desc + virt_irq; 296 struct irq_handler_data *data = get_irq_chip_data(virt_irq);
290 struct irq_handler_data *data = desc->handler_data;
291 297
292 if (likely(data)) { 298 if (likely(data)) {
293 unsigned long imap = data->imap; 299 unsigned long imap = data->imap;
@@ -300,8 +306,7 @@ static void sun4u_irq_disable(unsigned int virt_irq)
300 306
301static void sun4u_irq_end(unsigned int virt_irq) 307static void sun4u_irq_end(unsigned int virt_irq)
302{ 308{
303 irq_desc_t *desc = irq_desc + virt_irq; 309 struct irq_handler_data *data = get_irq_chip_data(virt_irq);
304 struct irq_handler_data *data = desc->handler_data;
305 310
306 if (likely(data)) 311 if (likely(data))
307 upa_writel(ICLR_IDLE, data->iclr); 312 upa_writel(ICLR_IDLE, data->iclr);
@@ -344,6 +349,20 @@ static void sun4v_irq_disable(unsigned int virt_irq)
344 } 349 }
345} 350}
346 351
352#ifdef CONFIG_PCI_MSI
353static void sun4v_msi_enable(unsigned int virt_irq)
354{
355 sun4v_irq_enable(virt_irq);
356 unmask_msi_irq(virt_irq);
357}
358
359static void sun4v_msi_disable(unsigned int virt_irq)
360{
361 mask_msi_irq(virt_irq);
362 sun4v_irq_disable(virt_irq);
363}
364#endif
365
347static void sun4v_irq_end(unsigned int virt_irq) 366static void sun4v_irq_end(unsigned int virt_irq)
348{ 367{
349 struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); 368 struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
@@ -362,8 +381,7 @@ static void sun4v_irq_end(unsigned int virt_irq)
362static void run_pre_handler(unsigned int virt_irq) 381static void run_pre_handler(unsigned int virt_irq)
363{ 382{
364 struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); 383 struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
365 irq_desc_t *desc = irq_desc + virt_irq; 384 struct irq_handler_data *data = get_irq_chip_data(virt_irq);
366 struct irq_handler_data *data = desc->handler_data;
367 385
368 if (likely(data->pre_handler)) { 386 if (likely(data->pre_handler)) {
369 data->pre_handler(__irq_ino(__irq(bucket)), 387 data->pre_handler(__irq_ino(__irq(bucket)),
@@ -402,30 +420,47 @@ static struct irq_chip sun4v_irq_ack = {
402 .end = sun4v_irq_end, 420 .end = sun4v_irq_end,
403}; 421};
404 422
423#ifdef CONFIG_PCI_MSI
424static struct irq_chip sun4v_msi = {
425 .typename = "sun4v+msi",
426 .mask = mask_msi_irq,
427 .unmask = unmask_msi_irq,
428 .enable = sun4v_msi_enable,
429 .disable = sun4v_msi_disable,
430 .ack = run_pre_handler,
431 .end = sun4v_irq_end,
432};
433#endif
434
405void irq_install_pre_handler(int virt_irq, 435void irq_install_pre_handler(int virt_irq,
406 void (*func)(unsigned int, void *, void *), 436 void (*func)(unsigned int, void *, void *),
407 void *arg1, void *arg2) 437 void *arg1, void *arg2)
408{ 438{
409 irq_desc_t *desc = irq_desc + virt_irq; 439 struct irq_handler_data *data = get_irq_chip_data(virt_irq);
410 struct irq_handler_data *data = desc->handler_data; 440 struct irq_chip *chip;
411 441
412 data->pre_handler = func; 442 data->pre_handler = func;
413 data->pre_handler_arg1 = arg1; 443 data->pre_handler_arg1 = arg1;
414 data->pre_handler_arg2 = arg2; 444 data->pre_handler_arg2 = arg2;
415 445
416 if (desc->chip == &sun4u_irq_ack || 446 chip = get_irq_chip(virt_irq);
417 desc->chip == &sun4v_irq_ack) 447 if (chip == &sun4u_irq_ack ||
448 chip == &sun4v_irq_ack
449#ifdef CONFIG_PCI_MSI
450 || chip == &sun4v_msi
451#endif
452 )
418 return; 453 return;
419 454
420 desc->chip = (desc->chip == &sun4u_irq ? 455 chip = (chip == &sun4u_irq ?
421 &sun4u_irq_ack : &sun4v_irq_ack); 456 &sun4u_irq_ack : &sun4v_irq_ack);
457 set_irq_chip(virt_irq, chip);
422} 458}
423 459
424unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap) 460unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
425{ 461{
426 struct ino_bucket *bucket; 462 struct ino_bucket *bucket;
427 struct irq_handler_data *data; 463 struct irq_handler_data *data;
428 irq_desc_t *desc;
429 int ino; 464 int ino;
430 465
431 BUG_ON(tlb_type == hypervisor); 466 BUG_ON(tlb_type == hypervisor);
@@ -434,11 +469,11 @@ unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
434 bucket = &ivector_table[ino]; 469 bucket = &ivector_table[ino];
435 if (!bucket->virt_irq) { 470 if (!bucket->virt_irq) {
436 bucket->virt_irq = virt_irq_alloc(__irq(bucket)); 471 bucket->virt_irq = virt_irq_alloc(__irq(bucket));
437 irq_desc[bucket->virt_irq].chip = &sun4u_irq; 472 set_irq_chip(bucket->virt_irq, &sun4u_irq);
438 } 473 }
439 474
440 desc = irq_desc + bucket->virt_irq; 475 data = get_irq_chip_data(bucket->virt_irq);
441 if (unlikely(desc->handler_data)) 476 if (unlikely(data))
442 goto out; 477 goto out;
443 478
444 data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC); 479 data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
@@ -446,7 +481,7 @@ unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
446 prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n"); 481 prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n");
447 prom_halt(); 482 prom_halt();
448 } 483 }
449 desc->handler_data = data; 484 set_irq_chip_data(bucket->virt_irq, data);
450 485
451 data->imap = imap; 486 data->imap = imap;
452 data->iclr = iclr; 487 data->iclr = iclr;
@@ -460,7 +495,6 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
460 struct ino_bucket *bucket; 495 struct ino_bucket *bucket;
461 struct irq_handler_data *data; 496 struct irq_handler_data *data;
462 unsigned long sysino; 497 unsigned long sysino;
463 irq_desc_t *desc;
464 498
465 BUG_ON(tlb_type != hypervisor); 499 BUG_ON(tlb_type != hypervisor);
466 500
@@ -468,11 +502,11 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
468 bucket = &ivector_table[sysino]; 502 bucket = &ivector_table[sysino];
469 if (!bucket->virt_irq) { 503 if (!bucket->virt_irq) {
470 bucket->virt_irq = virt_irq_alloc(__irq(bucket)); 504 bucket->virt_irq = virt_irq_alloc(__irq(bucket));
471 irq_desc[bucket->virt_irq].chip = &sun4v_irq; 505 set_irq_chip(bucket->virt_irq, &sun4v_irq);
472 } 506 }
473 507
474 desc = irq_desc + bucket->virt_irq; 508 data = get_irq_chip_data(bucket->virt_irq);
475 if (unlikely(desc->handler_data)) 509 if (unlikely(data))
476 goto out; 510 goto out;
477 511
478 data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC); 512 data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
@@ -480,7 +514,7 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
480 prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n"); 514 prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n");
481 prom_halt(); 515 prom_halt();
482 } 516 }
483 desc->handler_data = data; 517 set_irq_chip_data(bucket->virt_irq, data);
484 518
485 /* Catch accidental accesses to these things. IMAP/ICLR handling 519 /* Catch accidental accesses to these things. IMAP/ICLR handling
486 * is done by hypervisor calls on sun4v platforms, not by direct 520 * is done by hypervisor calls on sun4v platforms, not by direct
@@ -493,6 +527,56 @@ out:
493 return bucket->virt_irq; 527 return bucket->virt_irq;
494} 528}
495 529
530#ifdef CONFIG_PCI_MSI
531unsigned int sun4v_build_msi(u32 devhandle, unsigned int *virt_irq_p,
532 unsigned int msi_start, unsigned int msi_end)
533{
534 struct ino_bucket *bucket;
535 struct irq_handler_data *data;
536 unsigned long sysino;
537 unsigned int devino;
538
539 BUG_ON(tlb_type != hypervisor);
540
541 /* Find a free devino in the given range. */
542 for (devino = msi_start; devino < msi_end; devino++) {
543 sysino = sun4v_devino_to_sysino(devhandle, devino);
544 bucket = &ivector_table[sysino];
545 if (!bucket->virt_irq)
546 break;
547 }
548 if (devino >= msi_end)
549 return 0;
550
551 sysino = sun4v_devino_to_sysino(devhandle, devino);
552 bucket = &ivector_table[sysino];
553 bucket->virt_irq = virt_irq_alloc(__irq(bucket));
554 *virt_irq_p = bucket->virt_irq;
555 set_irq_chip(bucket->virt_irq, &sun4v_msi);
556
557 data = get_irq_chip_data(bucket->virt_irq);
558 if (unlikely(data))
559 return devino;
560
561 data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
562 if (unlikely(!data)) {
563 prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n");
564 prom_halt();
565 }
566 set_irq_chip_data(bucket->virt_irq, data);
567
568 data->imap = ~0UL;
569 data->iclr = ~0UL;
570
571 return devino;
572}
573
574void sun4v_destroy_msi(unsigned int virt_irq)
575{
576 virt_irq_free(virt_irq);
577}
578#endif
579
496void ack_bad_irq(unsigned int virt_irq) 580void ack_bad_irq(unsigned int virt_irq)
497{ 581{
498 struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); 582 struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);