diff options
Diffstat (limited to 'arch/sparc64/kernel/irq.c')
-rw-r--r-- | arch/sparc64/kernel/irq.c | 131 |
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 | ||
383 | static 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 | |||
411 | static 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 | |||
432 | static 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 | |||
383 | static void run_pre_handler(unsigned int virt_irq) | 453 | static 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 | ||
507 | static 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 | |||
514 | static 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 | |||
437 | void irq_install_pre_handler(int virt_irq, | 522 | void 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 | ||
495 | unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino) | 583 | static 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 | ||
619 | unsigned 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 | |||
626 | unsigned 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 |
533 | unsigned int sun4v_build_msi(u32 devhandle, unsigned int *virt_irq_p, | 646 | unsigned 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) |