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.c85
1 files changed, 38 insertions, 47 deletions
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index 2c3bea228159..30431bd24e1e 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -257,8 +257,8 @@ struct irq_handler_data {
257 unsigned long imap; 257 unsigned long imap;
258 258
259 void (*pre_handler)(unsigned int, void *, void *); 259 void (*pre_handler)(unsigned int, void *, void *);
260 void *pre_handler_arg1; 260 void *arg1;
261 void *pre_handler_arg2; 261 void *arg2;
262}; 262};
263 263
264#ifdef CONFIG_SMP 264#ifdef CONFIG_SMP
@@ -346,7 +346,7 @@ static void sun4u_irq_disable(unsigned int virt_irq)
346 } 346 }
347} 347}
348 348
349static void sun4u_irq_end(unsigned int virt_irq) 349static void sun4u_irq_eoi(unsigned int virt_irq)
350{ 350{
351 struct irq_handler_data *data = get_irq_chip_data(virt_irq); 351 struct irq_handler_data *data = get_irq_chip_data(virt_irq);
352 struct irq_desc *desc = irq_desc + virt_irq; 352 struct irq_desc *desc = irq_desc + virt_irq;
@@ -401,7 +401,7 @@ static void sun4v_irq_disable(unsigned int virt_irq)
401 "err(%d)\n", ino, err); 401 "err(%d)\n", ino, err);
402} 402}
403 403
404static void sun4v_irq_end(unsigned int virt_irq) 404static void sun4v_irq_eoi(unsigned int virt_irq)
405{ 405{
406 unsigned int ino = virt_irq_table[virt_irq].dev_ino; 406 unsigned int ino = virt_irq_table[virt_irq].dev_ino;
407 struct irq_desc *desc = irq_desc + virt_irq; 407 struct irq_desc *desc = irq_desc + virt_irq;
@@ -478,7 +478,7 @@ static void sun4v_virq_disable(unsigned int virt_irq)
478 dev_handle, dev_ino, err); 478 dev_handle, dev_ino, err);
479} 479}
480 480
481static void sun4v_virq_end(unsigned int virt_irq) 481static void sun4v_virq_eoi(unsigned int virt_irq)
482{ 482{
483 struct irq_desc *desc = irq_desc + virt_irq; 483 struct irq_desc *desc = irq_desc + virt_irq;
484 unsigned long dev_handle, dev_ino; 484 unsigned long dev_handle, dev_ino;
@@ -498,33 +498,11 @@ static void sun4v_virq_end(unsigned int virt_irq)
498 dev_handle, dev_ino, err); 498 dev_handle, dev_ino, err);
499} 499}
500 500
501static void run_pre_handler(unsigned int virt_irq)
502{
503 struct irq_handler_data *data = get_irq_chip_data(virt_irq);
504 unsigned int ino;
505
506 ino = virt_irq_table[virt_irq].dev_ino;
507 if (likely(data->pre_handler)) {
508 data->pre_handler(ino,
509 data->pre_handler_arg1,
510 data->pre_handler_arg2);
511 }
512}
513
514static struct irq_chip sun4u_irq = { 501static struct irq_chip sun4u_irq = {
515 .typename = "sun4u", 502 .typename = "sun4u",
516 .enable = sun4u_irq_enable, 503 .enable = sun4u_irq_enable,
517 .disable = sun4u_irq_disable, 504 .disable = sun4u_irq_disable,
518 .end = sun4u_irq_end, 505 .eoi = sun4u_irq_eoi,
519 .set_affinity = sun4u_set_affinity,
520};
521
522static struct irq_chip sun4u_irq_ack = {
523 .typename = "sun4u+ack",
524 .enable = sun4u_irq_enable,
525 .disable = sun4u_irq_disable,
526 .ack = run_pre_handler,
527 .end = sun4u_irq_end,
528 .set_affinity = sun4u_set_affinity, 506 .set_affinity = sun4u_set_affinity,
529}; 507};
530 508
@@ -532,7 +510,7 @@ static struct irq_chip sun4v_irq = {
532 .typename = "sun4v", 510 .typename = "sun4v",
533 .enable = sun4v_irq_enable, 511 .enable = sun4v_irq_enable,
534 .disable = sun4v_irq_disable, 512 .disable = sun4v_irq_disable,
535 .end = sun4v_irq_end, 513 .eoi = sun4v_irq_eoi,
536 .set_affinity = sun4v_set_affinity, 514 .set_affinity = sun4v_set_affinity,
537}; 515};
538 516
@@ -540,31 +518,33 @@ static struct irq_chip sun4v_virq = {
540 .typename = "vsun4v", 518 .typename = "vsun4v",
541 .enable = sun4v_virq_enable, 519 .enable = sun4v_virq_enable,
542 .disable = sun4v_virq_disable, 520 .disable = sun4v_virq_disable,
543 .end = sun4v_virq_end, 521 .eoi = sun4v_virq_eoi,
544 .set_affinity = sun4v_virt_set_affinity, 522 .set_affinity = sun4v_virt_set_affinity,
545}; 523};
546 524
525static void fastcall pre_flow_handler(unsigned int virt_irq,
526 struct irq_desc *desc)
527{
528 struct irq_handler_data *data = get_irq_chip_data(virt_irq);
529 unsigned int ino = virt_irq_table[virt_irq].dev_ino;
530
531 data->pre_handler(ino, data->arg1, data->arg2);
532
533 handle_fasteoi_irq(virt_irq, desc);
534}
535
547void irq_install_pre_handler(int virt_irq, 536void irq_install_pre_handler(int virt_irq,
548 void (*func)(unsigned int, void *, void *), 537 void (*func)(unsigned int, void *, void *),
549 void *arg1, void *arg2) 538 void *arg1, void *arg2)
550{ 539{
551 struct irq_handler_data *data = get_irq_chip_data(virt_irq); 540 struct irq_handler_data *data = get_irq_chip_data(virt_irq);
552 struct irq_chip *chip = get_irq_chip(virt_irq); 541 struct irq_desc *desc = irq_desc + virt_irq;
553
554 if (WARN_ON(chip == &sun4v_irq || chip == &sun4v_virq)) {
555 printk(KERN_ERR "IRQ: Trying to install pre-handler on "
556 "sun4v irq %u\n", virt_irq);
557 return;
558 }
559 542
560 data->pre_handler = func; 543 data->pre_handler = func;
561 data->pre_handler_arg1 = arg1; 544 data->arg1 = arg1;
562 data->pre_handler_arg2 = arg2; 545 data->arg2 = arg2;
563
564 if (chip == &sun4u_irq_ack)
565 return;
566 546
567 set_irq_chip(virt_irq, &sun4u_irq_ack); 547 desc->handle_irq = pre_flow_handler;
568} 548}
569 549
570unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap) 550unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
@@ -582,7 +562,10 @@ unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
582 if (!virt_irq) { 562 if (!virt_irq) {
583 virt_irq = virt_irq_alloc(0, ino); 563 virt_irq = virt_irq_alloc(0, ino);
584 bucket_set_virt_irq(__pa(bucket), virt_irq); 564 bucket_set_virt_irq(__pa(bucket), virt_irq);
585 set_irq_chip(virt_irq, &sun4u_irq); 565 set_irq_chip_and_handler_name(virt_irq,
566 &sun4u_irq,
567 handle_fasteoi_irq,
568 "IVEC");
586 } 569 }
587 570
588 data = get_irq_chip_data(virt_irq); 571 data = get_irq_chip_data(virt_irq);
@@ -617,7 +600,9 @@ static unsigned int sun4v_build_common(unsigned long sysino,
617 if (!virt_irq) { 600 if (!virt_irq) {
618 virt_irq = virt_irq_alloc(0, sysino); 601 virt_irq = virt_irq_alloc(0, sysino);
619 bucket_set_virt_irq(__pa(bucket), virt_irq); 602 bucket_set_virt_irq(__pa(bucket), virt_irq);
620 set_irq_chip(virt_irq, chip); 603 set_irq_chip_and_handler_name(virt_irq, chip,
604 handle_fasteoi_irq,
605 "IVEC");
621 } 606 }
622 607
623 data = get_irq_chip_data(virt_irq); 608 data = get_irq_chip_data(virt_irq);
@@ -665,7 +650,10 @@ unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
665 650
666 virt_irq = virt_irq_alloc(devhandle, devino); 651 virt_irq = virt_irq_alloc(devhandle, devino);
667 bucket_set_virt_irq(__pa(bucket), virt_irq); 652 bucket_set_virt_irq(__pa(bucket), virt_irq);
668 set_irq_chip(virt_irq, &sun4v_virq); 653
654 set_irq_chip_and_handler_name(virt_irq, &sun4v_virq,
655 handle_fasteoi_irq,
656 "IVEC");
669 657
670 data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC); 658 data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
671 if (unlikely(!data)) 659 if (unlikely(!data))
@@ -724,6 +712,7 @@ void handler_irq(int irq, struct pt_regs *regs)
724 : "memory"); 712 : "memory");
725 713
726 while (bucket_pa) { 714 while (bucket_pa) {
715 struct irq_desc *desc;
727 unsigned long next_pa; 716 unsigned long next_pa;
728 unsigned int virt_irq; 717 unsigned int virt_irq;
729 718
@@ -731,7 +720,9 @@ void handler_irq(int irq, struct pt_regs *regs)
731 virt_irq = bucket_get_virt_irq(bucket_pa); 720 virt_irq = bucket_get_virt_irq(bucket_pa);
732 bucket_clear_chain_pa(bucket_pa); 721 bucket_clear_chain_pa(bucket_pa);
733 722
734 __do_IRQ(virt_irq); 723 desc = irq_desc + virt_irq;
724
725 desc->handle_irq(virt_irq, desc);
735 726
736 bucket_pa = next_pa; 727 bucket_pa = next_pa;
737 } 728 }