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.c131
1 files changed, 122 insertions, 9 deletions
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index a36f8dd0c021..e60d283f60bc 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -1,7 +1,6 @@
1/* $Id: irq.c,v 1.114 2002/01/11 08:45:38 davem Exp $ 1/* irq.c: UltraSparc IRQ handling/init/registry.
2 * irq.c: UltraSparc IRQ handling/init/registry.
3 * 2 *
4 * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) 3 * Copyright (C) 1997, 2007 David S. Miller (davem@davemloft.net)
5 * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) 4 * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
6 * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) 5 * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
7 */ 6 */
@@ -43,6 +42,7 @@
43#include <asm/cpudata.h> 42#include <asm/cpudata.h>
44#include <asm/auxio.h> 43#include <asm/auxio.h>
45#include <asm/head.h> 44#include <asm/head.h>
45#include <asm/hypervisor.h>
46 46
47/* UPA nodes send interrupt packet to UltraSparc with first data reg 47/* UPA nodes send interrupt packet to UltraSparc with first data reg
48 * value low 5 (7 on Starfire) bits holding the IRQ identifier being 48 * value low 5 (7 on Starfire) bits holding the IRQ identifier being
@@ -380,6 +380,76 @@ static void sun4v_irq_end(unsigned int virt_irq)
380 } 380 }
381} 381}
382 382
383static void sun4v_virq_enable(unsigned int virt_irq)
384{
385 struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
386 unsigned int ino = bucket - &ivector_table[0];
387
388 if (likely(bucket)) {
389 unsigned long cpuid, dev_handle, dev_ino;
390 int err;
391
392 cpuid = irq_choose_cpu(virt_irq);
393
394 dev_handle = ino & IMAP_IGN;
395 dev_ino = ino & IMAP_INO;
396
397 err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
398 if (err != HV_EOK)
399 printk("sun4v_vintr_set_target(%lx,%lx,%lu): "
400 "err(%d)\n",
401 dev_handle, dev_ino, cpuid, err);
402 err = sun4v_vintr_set_state(dev_handle, dev_ino,
403 HV_INTR_ENABLED);
404 if (err != HV_EOK)
405 printk("sun4v_vintr_set_state(%lx,%lx,"
406 "HV_INTR_ENABLED): err(%d)\n",
407 dev_handle, dev_ino, err);
408 }
409}
410
411static void sun4v_virq_disable(unsigned int virt_irq)
412{
413 struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
414 unsigned int ino = bucket - &ivector_table[0];
415
416 if (likely(bucket)) {
417 unsigned long dev_handle, dev_ino;
418 int err;
419
420 dev_handle = ino & IMAP_IGN;
421 dev_ino = ino & IMAP_INO;
422
423 err = sun4v_vintr_set_state(dev_handle, dev_ino,
424 HV_INTR_DISABLED);
425 if (err != HV_EOK)
426 printk("sun4v_vintr_set_state(%lx,%lx,"
427 "HV_INTR_DISABLED): err(%d)\n",
428 dev_handle, dev_ino, err);
429 }
430}
431
432static void sun4v_virq_end(unsigned int virt_irq)
433{
434 struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
435 unsigned int ino = bucket - &ivector_table[0];
436
437 if (likely(bucket)) {
438 unsigned long dev_handle, dev_ino;
439 int err;
440
441 dev_handle = ino & IMAP_IGN;
442 dev_ino = ino & IMAP_INO;
443
444 err = sun4v_vintr_set_state(dev_handle, dev_ino,
445 HV_INTR_STATE_IDLE);
446 if (err != HV_EOK)
447 printk("sun4v_vintr_set_state(%lx,%lx,"
448 "HV_INTR_STATE_IDLE): err(%d)\n",
449 dev_handle, dev_ino, err);
450 }
451}
452
383static void run_pre_handler(unsigned int virt_irq) 453static void run_pre_handler(unsigned int virt_irq)
384{ 454{
385 struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq); 455 struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
@@ -434,6 +504,21 @@ static struct irq_chip sun4v_msi = {
434}; 504};
435#endif 505#endif
436 506
507static struct irq_chip sun4v_virq = {
508 .typename = "vsun4v",
509 .enable = sun4v_virq_enable,
510 .disable = sun4v_virq_disable,
511 .end = sun4v_virq_end,
512};
513
514static struct irq_chip sun4v_virq_ack = {
515 .typename = "vsun4v+ack",
516 .enable = sun4v_virq_enable,
517 .disable = sun4v_virq_disable,
518 .ack = run_pre_handler,
519 .end = sun4v_virq_end,
520};
521
437void irq_install_pre_handler(int virt_irq, 522void irq_install_pre_handler(int virt_irq,
438 void (*func)(unsigned int, void *, void *), 523 void (*func)(unsigned int, void *, void *),
439 void *arg1, void *arg2) 524 void *arg1, void *arg2)
@@ -447,7 +532,8 @@ void irq_install_pre_handler(int virt_irq,
447 532
448 chip = get_irq_chip(virt_irq); 533 chip = get_irq_chip(virt_irq);
449 if (chip == &sun4u_irq_ack || 534 if (chip == &sun4u_irq_ack ||
450 chip == &sun4v_irq_ack 535 chip == &sun4v_irq_ack ||
536 chip == &sun4v_virq_ack
451#ifdef CONFIG_PCI_MSI 537#ifdef CONFIG_PCI_MSI
452 || chip == &sun4v_msi 538 || chip == &sun4v_msi
453#endif 539#endif
@@ -455,7 +541,9 @@ void irq_install_pre_handler(int virt_irq,
455 return; 541 return;
456 542
457 chip = (chip == &sun4u_irq ? 543 chip = (chip == &sun4u_irq ?
458 &sun4u_irq_ack : &sun4v_irq_ack); 544 &sun4u_irq_ack :
545 (chip == &sun4v_irq ?
546 &sun4v_irq_ack : &sun4v_virq_ack));
459 set_irq_chip(virt_irq, chip); 547 set_irq_chip(virt_irq, chip);
460} 548}
461 549
@@ -492,19 +580,18 @@ out:
492 return bucket->virt_irq; 580 return bucket->virt_irq;
493} 581}
494 582
495unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino) 583static unsigned int sun4v_build_common(unsigned long sysino,
584 struct irq_chip *chip)
496{ 585{
497 struct ino_bucket *bucket; 586 struct ino_bucket *bucket;
498 struct irq_handler_data *data; 587 struct irq_handler_data *data;
499 unsigned long sysino;
500 588
501 BUG_ON(tlb_type != hypervisor); 589 BUG_ON(tlb_type != hypervisor);
502 590
503 sysino = sun4v_devino_to_sysino(devhandle, devino);
504 bucket = &ivector_table[sysino]; 591 bucket = &ivector_table[sysino];
505 if (!bucket->virt_irq) { 592 if (!bucket->virt_irq) {
506 bucket->virt_irq = virt_irq_alloc(__irq(bucket)); 593 bucket->virt_irq = virt_irq_alloc(__irq(bucket));
507 set_irq_chip(bucket->virt_irq, &sun4v_irq); 594 set_irq_chip(bucket->virt_irq, chip);
508 } 595 }
509 596
510 data = get_irq_chip_data(bucket->virt_irq); 597 data = get_irq_chip_data(bucket->virt_irq);
@@ -529,6 +616,32 @@ out:
529 return bucket->virt_irq; 616 return bucket->virt_irq;
530} 617}
531 618
619unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
620{
621 unsigned long sysino = sun4v_devino_to_sysino(devhandle, devino);
622
623 return sun4v_build_common(sysino, &sun4v_irq);
624}
625
626unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
627{
628 unsigned long sysino, hv_err;
629
630 BUG_ON(devhandle & ~IMAP_IGN);
631 BUG_ON(devino & ~IMAP_INO);
632
633 sysino = devhandle | devino;
634
635 hv_err = sun4v_vintr_set_cookie(devhandle, devino, sysino);
636 if (hv_err) {
637 prom_printf("IRQ: Fatal, cannot set cookie for [%x:%x] "
638 "err=%lu\n", devhandle, devino, hv_err);
639 prom_halt();
640 }
641
642 return sun4v_build_common(sysino, &sun4v_virq);
643}
644
532#ifdef CONFIG_PCI_MSI 645#ifdef CONFIG_PCI_MSI
533unsigned int sun4v_build_msi(u32 devhandle, unsigned int *virt_irq_p, 646unsigned int sun4v_build_msi(u32 devhandle, unsigned int *virt_irq_p,
534 unsigned int msi_start, unsigned int msi_end) 647 unsigned int msi_start, unsigned int msi_end)