irq: support domains with non-zero hwirq base
authorRob Herring <rob.herring@calxeda.com>
Fri, 30 Sep 2011 15:48:38 +0000 (10:48 -0500)
committerArnd Bergmann <arnd@arndb.de>
Mon, 31 Oct 2011 13:03:23 +0000 (14:03 +0100)
Interrupt controllers can have non-zero starting value for h/w irq numbers.
Adding support in irq_domain allows the domain hwirq numbering to match
the interrupt controllers' numbering.

As this makes looping over irqs for a domain more complicated, add loop
iterators to iterate over all hwirqs and irqs for a domain.

Signed-off-by: Rob Herring <rob.herring@calxeda.com>
Reviewed-by: Jamie Iles <jamie@jamieiles.com>
Tested-by: Thomas Abraham <thomas.abraham@linaro.org>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
include/linux/irqdomain.h
kernel/irq/irqdomain.c

index 3ad553e8eae20c207ec1ae52c7e21e0178920d01..99834e581b9e6fc2b1772d83b7556d354a414e0f 100644 (file)
@@ -47,6 +47,7 @@ struct irq_domain_ops {
  *            of the irq_domain is responsible for allocating the array of
  *            irq_desc structures.
  * @nr_irq: Number of irqs managed by the irq domain
+ * @hwirq_base: Starting number for hwirqs 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.
@@ -57,6 +58,7 @@ struct irq_domain {
        struct list_head list;
        unsigned int irq_base;
        unsigned int nr_irq;
+       unsigned int hwirq_base;
        const struct irq_domain_ops *ops;
        void *priv;
        struct device_node *of_node;
@@ -72,9 +74,21 @@ struct irq_domain {
 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;
+       if (d->ops->to_irq)
+               return d->ops->to_irq(d, hwirq);
+       if (WARN_ON(hwirq < d->hwirq_base))
+               return 0;
+       return d->irq_base + hwirq - d->hwirq_base;
 }
 
+#define irq_domain_for_each_hwirq(d, hw) \
+       for (hw = d->hwirq_base; hw < d->hwirq_base + d->nr_irq; hw++)
+
+#define irq_domain_for_each_irq(d, hw, irq) \
+       for (hw = d->hwirq_base, irq = irq_domain_to_irq(d, hw); \
+            hw < d->hwirq_base + d->nr_irq; \
+            hw++, irq = irq_domain_to_irq(d, hw))
+
 extern void irq_domain_add(struct irq_domain *domain);
 extern void irq_domain_del(struct irq_domain *domain);
 #endif /* CONFIG_IRQ_DOMAIN */
index b57a3776de44dd833eb9a545dced819d69e5fa51..200ce832c58543785f62f3c4b6e4d80dcddc80f1 100644 (file)
@@ -20,15 +20,15 @@ static DEFINE_MUTEX(irq_domain_mutex);
 void irq_domain_add(struct irq_domain *domain)
 {
        struct irq_data *d;
-       int hwirq;
+       int hwirq, irq;
 
        /*
         * 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));
+       irq_domain_for_each_irq(domain, hwirq, irq) {
+               d = irq_get_irq_data(irq);
                if (!d) {
                        WARN(1, "error: assigning domain to non existant irq_desc");
                        return;
@@ -54,15 +54,15 @@ void irq_domain_add(struct irq_domain *domain)
 void irq_domain_del(struct irq_domain *domain)
 {
        struct irq_data *d;
-       int hwirq;
+       int hwirq, irq;
 
        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));
+       irq_domain_for_each_irq(domain, hwirq, irq) {
+               d = irq_get_irq_data(irq);
                d->domain = NULL;
        }
 }