]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
sh: multiple vectors per irq - base
authorMagnus Damm <damm@igel.co.jp>
Tue, 24 Feb 2009 13:58:57 +0000 (22:58 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Fri, 27 Feb 2009 07:53:50 +0000 (16:53 +0900)
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>
arch/sh/kernel/irq.c
drivers/sh/intc.c
include/linux/sh_intc.h

index 64b7690c664cb9ac1cabe09c30dfee042451a3b1..90d63aefd2755907d66932d42e4ac30629d277b5 100644 (file)
@@ -106,7 +106,7 @@ asmlinkage int do_IRQ(unsigned int irq, struct pt_regs *regs)
        }
 #endif
 
-       irq = irq_demux(evt2irq(irq));
+       irq = irq_demux(intc_evt2irq(irq));
 
 #ifdef CONFIG_IRQSTACKS
        curctx = (union irq_ctx *)current_thread_info();
index 58d24c5a76cea5732d9a8b13cca5294dc95700a0..d7b8959d9d9235180c91e5be1a932f6159c0870a 100644 (file)
@@ -568,6 +568,10 @@ static void __init intc_register_irq(struct intc_desc *desc,
        if (!data[0] && data[1])
                primary = 1;
 
+       if (!data[0] && !data[1])
+               pr_warning("intc: missing unique irq mask for 0x%04x\n",
+                          irq2evt(irq));
+
        data[0] = data[0] ? data[0] : intc_mask_data(desc, d, enum_id, 1);
        data[1] = data[1] ? data[1] : intc_prio_data(desc, d, enum_id, 1);
 
@@ -641,6 +645,17 @@ static unsigned int __init save_reg(struct intc_desc_int *d,
        return 0;
 }
 
+static unsigned char *intc_evt2irq_table;
+
+unsigned int intc_evt2irq(unsigned int vector)
+{
+       unsigned int irq = evt2irq(vector);
+
+       if (intc_evt2irq_table && intc_evt2irq_table[irq])
+               irq = intc_evt2irq_table[irq];
+
+       return irq;
+}
 
 void __init register_intc_controller(struct intc_desc *desc)
 {
@@ -705,9 +720,41 @@ void __init register_intc_controller(struct intc_desc *desc)
 
        BUG_ON(k > 256); /* _INTC_ADDR_E() and _INTC_ADDR_D() are 8 bits */
 
+       /* keep the first vector only if same enum is used multiple times */
+       for (i = 0; i < desc->nr_vectors; i++) {
+               struct intc_vect *vect = desc->vectors + i;
+               int first_irq = evt2irq(vect->vect);
+
+               if (!vect->enum_id)
+                       continue;
+
+               for (k = i + 1; k < desc->nr_vectors; k++) {
+                       struct intc_vect *vect2 = desc->vectors + k;
+
+                       if (vect->enum_id != vect2->enum_id)
+                               continue;
+
+                       vect2->enum_id = 0;
+
+                       if (!intc_evt2irq_table)
+                               intc_evt2irq_table = alloc_bootmem(NR_IRQS);
+
+                       if (!intc_evt2irq_table) {
+                               pr_warning("intc: cannot allocate evt2irq!\n");
+                               continue;
+                       }
+
+                       intc_evt2irq_table[evt2irq(vect2->vect)] = first_irq;
+               }
+       }
+
+       /* register the vectors one by one */
        for (i = 0; i < desc->nr_vectors; i++) {
                struct intc_vect *vect = desc->vectors + i;
 
+               if (!vect->enum_id)
+                       continue;
+
                intc_register_irq(desc, d, vect->enum_id, evt2irq(vect->vect));
        }
 }
index 68e212ff9dde57aa9141076881cd15b8302b5a4a..eb1423a0078d45f340af21ab325d8a93d9916139 100644 (file)
@@ -85,6 +85,7 @@ struct intc_desc symbol __initdata = {                                        \
 }
 #endif
 
+unsigned int intc_evt2irq(unsigned int vector);
 void __init register_intc_controller(struct intc_desc *desc);
 int intc_set_priority(unsigned int irq, unsigned int prio);