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