aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMagnus Damm <damm@igel.co.jp>2009-02-24 08:58:57 -0500
committerPaul Mundt <lethal@linux-sh.org>2009-02-27 02:53:50 -0500
commitbdaa6e8062d7f8085d8ed94ff88c99406ad53d79 (patch)
treec68310adbcea90c5c8bdb4b4b7c6517c40ecb0de
parent3e91faec47e9e12b965c952d698b0bb64847af06 (diff)
sh: multiple vectors per irq - base
Instead of keeping the single vector -> single linux irq mapping we extend the intc code to support merging of vectors to a single linux irq. This helps processors such as sh7750, sh7780 and sh7785 which have more vectors than masking ability. With this patch in place we can modify the intc tables to use one irq per maskable irq source. Please note the following: - If multiple vectors share the same enum then only the first vector will be available as a linux irq. - Drivers may need to be rewritten to get pending irq source from the hardware block instead of irq number. This patch together with the sh7785 specific intc tables solves DMA controller irq issues related to buggy interrupt masking. Reported-by: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com> Signed-off-by: Magnus Damm <damm@igel.co.jp> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-rw-r--r--arch/sh/kernel/irq.c2
-rw-r--r--drivers/sh/intc.c47
-rw-r--r--include/linux/sh_intc.h1
3 files changed, 49 insertions, 1 deletions
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index 64b7690c664c..90d63aefd275 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -106,7 +106,7 @@ asmlinkage int do_IRQ(unsigned int irq, struct pt_regs *regs)
106 } 106 }
107#endif 107#endif
108 108
109 irq = irq_demux(evt2irq(irq)); 109 irq = irq_demux(intc_evt2irq(irq));
110 110
111#ifdef CONFIG_IRQSTACKS 111#ifdef CONFIG_IRQSTACKS
112 curctx = (union irq_ctx *)current_thread_info(); 112 curctx = (union irq_ctx *)current_thread_info();
diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c
index 58d24c5a76ce..d7b8959d9d92 100644
--- a/drivers/sh/intc.c
+++ b/drivers/sh/intc.c
@@ -568,6 +568,10 @@ static void __init intc_register_irq(struct intc_desc *desc,
568 if (!data[0] && data[1]) 568 if (!data[0] && data[1])
569 primary = 1; 569 primary = 1;
570 570
571 if (!data[0] && !data[1])
572 pr_warning("intc: missing unique irq mask for 0x%04x\n",
573 irq2evt(irq));
574
571 data[0] = data[0] ? data[0] : intc_mask_data(desc, d, enum_id, 1); 575 data[0] = data[0] ? data[0] : intc_mask_data(desc, d, enum_id, 1);
572 data[1] = data[1] ? data[1] : intc_prio_data(desc, d, enum_id, 1); 576 data[1] = data[1] ? data[1] : intc_prio_data(desc, d, enum_id, 1);
573 577
@@ -641,6 +645,17 @@ static unsigned int __init save_reg(struct intc_desc_int *d,
641 return 0; 645 return 0;
642} 646}
643 647
648static unsigned char *intc_evt2irq_table;
649
650unsigned int intc_evt2irq(unsigned int vector)
651{
652 unsigned int irq = evt2irq(vector);
653
654 if (intc_evt2irq_table && intc_evt2irq_table[irq])
655 irq = intc_evt2irq_table[irq];
656
657 return irq;
658}
644 659
645void __init register_intc_controller(struct intc_desc *desc) 660void __init register_intc_controller(struct intc_desc *desc)
646{ 661{
@@ -705,9 +720,41 @@ void __init register_intc_controller(struct intc_desc *desc)
705 720
706 BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */ 721 BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */
707 722
723 /* keep the first vector only if same enum is used multiple times */
724 for (i = 0; i < desc->nr_vectors; i++) {
725 struct intc_vect *vect = desc->vectors + i;
726 int first_irq = evt2irq(vect->vect);
727
728 if (!vect->enum_id)
729 continue;
730
731 for (k = i + 1; k < desc->nr_vectors; k++) {
732 struct intc_vect *vect2 = desc->vectors + k;
733
734 if (vect->enum_id != vect2->enum_id)
735 continue;
736
737 vect2->enum_id = 0;
738
739 if (!intc_evt2irq_table)
740 intc_evt2irq_table = alloc_bootmem(NR_IRQS);
741
742 if (!intc_evt2irq_table) {
743 pr_warning("intc: cannot allocate evt2irq!\n");
744 continue;
745 }
746
747 intc_evt2irq_table[evt2irq(vect2->vect)] = first_irq;
748 }
749 }
750
751 /* register the vectors one by one */
708 for (i = 0; i < desc->nr_vectors; i++) { 752 for (i = 0; i < desc->nr_vectors; i++) {
709 struct intc_vect *vect = desc->vectors + i; 753 struct intc_vect *vect = desc->vectors + i;
710 754
755 if (!vect->enum_id)
756 continue;
757
711 intc_register_irq(desc, d, vect->enum_id, evt2irq(vect->vect)); 758 intc_register_irq(desc, d, vect->enum_id, evt2irq(vect->vect));
712 } 759 }
713} 760}
diff --git a/include/linux/sh_intc.h b/include/linux/sh_intc.h
index 68e212ff9dde..eb1423a0078d 100644
--- a/include/linux/sh_intc.h
+++ b/include/linux/sh_intc.h
@@ -85,6 +85,7 @@ struct intc_desc symbol __initdata = { \
85} 85}
86#endif 86#endif
87 87
88unsigned int intc_evt2irq(unsigned int vector);
88void __init register_intc_controller(struct intc_desc *desc); 89void __init register_intc_controller(struct intc_desc *desc);
89int intc_set_priority(unsigned int irq, unsigned int prio); 90int intc_set_priority(unsigned int irq, unsigned int prio);
90 91