diff options
author | Rob Herring <rob.herring@calxeda.com> | 2011-09-30 11:48:38 -0400 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2011-10-31 09:03:23 -0400 |
commit | 6d274309d0e64bdbdb6c50945ca2964596e8fa5a (patch) | |
tree | 4b4c40a0a75b3e261f08e1525b5cc0e0bd781676 | |
parent | c71a54b0820179e53483d5220cdef1a0df8d5bd1 (diff) |
irq: support domains with non-zero hwirq base
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>
-rw-r--r-- | include/linux/irqdomain.h | 16 | ||||
-rw-r--r-- | kernel/irq/irqdomain.c | 12 |
2 files changed, 21 insertions, 7 deletions
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 3ad553e8eae2..99834e581b9e 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h | |||
@@ -47,6 +47,7 @@ struct irq_domain_ops { | |||
47 | * of the irq_domain is responsible for allocating the array of | 47 | * of the irq_domain is responsible for allocating the array of |
48 | * irq_desc structures. | 48 | * irq_desc structures. |
49 | * @nr_irq: Number of irqs managed by the irq domain | 49 | * @nr_irq: Number of irqs managed by the irq domain |
50 | * @hwirq_base: Starting number for hwirqs managed by the irq domain | ||
50 | * @ops: pointer to irq_domain methods | 51 | * @ops: pointer to irq_domain methods |
51 | * @priv: private data pointer for use by owner. Not touched by irq_domain | 52 | * @priv: private data pointer for use by owner. Not touched by irq_domain |
52 | * core code. | 53 | * core code. |
@@ -57,6 +58,7 @@ struct irq_domain { | |||
57 | struct list_head list; | 58 | struct list_head list; |
58 | unsigned int irq_base; | 59 | unsigned int irq_base; |
59 | unsigned int nr_irq; | 60 | unsigned int nr_irq; |
61 | unsigned int hwirq_base; | ||
60 | const struct irq_domain_ops *ops; | 62 | const struct irq_domain_ops *ops; |
61 | void *priv; | 63 | void *priv; |
62 | struct device_node *of_node; | 64 | struct device_node *of_node; |
@@ -72,9 +74,21 @@ struct irq_domain { | |||
72 | static inline unsigned int irq_domain_to_irq(struct irq_domain *d, | 74 | static inline unsigned int irq_domain_to_irq(struct irq_domain *d, |
73 | unsigned long hwirq) | 75 | unsigned long hwirq) |
74 | { | 76 | { |
75 | return d->ops->to_irq ? d->ops->to_irq(d, hwirq) : d->irq_base + hwirq; | 77 | if (d->ops->to_irq) |
78 | return d->ops->to_irq(d, hwirq); | ||
79 | if (WARN_ON(hwirq < d->hwirq_base)) | ||
80 | return 0; | ||
81 | return d->irq_base + hwirq - d->hwirq_base; | ||
76 | } | 82 | } |
77 | 83 | ||
84 | #define irq_domain_for_each_hwirq(d, hw) \ | ||
85 | for (hw = d->hwirq_base; hw < d->hwirq_base + d->nr_irq; hw++) | ||
86 | |||
87 | #define irq_domain_for_each_irq(d, hw, irq) \ | ||
88 | for (hw = d->hwirq_base, irq = irq_domain_to_irq(d, hw); \ | ||
89 | hw < d->hwirq_base + d->nr_irq; \ | ||
90 | hw++, irq = irq_domain_to_irq(d, hw)) | ||
91 | |||
78 | extern void irq_domain_add(struct irq_domain *domain); | 92 | extern void irq_domain_add(struct irq_domain *domain); |
79 | extern void irq_domain_del(struct irq_domain *domain); | 93 | extern void irq_domain_del(struct irq_domain *domain); |
80 | #endif /* CONFIG_IRQ_DOMAIN */ | 94 | #endif /* CONFIG_IRQ_DOMAIN */ |
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index b57a3776de44..200ce832c585 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c | |||
@@ -20,15 +20,15 @@ static DEFINE_MUTEX(irq_domain_mutex); | |||
20 | void irq_domain_add(struct irq_domain *domain) | 20 | void irq_domain_add(struct irq_domain *domain) |
21 | { | 21 | { |
22 | struct irq_data *d; | 22 | struct irq_data *d; |
23 | int hwirq; | 23 | int hwirq, irq; |
24 | 24 | ||
25 | /* | 25 | /* |
26 | * This assumes that the irq_domain owner has already allocated | 26 | * This assumes that the irq_domain owner has already allocated |
27 | * the irq_descs. This block will be removed when support for dynamic | 27 | * the irq_descs. This block will be removed when support for dynamic |
28 | * allocation of irq_descs is added to irq_domain. | 28 | * allocation of irq_descs is added to irq_domain. |
29 | */ | 29 | */ |
30 | for (hwirq = 0; hwirq < domain->nr_irq; hwirq++) { | 30 | irq_domain_for_each_irq(domain, hwirq, irq) { |
31 | d = irq_get_irq_data(irq_domain_to_irq(domain, hwirq)); | 31 | d = irq_get_irq_data(irq); |
32 | if (!d) { | 32 | if (!d) { |
33 | WARN(1, "error: assigning domain to non existant irq_desc"); | 33 | WARN(1, "error: assigning domain to non existant irq_desc"); |
34 | return; | 34 | return; |
@@ -54,15 +54,15 @@ void irq_domain_add(struct irq_domain *domain) | |||
54 | void irq_domain_del(struct irq_domain *domain) | 54 | void irq_domain_del(struct irq_domain *domain) |
55 | { | 55 | { |
56 | struct irq_data *d; | 56 | struct irq_data *d; |
57 | int hwirq; | 57 | int hwirq, irq; |
58 | 58 | ||
59 | mutex_lock(&irq_domain_mutex); | 59 | mutex_lock(&irq_domain_mutex); |
60 | list_del(&domain->list); | 60 | list_del(&domain->list); |
61 | mutex_unlock(&irq_domain_mutex); | 61 | mutex_unlock(&irq_domain_mutex); |
62 | 62 | ||
63 | /* Clear the irq_domain assignments */ | 63 | /* Clear the irq_domain assignments */ |
64 | for (hwirq = 0; hwirq < domain->nr_irq; hwirq++) { | 64 | irq_domain_for_each_irq(domain, hwirq, irq) { |
65 | d = irq_get_irq_data(irq_domain_to_irq(domain, hwirq)); | 65 | d = irq_get_irq_data(irq); |
66 | d->domain = NULL; | 66 | d->domain = NULL; |
67 | } | 67 | } |
68 | } | 68 | } |