bool "Flattened Device Tree support"
        select OF
        select OF_EARLY_FLATTREE
+       select IRQ_DOMAIN
        help
          Include support for flattened device tree machine descriptions.
 
 
 #include <asm/setup.h>
 #include <asm/irq.h>
 
-static inline void irq_dispose_mapping(unsigned int virq)
-{
-       return;
-}
-
 extern struct machine_desc *setup_machine_fdt(unsigned int dt_phys);
 extern void arm_dt_memblock_reserve(void);
 
 
 
        return mdesc_best;
 }
-
-/**
- * irq_create_of_mapping - Hook to resolve OF irq specifier into a Linux irq#
- *
- * Currently the mapping mechanism is trivial; simple flat hwirq numbers are
- * mapped 1:1 onto Linux irq numbers.  Cascaded irq controllers are not
- * supported.
- */
-unsigned int irq_create_of_mapping(struct device_node *controller,
-                                  const u32 *intspec, unsigned int intsize)
-{
-       return intspec[0];
-}
-EXPORT_SYMBOL_GPL(irq_create_of_mapping);
 
 };
 
 struct msi_desc;
+struct irq_domain;
 
 /**
  * struct irq_data - per irq and irq chip data passed down to chip functions
  * @irq:               interrupt number
+ * @hwirq:             hardware interrupt number, local to the interrupt domain
  * @node:              node index useful for balancing
  * @state_use_accessors: status information for irq chip functions.
  *                     Use accessor functions to deal with it
  * @chip:              low level interrupt hardware access
+ * @domain:            Interrupt translation domain; responsible for mapping
+ *                     between hwirq number and linux irq number.
  * @handler_data:      per-IRQ data for the irq_chip methods
  * @chip_data:         platform-specific per-chip private data for the chip
  *                     methods, to allow shared chip implementations
  */
 struct irq_data {
        unsigned int            irq;
+       unsigned long           hwirq;
        unsigned int            node;
        unsigned int            state_use_accessors;
        struct irq_chip         *chip;
+       struct irq_domain       *domain;
        void                    *handler_data;
        void                    *chip_data;
        struct msi_desc         *msi_desc;
 
--- /dev/null
+/*
+ * irq_domain - IRQ translation domains
+ *
+ * Translation infrastructure between hw and linux irq numbers.  This is
+ * helpful for interrupt controllers to implement mapping between hardware
+ * irq numbers and the Linux irq number space.
+ *
+ * irq_domains also have a hook for translating device tree interrupt
+ * representation into a hardware irq number that can be mapped back to a
+ * Linux irq number without any extra platform support code.
+ *
+ * irq_domain is expected to be embedded in an interrupt controller's private
+ * data structure.
+ */
+#ifndef _LINUX_IRQDOMAIN_H
+#define _LINUX_IRQDOMAIN_H
+
+#include <linux/irq.h>
+
+#ifdef CONFIG_IRQ_DOMAIN
+struct device_node;
+struct irq_domain;
+
+/**
+ * struct irq_domain_ops - Methods for irq_domain objects
+ * @to_irq: (optional) given a local hardware irq number, return the linux
+ *          irq number.  If to_irq is not implemented, then the irq_domain
+ *          will use this translation: irq = (domain->irq_base + hwirq)
+ * @dt_translate: Given a device tree node and interrupt specifier, decode
+ *                the hardware irq number and linux irq type value.
+ */
+struct irq_domain_ops {
+       unsigned int (*to_irq)(struct irq_domain *d, unsigned long hwirq);
+
+#ifdef CONFIG_OF
+       int (*dt_translate)(struct irq_domain *d, struct device_node *node,
+                           const u32 *intspec, unsigned int intsize,
+                           unsigned long *out_hwirq, unsigned int *out_type);
+#endif /* CONFIG_OF */
+};
+
+/**
+ * struct irq_domain - Hardware interrupt number translation object
+ * @list: Element in global irq_domain list.
+ * @irq_base: Start of irq_desc range assigned to the irq_domain.  The creator
+ *            of the irq_domain is responsible for allocating the array of
+ *            irq_desc structures.
+ * @nr_irq: Number of irqs managed by the irq domain
+ * @ops: pointer to irq_domain methods
+ * @priv: private data pointer for use by owner.  Not touched by irq_domain
+ *        core code.
+ * @of_node: (optional) Pointer to device tree nodes associated with the
+ *           irq_domain.  Used when decoding device tree interrupt specifiers.
+ */
+struct irq_domain {
+       struct list_head list;
+       unsigned int irq_base;
+       unsigned int nr_irq;
+       const struct irq_domain_ops *ops;
+       void *priv;
+       struct device_node *of_node;
+};
+
+/**
+ * irq_domain_to_irq() - Translate from a hardware irq to a linux irq number
+ *
+ * Returns the linux irq number associated with a hardware irq.  By default,
+ * the mapping is irq == domain->irq_base + hwirq, but this mapping can
+ * be overridden if the irq_domain implements a .to_irq() hook.
+ */
+static inline unsigned int irq_domain_to_irq(struct irq_domain *d,
+                                            unsigned long hwirq)
+{
+       return d->ops->to_irq ? d->ops->to_irq(d, hwirq) : d->irq_base + hwirq;
+}
+
+extern void irq_domain_add(struct irq_domain *domain);
+extern void irq_domain_del(struct irq_domain *domain);
+#endif /* CONFIG_IRQ_DOMAIN */
+
+#endif /* _LINUX_IRQDOMAIN_H */
 
 extern unsigned int irq_create_of_mapping(struct device_node *controller,
                                          const u32 *intspec,
                                          unsigned int intsize);
+#ifdef CONFIG_IRQ_DOMAIN
+extern void irq_dispose_mapping(unsigned int irq);
+#endif
 extern int of_irq_to_resource(struct device_node *dev, int index,
                              struct resource *r);
 extern int of_irq_count(struct device_node *dev);
                struct resource *res, int nr_irqs);
 extern struct device_node *of_irq_find_parent(struct device_node *child);
 
