Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 272936
b: refs/heads/master
c: c71a54b
h: refs/heads/master
v: v3
  • Loading branch information
Rob Herring authored and Arnd Bergmann committed Oct 31, 2011
1 parent 59c5551 commit a1e1821
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 3a8254364277fabe01bc0e12b9691722939f5ef3
refs/heads/master: c71a54b0820179e53483d5220cdef1a0df8d5bd1
107 changes: 107 additions & 0 deletions trunk/drivers/of/irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@
*/

#include <linux/errno.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/string.h>
#include <linux/slab.h>

/* For archs that don't support NO_IRQ (such as x86), provide a dummy value */
#ifndef NO_IRQ
Expand Down Expand Up @@ -386,3 +388,108 @@ int of_irq_to_resource_table(struct device_node *dev, struct resource *res,

return i;
}

struct intc_desc {
struct list_head list;
struct device_node *dev;
struct device_node *interrupt_parent;
};

/**
* of_irq_init - Scan and init matching interrupt controllers in DT
* @matches: 0 terminated array of nodes to match and init function to call
*
* This function scans the device tree for matching interrupt controller nodes,
* and calls their initialization functions in order with parents first.
*/
void __init of_irq_init(const struct of_device_id *matches)
{
struct device_node *np, *parent = NULL;
struct intc_desc *desc, *temp_desc;
struct list_head intc_desc_list, intc_parent_list;

INIT_LIST_HEAD(&intc_desc_list);
INIT_LIST_HEAD(&intc_parent_list);

for_each_matching_node(np, matches) {
if (!of_find_property(np, "interrupt-controller", NULL))
continue;
/*
* Here, we allocate and populate an intc_desc with the node
* pointer, interrupt-parent device_node etc.
*/
desc = kzalloc(sizeof(*desc), GFP_KERNEL);
if (WARN_ON(!desc))
goto err;

desc->dev = np;
desc->interrupt_parent = of_irq_find_parent(np);
list_add_tail(&desc->list, &intc_desc_list);
}

/*
* The root irq controller is the one without an interrupt-parent.
* That one goes first, followed by the controllers that reference it,
* followed by the ones that reference the 2nd level controllers, etc.
*/
while (!list_empty(&intc_desc_list)) {
/*
* Process all controllers with the current 'parent'.
* First pass will be looking for NULL as the parent.
* The assumption is that NULL parent means a root controller.
*/
list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
const struct of_device_id *match;
int ret;
of_irq_init_cb_t irq_init_cb;

if (desc->interrupt_parent != parent)
continue;

list_del(&desc->list);
match = of_match_node(matches, desc->dev);
if (WARN(!match->data,
"of_irq_init: no init function for %s\n",
match->compatible)) {
kfree(desc);
continue;
}

pr_debug("of_irq_init: init %s @ %p, parent %p\n",
match->compatible,
desc->dev, desc->interrupt_parent);
irq_init_cb = match->data;
ret = irq_init_cb(desc->dev, desc->interrupt_parent);
if (ret) {
kfree(desc);
continue;
}

/*
* This one is now set up; add it to the parent list so
* its children can get processed in a subsequent pass.
*/
list_add_tail(&desc->list, &intc_parent_list);
}

/* Get the next pending parent that might have children */
desc = list_first_entry(&intc_parent_list, typeof(*desc), list);
if (list_empty(&intc_parent_list) || !desc) {
pr_err("of_irq_init: children remain, but no parents\n");
break;
}
list_del(&desc->list);
parent = desc->dev;
kfree(desc);
}

list_for_each_entry_safe(desc, temp_desc, &intc_parent_list, list) {
list_del(&desc->list);
kfree(desc);
}
err:
list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
list_del(&desc->list);
kfree(desc);
}
}
3 changes: 3 additions & 0 deletions trunk/include/linux/of_irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down Expand Up @@ -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 */
Expand Down

0 comments on commit a1e1821

Please sign in to comment.