1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
|
void __init of_irq_init(const struct of_device_id *matches) { const struct of_device_id *match; struct device_node *np, *parent = NULL; struct of_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_and_match(np, matches, &match) { if (!of_property_read_bool(np, "interrupt-controller") || !of_device_is_available(np)) continue;
if (WARN(!match->data, "of_irq_init: no init function for %s\n", match->compatible)) continue;
desc = kzalloc(sizeof(*desc), GFP_KERNEL); if (!desc) { of_node_put(np); goto err; }
desc->irq_init_cb = match->data; desc->dev = of_node_get(np);
desc->interrupt_parent = of_parse_phandle(np, "interrupts-extended", 0); if (!desc->interrupt_parent) desc->interrupt_parent = of_irq_find_parent(np); if (desc->interrupt_parent == np) { of_node_put(desc->interrupt_parent); desc->interrupt_parent = NULL; } list_add_tail(&desc->list, &intc_desc_list); }
while (!list_empty(&intc_desc_list)) {
list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) { int ret;
if (desc->interrupt_parent != parent) continue; list_del(&desc->list);
of_node_set_flag(desc->dev, OF_POPULATED);
pr_debug("of_irq_init: init %pOF (%p), parent %p\n", desc->dev, desc->dev, desc->interrupt_parent); ret = desc->irq_init_cb(desc->dev, desc->interrupt_parent); if (ret) { pr_err("%s: Failed to init %pOF (%p), parent %p\n", __func__, desc->dev, desc->dev, desc->interrupt_parent); of_node_clear_flag(desc->dev, OF_POPULATED); of_node_put(desc->interrupt_parent); of_node_put(desc->dev); kfree(desc); continue; }
list_add_tail(&desc->list, &intc_parent_list); }
desc = list_first_entry_or_null(&intc_parent_list, typeof(*desc), list); if (!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); of_node_put(desc->interrupt_parent); of_node_put(desc->dev); kfree(desc); } }
|