From 264041e3796133003f010303629a249f9caa3275 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 24 Nov 2015 22:10:26 +0900 Subject: of/irq: optimize device node matching loop in of_irq_init() Currently, of_irq_init() iterates over interrupt controller nodes with for_each_matching_node(), and then gets each init function with of_match_node() later. This routine can be optimized with for_each_matching_node_and_match(). It allows to get the interrupt controller node and its init function at the same time, saving __of_match_node() callings. Signed-off-by: Masahiro Yamada Signed-off-by: Rob Herring --- drivers/of/irq.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'drivers/of') diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 902b89be7217..4c0da87b417c 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -472,6 +472,7 @@ EXPORT_SYMBOL_GPL(of_irq_to_resource_table); struct of_intc_desc { struct list_head list; + of_irq_init_cb_t irq_init_cb; struct device_node *dev; struct device_node *interrupt_parent; }; @@ -485,6 +486,7 @@ struct of_intc_desc { */ 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; @@ -492,10 +494,15 @@ void __init of_irq_init(const struct of_device_id *matches) INIT_LIST_HEAD(&intc_desc_list); INIT_LIST_HEAD(&intc_parent_list); - for_each_matching_node(np, matches) { + for_each_matching_node_and_match(np, matches, &match) { if (!of_find_property(np, "interrupt-controller", NULL) || !of_device_is_available(np)) continue; + + if (WARN(!match->data, "of_irq_init: no init function for %s\n", + match->compatible)) + continue; + /* * Here, we allocate and populate an of_intc_desc with the node * pointer, interrupt-parent device_node etc. @@ -506,6 +513,7 @@ void __init of_irq_init(const struct of_device_id *matches) goto err; } + desc->irq_init_cb = match->data; desc->dev = of_node_get(np); desc->interrupt_parent = of_irq_find_parent(np); if (desc->interrupt_parent == np) @@ -525,27 +533,18 @@ void __init of_irq_init(const struct of_device_id *matches) * 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, + pr_debug("of_irq_init: init %s (%p), parent %p\n", + desc->dev->full_name, desc->dev, desc->interrupt_parent); - irq_init_cb = (of_irq_init_cb_t)match->data; - ret = irq_init_cb(desc->dev, desc->interrupt_parent); + ret = desc->irq_init_cb(desc->dev, + desc->interrupt_parent); if (ret) { kfree(desc); continue; -- cgit v1.2.3 From 289582eac070a960e3c1cbfd8d110342426c5842 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 30 Nov 2015 15:14:19 +0900 Subject: of/address: replace printk(KERN_ERR ...) with pr_err(...) A trivial change suggested by checkpatch.pl. Signed-off-by: Masahiro Yamada Signed-off-by: Rob Herring --- drivers/of/address.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/of') diff --git a/drivers/of/address.c b/drivers/of/address.c index cd53fe4a0c86..5289c80d5467 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -596,7 +596,7 @@ static u64 __of_translate_address(struct device_node *dev, pbus = of_match_bus(parent); pbus->count_cells(dev, &pna, &pns); if (!OF_CHECK_COUNTS(pna, pns)) { - printk(KERN_ERR "prom_parse: Bad cell count for %s\n", + pr_err("prom_parse: Bad cell count for %s\n", of_node_full_name(dev)); break; } -- cgit v1.2.3 From d2329fb576d2c7eb0824028d9c6d3d48fb90b11a Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Mon, 4 Jan 2016 13:13:21 +0100 Subject: of/unittest: Show broken behaviour in the platform bus Add a single resource to the test bus device to exercise the platform bus code a little more. This isn't strictly a devicetree test, but it is a corner case that the devicetree runs into. Until we've got platform device unittests, it can live here. It doesn't need to be an explicit text because the kernel will oops when it is wrong. Cc: Pantelis Antoniou Cc: Rob Herring Cc: Greg Kroah-Hartman Cc: Ricardo Ribalda Delgado Signed-off-by: Grant Likely [wsa: added the comment provided by Grant, rebased, and tested] Signed-off-by: Wolfram Sang Signed-off-by: Rob Herring --- drivers/of/unittest.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers/of') diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index e16ea5717b7f..bbff09dee1cf 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -757,6 +757,11 @@ static void __init of_unittest_match_node(void) } } +static struct resource test_bus_res = { + .start = 0xfffffff8, + .end = 0xfffffff9, + .flags = IORESOURCE_MEM, +}; static const struct platform_device_info test_bus_info = { .name = "unittest-bus", }; @@ -800,6 +805,15 @@ static void __init of_unittest_platform_populate(void) return; test_bus->dev.of_node = np; + /* + * Add a dummy resource to the test bus node after it is + * registered to catch problems with un-inserted resources. The + * DT code doesn't insert the resources, and it has caused the + * kernel to oops in the past. This makes sure the same bug + * doesn't crop up again. + */ + platform_device_add_resources(test_bus, &test_bus_res, 1); + of_platform_populate(np, match, NULL, &test_bus->dev); for_each_child_of_node(np, child) { for_each_child_of_node(child, grandchild) -- cgit v1.2.3 From b80443c2211c7daaabd20fbbe9e7beb3fa3408e0 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 5 Jan 2016 11:17:53 +0900 Subject: of/platform: export of_default_bus_match_table Currently, drivers/bus/uniphier-system-bus.c is kept from being a module due to the unresolved reference to of_default_bus_match_table. Refer to commit 326ea45aa827 ("bus: uniphier: allow only built-in driver"). Signed-off-by: Masahiro Yamada Signed-off-by: Rob Herring --- drivers/of/platform.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/of') diff --git a/drivers/of/platform.c b/drivers/of/platform.c index af98343614d8..8d103e4968be 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -31,6 +31,7 @@ const struct of_device_id of_default_bus_match_table[] = { #endif /* CONFIG_ARM_AMBA */ {} /* Empty terminated list */ }; +EXPORT_SYMBOL(of_default_bus_match_table); static int of_dev_node_match(struct device *dev, void *data) { -- cgit v1.2.3 From 183223770ae8625df8966ed15811d1b3ee8720aa Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Thu, 5 Nov 2015 00:12:49 +1100 Subject: drivers/of: Export OF changeset functions The PowerNV PCI hotplug driver is going to use the OF changeset to manage the changed device sub-tree. This exports those OF changeset functions for that. Signed-off-by: Gavin Shan Acked-by: Wolfram Sang Tested-by: Wolfram Sang Signed-off-by: Rob Herring --- drivers/of/dynamic.c | 65 ++++++++++++++++++++++++++++++++++--------------- drivers/of/of_private.h | 2 ++ drivers/of/overlay.c | 8 +++--- drivers/of/unittest.c | 4 --- 4 files changed, 52 insertions(+), 27 deletions(-) (limited to 'drivers/of') diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c index 53826b84e0ec..c647bd1b6903 100644 --- a/drivers/of/dynamic.c +++ b/drivers/of/dynamic.c @@ -646,6 +646,7 @@ void of_changeset_init(struct of_changeset *ocs) memset(ocs, 0, sizeof(*ocs)); INIT_LIST_HEAD(&ocs->entries); } +EXPORT_SYMBOL_GPL(of_changeset_init); /** * of_changeset_destroy - Destroy a changeset @@ -662,20 +663,9 @@ void of_changeset_destroy(struct of_changeset *ocs) list_for_each_entry_safe_reverse(ce, cen, &ocs->entries, node) __of_changeset_entry_destroy(ce); } +EXPORT_SYMBOL_GPL(of_changeset_destroy); -/** - * of_changeset_apply - Applies a changeset - * - * @ocs: changeset pointer - * - * Applies a changeset to the live tree. - * Any side-effects of live tree state changes are applied here on - * sucess, like creation/destruction of devices and side-effects - * like creation of sysfs properties and directories. - * Returns 0 on success, a negative error value in case of an error. - * On error the partially applied effects are reverted. - */ -int of_changeset_apply(struct of_changeset *ocs) +int __of_changeset_apply(struct of_changeset *ocs) { struct of_changeset_entry *ce; int ret; @@ -704,17 +694,30 @@ int of_changeset_apply(struct of_changeset *ocs) } /** - * of_changeset_revert - Reverts an applied changeset + * of_changeset_apply - Applies a changeset * * @ocs: changeset pointer * - * Reverts a changeset returning the state of the tree to what it - * was before the application. - * Any side-effects like creation/destruction of devices and - * removal of sysfs properties and directories are applied. + * Applies a changeset to the live tree. + * Any side-effects of live tree state changes are applied here on + * success, like creation/destruction of devices and side-effects + * like creation of sysfs properties and directories. * Returns 0 on success, a negative error value in case of an error. + * On error the partially applied effects are reverted. */ -int of_changeset_revert(struct of_changeset *ocs) +int of_changeset_apply(struct of_changeset *ocs) +{ + int ret; + + mutex_lock(&of_mutex); + ret = __of_changeset_apply(ocs); + mutex_unlock(&of_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(of_changeset_apply); + +int __of_changeset_revert(struct of_changeset *ocs) { struct of_changeset_entry *ce; int ret; @@ -741,6 +744,29 @@ int of_changeset_revert(struct of_changeset *ocs) return 0; } +/** + * of_changeset_revert - Reverts an applied changeset + * + * @ocs: changeset pointer + * + * Reverts a changeset returning the state of the tree to what it + * was before the application. + * Any side-effects like creation/destruction of devices and + * removal of sysfs properties and directories are applied. + * Returns 0 on success, a negative error value in case of an error. + */ +int of_changeset_revert(struct of_changeset *ocs) +{ + int ret; + + mutex_lock(&of_mutex); + ret = __of_changeset_revert(ocs); + mutex_unlock(&of_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(of_changeset_revert); + /** * of_changeset_action - Perform a changeset action * @@ -779,3 +805,4 @@ int of_changeset_action(struct of_changeset *ocs, unsigned long action, list_add_tail(&ce->node, &ocs->entries); return 0; } +EXPORT_SYMBOL_GPL(of_changeset_action); diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h index 8e882e706cd8..829469faeb23 100644 --- a/drivers/of/of_private.h +++ b/drivers/of/of_private.h @@ -45,6 +45,8 @@ static inline struct device_node *kobj_to_device_node(struct kobject *kobj) extern int of_property_notify(int action, struct device_node *np, struct property *prop, struct property *old_prop); extern void of_node_release(struct kobject *kobj); +extern int __of_changeset_apply(struct of_changeset *ocs); +extern int __of_changeset_revert(struct of_changeset *ocs); #else /* CONFIG_OF_DYNAMIC */ static inline int of_property_notify(int action, struct device_node *np, struct property *prop, struct property *old_prop) diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c index 54e5af9d7377..82250815e9a5 100644 --- a/drivers/of/overlay.c +++ b/drivers/of/overlay.c @@ -379,9 +379,9 @@ int of_overlay_create(struct device_node *tree) } /* apply the changeset */ - err = of_changeset_apply(&ov->cset); + err = __of_changeset_apply(&ov->cset); if (err) { - pr_err("%s: of_changeset_apply() failed for tree@%s\n", + pr_err("%s: __of_changeset_apply() failed for tree@%s\n", __func__, tree->full_name); goto err_revert_overlay; } @@ -511,7 +511,7 @@ int of_overlay_destroy(int id) list_del(&ov->node); - of_changeset_revert(&ov->cset); + __of_changeset_revert(&ov->cset); of_free_overlay_info(ov); idr_remove(&ov_idr, id); of_changeset_destroy(&ov->cset); @@ -542,7 +542,7 @@ int of_overlay_destroy_all(void) /* the tail of list is guaranteed to be safe to remove */ list_for_each_entry_safe_reverse(ov, ovn, &ov_list, node) { list_del(&ov->node); - of_changeset_revert(&ov->cset); + __of_changeset_revert(&ov->cset); of_free_overlay_info(ov); idr_remove(&ov_idr, ov->id); kfree(ov); diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index bbff09dee1cf..979b6e415cea 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -530,18 +530,14 @@ static void __init of_unittest_changeset(void) unittest(!of_changeset_add_property(&chgset, parent, ppadd), "fail add prop\n"); unittest(!of_changeset_update_property(&chgset, parent, ppupdate), "fail update prop\n"); unittest(!of_changeset_remove_property(&chgset, parent, ppremove), "fail remove prop\n"); - mutex_lock(&of_mutex); unittest(!of_changeset_apply(&chgset), "apply failed\n"); - mutex_unlock(&of_mutex); /* Make sure node names are constructed correctly */ unittest((np = of_find_node_by_path("/testcase-data/changeset/n2/n21")), "'%s' not added\n", n21->full_name); of_node_put(np); - mutex_lock(&of_mutex); unittest(!of_changeset_revert(&chgset), "revert failed\n"); - mutex_unlock(&of_mutex); of_changeset_destroy(&chgset); #endif -- cgit v1.2.3