irq_domain/microblaze: Convert microblaze to use irq_domains
authorGrant Likely <grant.likely@secretlab.ca>
Thu, 26 Jan 2012 21:10:13 +0000 (14:10 -0700)
committerGrant Likely <grant.likely@secretlab.ca>
Thu, 16 Feb 2012 13:11:24 +0000 (06:11 -0700)
This patch converts Microblaze to use the irq_domain remapper and get
away from hard coding the offset between hwirq number and the linux irq
number space.  This also paves the way for multiple interrupt controllers.

v2: Don't enable SPARSE_IRQ and keep NR_IRQS set to 33

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Michal Simek <monstr@monstr.eu>
Cc: Rob Herring <rob.herring@calxeda.com>
Cc: John Williams <john.williams@petalogix.com>
Cc: John Linn <john.linn@xilinx.com>
arch/microblaze/Kconfig
arch/microblaze/include/asm/hardirq.h
arch/microblaze/include/asm/irq.h
arch/microblaze/kernel/intc.c
arch/microblaze/kernel/irq.c

index c8d6efb99dbf668b7f283f23624c2f50f632c442..11060fa87da35c304df036bfe968fe66556851cd 100644 (file)
@@ -14,6 +14,7 @@ config MICROBLAZE
        select TRACING_SUPPORT
        select OF
        select OF_EARLY_FLATTREE
+       select IRQ_DOMAIN
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
index cd1ac9aad56c443598725e0e19d07fa3c7f038db..fb3c05a0cbbf11e48551550270d354b0e0eb7dc1 100644 (file)
@@ -1,17 +1 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#ifndef _ASM_MICROBLAZE_HARDIRQ_H
-#define _ASM_MICROBLAZE_HARDIRQ_H
-
-/* should be defined in each interrupt controller driver */
-extern unsigned int get_irq(struct pt_regs *regs);
-
 #include <asm-generic/hardirq.h>
-
-#endif /* _ASM_MICROBLAZE_HARDIRQ_H */
index 7798ad14c6105b49b78abb1cf57a07e50cea8ff0..bab3b1393ad4306b61c6a8a3ba766ee847b1bb8e 100644 (file)
@@ -9,49 +9,13 @@
 #ifndef _ASM_MICROBLAZE_IRQ_H
 #define _ASM_MICROBLAZE_IRQ_H
 
-
-/*
- * Linux IRQ# is currently offset by one to map to the hardware
- * irq number. So hardware IRQ0 maps to Linux irq 1.
- */
-#define NO_IRQ_OFFSET  1
-#define IRQ_OFFSET     NO_IRQ_OFFSET
-#define NR_IRQS                (32 + IRQ_OFFSET)
+#define NR_IRQS                (32 + 1)
 #include <asm-generic/irq.h>
 
-/* This type is the placeholder for a hardware interrupt number. It has to
- * be big enough to enclose whatever representation is used by a given
- * platform.
- */
-typedef unsigned long irq_hw_number_t;
-
-extern unsigned int nr_irq;
-
 struct pt_regs;
 extern void do_IRQ(struct pt_regs *regs);
 
-/** FIXME - not implement
- * irq_dispose_mapping - Unmap an interrupt
- * @virq: linux virq number of the interrupt to unmap
- */
-static inline void irq_dispose_mapping(unsigned int virq)
-{
-       return;
-}
-
-struct irq_domain;
-
-/**
- * irq_create_mapping - Map a hardware interrupt into linux virq space
- * @host: host owning this hardware interrupt or NULL for default host
- * @hwirq: hardware irq number in that host space
- *
- * Only one mapping per hardware interrupt is permitted. Returns a linux
- * virq number.
- * If the sense/trigger is to be specified, set_irq_type() should be called
- * on the number returned from that call.
- */
-extern unsigned int irq_create_mapping(struct irq_domain *host,
-                                       irq_hw_number_t hwirq);
+/* should be defined in each interrupt controller driver */
+extern unsigned int get_irq(void);
 
 #endif /* _ASM_MICROBLAZE_IRQ_H */
index 44b177e2ab124c7338c04eeafb81814bf63177c0..ad120672cee5779eaf91e1f6fb48ff89ca44e3a4 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/irqdomain.h>
 #include <linux/irq.h>
 #include <asm/page.h>
 #include <linux/io.h>
@@ -25,8 +26,6 @@ static unsigned int intc_baseaddr;
 #define INTC_BASE      intc_baseaddr
 #endif
 
-unsigned int nr_irq;
-
 /* No one else should require these constants, so define them locally here. */
 #define ISR 0x00                       /* Interrupt Status Register */
 #define IPR 0x04                       /* Interrupt Pending Register */