+
 #endif /* CONFIG_OF_IRQ */
 #endif /* CONFIG_OF */
 #endif /* __OF_IRQ_H */
 
 config GENERIC_IRQ_CHIP
        bool
 
+# Generic irq_domain hw <--> linux irq number translation
+config IRQ_DOMAIN
+       bool
+
 # Support forced irq threading
 config IRQ_FORCED_THREADING
        bool
 
 obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o
 obj-$(CONFIG_GENERIC_IRQ_CHIP) += generic-chip.o
 obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o
+obj-$(CONFIG_IRQ_DOMAIN) += irqdomain.o
 obj-$(CONFIG_PROC_FS) += proc.o
 obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o
 obj-$(CONFIG_PM_SLEEP) += pm.o
 
--- /dev/null
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+
+static LIST_HEAD(irq_domain_list);
+static DEFINE_MUTEX(irq_domain_mutex);
+
+/**
+ * irq_domain_add() - Register an irq_domain
+ * @domain: ptr to initialized irq_domain structure
+ *
+ * Registers an irq_domain structure.  The irq_domain must at a minimum be
+ * initialized with an ops structure pointer, and either a ->to_irq hook or
+ * a valid irq_base value.  Everything else is optional.
+ */
+void irq_domain_add(struct irq_domain *domain)
+{
+       struct irq_data *d;
+       int hwirq;
+
+       /*
+        * This assumes that the irq_domain owner has already allocated
+        * the irq_descs.  This block will be removed when support for dynamic
+        * allocation of irq_descs is added to irq_domain.
+        */
+       for (hwirq = 0; hwirq < domain->nr_irq; hwirq++) {
+               d = irq_get_irq_data(irq_domain_to_irq(domain, hwirq));
+               if (d || d->domain) {
+                       /* things are broken; just report, don't clean up */
+                       WARN(1, "error: irq_desc already assigned to a domain");
+                       return;
+               }
+               d->domain = domain;
+               d->hwirq = hwirq;
+       }
+
+       mutex_lock(&irq_domain_mutex);
+       list_add(&domain->list, &irq_domain_list);
+       mutex_unlock(&irq_domain_mutex);
+}
+
+/**
+ * irq_domain_del() - Unregister an irq_domain
+ * @domain: ptr to registered irq_domain.
+ */
+void irq_domain_del(struct irq_domain *domain)
+{
+       struct irq_data *d;
+       int hwirq;
+
+       mutex_lock(&irq_domain_mutex);
+       list_del(&domain->list);
+       mutex_unlock(&irq_domain_mutex);
+
+       /* Clear the irq_domain assignments */
+       for (hwirq = 0; hwirq < domain->nr_irq; hwirq++) {
+               d = irq_get_irq_data(irq_domain_to_irq(domain, hwirq));
+               d->domain = NULL;
+       }
+}
+
+#if defined(CONFIG_OF_IRQ)
+/**
+ * irq_create_of_mapping() - Map a linux irq number from a DT interrupt spec
+ *
+ * Used by the device tree interrupt mapping code to translate a device tree
+ * interrupt specifier to a valid linux irq number.  Returns either a valid
+ * linux IRQ number or 0.
+ *
+ * When the caller no longer need the irq number returned by this function it
+ * should arrange to call irq_dispose_mapping().
+ */
+unsigned int irq_create_of_mapping(struct device_node *controller,
+                                  const u32 *intspec, unsigned int intsize)
+{
+       struct irq_domain *domain;
+       unsigned long hwirq;
+       unsigned int irq, type;
+       int rc = -EINVAL;
+
+       /* Find a domain which can translate the irq spec */
+       mutex_lock(&irq_domain_mutex);
+       list_for_each_entry(domain, &irq_domain_list, list) {
+               if (!domain->ops->dt_translate)
+                       continue;
+               rc = domain->ops->dt_translate(domain, controller,
+                                       intspec, intsize, &hwirq, &type);
+               if (rc == 0)
+                       break;
+       }
+       mutex_unlock(&irq_domain_mutex);
+
+       if (rc != 0)
+               return 0;
+
+       irq = irq_domain_to_irq(domain, hwirq);
+       if (type != IRQ_TYPE_NONE)
+               irq_set_irq_type(irq, type);
+       pr_debug("%s: mapped hwirq=%i to irq=%i, flags=%x\n",
+                controller->full_name, (int)hwirq, irq, type);
+       return irq;
+}
+EXPORT_SYMBOL_GPL(irq_create_of_mapping);
+
+/**
+ * irq_dispose_mapping() - Discard a mapping created by irq_create_of_mapping()
+ * @irq: linux irq number to be discarded
+ *
+ * Calling this function indicates the caller no longer needs a reference to
+ * the linux irq number returned by a prior call to irq_create_of_mapping().
+ */
+void irq_dispose_mapping(unsigned int irq)
+{
+       /*
+        * nothing yet; will be filled when support for dynamic allocation of
+        * irq_descs is added to irq_domain
+        */
+}
+EXPORT_SYMBOL_GPL(irq_dispose_mapping);
+#endif /* CONFIG_OF_IRQ */