From c71a54b0820179e53483d5220cdef1a0df8d5bd1 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 20 Sep 2011 15:13:50 -0500 Subject: of/irq: introduce of_irq_init of_irq_init will scan the devicetree for matching interrupt controller nodes. Then it calls an initialization function for each found controller in the proper order with parent nodes initialized before child nodes. Based on initial pseudo code from Grant Likely. Changes in v4: - Drop unnecessary empty list check - Be more verbose on errors - Simplify "if (!desc) WARN_ON(1)" to "if (WARN_ON(!desc))" Changes in v3: - add missing kfree's found by Jamie - Implement Grant's comments to simplify the init loop - fix function comments Changes in v2: - Complete re-write of list searching code from Grant Likely Signed-off-by: Rob Herring Reviewed-by: Jamie Iles Tested-by: Thomas Abraham Acked-by: Grant Likely --- include/linux/of_irq.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include') diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h index cd2e61ce4e8..d0307eed20c 100644 --- a/include/linux/of_irq.h +++ b/include/linux/of_irq.h @@ -33,6 +33,8 @@ struct of_irq { u32 specifier[OF_MAX_IRQ_SPEC]; /* Specifier copy */ }; +typedef int (*of_irq_init_cb_t)(struct device_node *, struct device_node *); + /* * Workarounds only applied to 32bit powermac machines */ @@ -73,6 +75,7 @@ extern int of_irq_to_resource_table(struct device_node *dev, struct resource *res, int nr_irqs); extern struct device_node *of_irq_find_parent(struct device_node *child); +extern void of_irq_init(const struct of_device_id *matches); #endif /* CONFIG_OF_IRQ */ #endif /* CONFIG_OF */ -- cgit v1.2.3-70-g09d2 From 6d274309d0e64bdbdb6c50945ca2964596e8fa5a Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 30 Sep 2011 10:48:38 -0500 Subject: 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 Reviewed-by: Jamie Iles Tested-by: Thomas Abraham Acked-by: Grant Likely Acked-by: Thomas Gleixner --- include/linux/irqdomain.h | 16 +++++++++++++++- kernel/irq/irqdomain.c | 12 ++++++------ 2 files changed, 21 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index 3ad553e8eae..99834e581b9 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h @@ -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 */ diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c index b57a3776de4..200ce832c58 100644 --- a/kernel/irq/irqdomain.c +++ b/kernel/irq/irqdomain.c @@ -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; } } -- cgit v1.2.3-70-g09d2