@@ -84,24 +83,45 @@ static struct irq_chip intc_dev = {
        .irq_mask_ack = intc_mask_ack,
 };
 
-unsigned int get_irq(struct pt_regs *regs)
+static struct irq_domain *root_domain;
+
+unsigned int get_irq(void)
 {
-       int irq;
+       unsigned int hwirq, irq = -1;
 
-       /*
-        * NOTE: This function is the one that needs to be improved in
-        * order to handle multiple interrupt controllers. It currently
-        * is hardcoded to check for interrupts only on the first INTC.
-        */
-       irq = in_be32(INTC_BASE + IVR) + NO_IRQ_OFFSET;
-       pr_debug("get_irq: %d\n", irq);
+       hwirq = in_be32(INTC_BASE + IVR);
+       if (hwirq != -1U)
+               irq = irq_find_mapping(root_domain, hwirq);
+
+       pr_debug("get_irq: hwirq=%d, irq=%d\n", hwirq, irq);
 
        return irq;
 }
 
+int xintc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
+{
+       u32 intr_mask = (u32)d->host_data;
+
+       if (intr_mask & (1 << hw)) {
+               irq_set_chip_and_handler_name(irq, &intc_dev,
+                                               handle_edge_irq, "edge");
+               irq_clear_status_flags(irq, IRQ_LEVEL);
+       } else {
+               irq_set_chip_and_handler_name(irq, &intc_dev,
+                                               handle_level_irq, "level");
+               irq_set_status_flags(irq, IRQ_LEVEL);
+       }
+       return 0;
+}
+
+static const struct irq_domain_ops xintc_irq_domain_ops = {
+       .xlate = irq_domain_xlate_onetwocell,
+       .map = xintc_map,
+};
+
 void __init init_IRQ(void)
 {
-       u32 i, intr_mask;
+       u32 nr_irq, intr_mask;
        struct device_node *intc = NULL;
 #ifdef CONFIG_SELFMOD_INTC
        unsigned int intc_baseaddr = 0;
@@ -146,16 +166,9 @@ void __init init_IRQ(void)
        /* Turn on the Master Enable. */
        out_be32(intc_baseaddr + MER, MER_HIE | MER_ME);
 
-       for (i = IRQ_OFFSET; i < (nr_irq + IRQ_OFFSET); ++i) {
-               if (intr_mask & (0x00000001 << (i - IRQ_OFFSET))) {
-                       irq_set_chip_and_handler_name(i, &intc_dev,
-                               handle_edge_irq, "edge");
-                       irq_clear_status_flags(i, IRQ_LEVEL);
-               } else {
-                       irq_set_chip_and_handler_name(i, &intc_dev,
-                               handle_level_irq, "level");
-                       irq_set_status_flags(i, IRQ_LEVEL);
-               }
-               irq_get_irq_data(i)->hwirq = i - IRQ_OFFSET;
-       }
+       /* Yeah, okay, casting the intr_mask to a void* is butt-ugly, but I'm
+        * lazy and Michal can clean it up to something nicer when he tests
+        * and commits this patch.  ~~gcl */
+       root_domain = irq_domain_add_linear(intc, nr_irq, &xintc_irq_domain_ops,
+                                                       (void *)intr_mask);
 }
index 3f613dfe5a0752afd7406285b3e6a711d5943de5..ace700afbfdf01350065662020c7a94622717781 100644 (file)
@@ -31,14 +31,13 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
        trace_hardirqs_off();
 
        irq_enter();
-       irq = get_irq(regs);
+       irq = get_irq();
 next_irq:
        BUG_ON(!irq);
-       /* Substract 1 because of get_irq */
-       generic_handle_irq(irq + IRQ_OFFSET - NO_IRQ_OFFSET);
+       generic_handle_irq(irq);
 
-       irq = get_irq(regs);
-       if (irq) {
+       irq = get_irq();
+       if (irq != -1U) {
                pr_debug("next irq: %d\n", irq);
                ++concurrent_irq;
                goto next_irq;
@@ -48,18 +47,3 @@ next_irq:
        set_irq_regs(old_regs);
        trace_hardirqs_on();
 }
-
-/* MS: There is no any advance mapping mechanism. We are using simple 32bit
-  intc without any cascades or any connection that's why mapping is 1:1 */
-unsigned int irq_create_mapping(struct irq_domain *host, irq_hw_number_t hwirq)
-{
-       return hwirq + IRQ_OFFSET;
-}
-EXPORT_SYMBOL_GPL(irq_create_mapping);
-
-unsigned int irq_create_of_mapping(struct device_node *controller,
-                                  const u32 *intspec, unsigned int intsize)
-{
-       return intspec[0] + IRQ_OFFSET;
-}
-EXPORT_SYMBOL_GPL(irq_create_of_mapping);