summaryrefslogtreecommitdiff
path: root/drivers/of
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/of')
-rw-r--r--drivers/of/base.c14
-rw-r--r--drivers/of/fdt.c2
-rw-r--r--drivers/of/irq.c28
-rw-r--r--drivers/of/platform.c4
-rw-r--r--drivers/of/selftest.c32
-rw-r--r--drivers/of/testcase-data/tests-interrupts.dtsi13
6 files changed, 83 insertions, 10 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c
index f72d19b7e5d2..32e969d95319 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -1828,17 +1828,17 @@ int of_update_property(struct device_node *np, struct property *newprop)
next = &(*next)->next;
}
raw_spin_unlock_irqrestore(&devtree_lock, flags);
- if (rc)
- return rc;
+ if (!found)
+ return -ENODEV;
+
+ /* At early boot, bail out and defer setup to of_init() */
+ if (!of_kset)
+ return found ? 0 : -ENODEV;
/* Update the sysfs attribute */
- if (oldprop)
- sysfs_remove_bin_file(&np->kobj, &oldprop->attr);
+ sysfs_remove_bin_file(&np->kobj, &oldprop->attr);
__of_add_property_sysfs(np, newprop);
- if (!found)
- return -ENODEV;
-
return 0;
}
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index fa16a912a927..7a2ef7bb8022 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -491,7 +491,7 @@ static int __init __reserved_mem_reserve_reg(unsigned long node,
* in /reserved-memory matches the values supported by the current implementation,
* also check if ranges property has been provided
*/
-static int __reserved_mem_check_root(unsigned long node)
+static int __init __reserved_mem_check_root(unsigned long node)
{
__be32 *prop;
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index 9bcf2cf19357..5aeb89411350 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -364,7 +364,7 @@ int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
memset(r, 0, sizeof(*r));
/*
- * Get optional "interrupts-names" property to add a name
+ * Get optional "interrupt-names" property to add a name
* to the resource.
*/
of_property_read_string_index(dev, "interrupt-names", index,
@@ -380,6 +380,32 @@ int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
EXPORT_SYMBOL_GPL(of_irq_to_resource);
/**
+ * of_irq_get - Decode a node's IRQ and return it as a Linux irq number
+ * @dev: pointer to device tree node
+ * @index: zero-based index of the irq
+ *
+ * Returns Linux irq number on success, or -EPROBE_DEFER if the irq domain
+ * is not yet created.
+ *
+ */
+int of_irq_get(struct device_node *dev, int index)
+{
+ int rc;
+ struct of_phandle_args oirq;
+ struct irq_domain *domain;
+
+ rc = of_irq_parse_one(dev, index, &oirq);
+ if (rc)
+ return rc;
+
+ domain = irq_find_host(oirq.np);
+ if (!domain)
+ return -EPROBE_DEFER;
+
+ return irq_create_of_mapping(&oirq);
+}
+
+/**
* of_irq_count - Count the number of IRQs a node uses
* @dev: pointer to device tree node
*/
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 91fa9838b56f..4e91583a3908 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -168,7 +168,9 @@ struct platform_device *of_device_alloc(struct device_node *np,
rc = of_address_to_resource(np, i, res);
WARN_ON(rc);
}
- WARN_ON(of_irq_to_resource_table(np, res, num_irq) != num_irq);
+ if (of_irq_to_resource_table(np, res, num_irq) != num_irq)
+ pr_debug("not all legacy IRQ resources mapped for %s\n",
+ np->name);
}
dev->dev.of_node = of_node_get(np);
diff --git a/drivers/of/selftest.c b/drivers/of/selftest.c
index ae4450070503..fe70b86bcffb 100644
--- a/drivers/of/selftest.c
+++ b/drivers/of/selftest.c
@@ -10,6 +10,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
+#include <linux/of_platform.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/slab.h>
@@ -427,6 +428,36 @@ static void __init of_selftest_match_node(void)
}
}
+static void __init of_selftest_platform_populate(void)
+{
+ int irq;
+ struct device_node *np;
+ struct platform_device *pdev;
+
+ np = of_find_node_by_path("/testcase-data");
+ of_platform_populate(np, of_default_bus_match_table, NULL, NULL);
+
+ /* Test that a missing irq domain returns -EPROBE_DEFER */
+ np = of_find_node_by_path("/testcase-data/testcase-device1");
+ pdev = of_find_device_by_node(np);
+ if (!pdev)
+ selftest(0, "device 1 creation failed\n");
+ irq = platform_get_irq(pdev, 0);
+ if (irq != -EPROBE_DEFER)
+ selftest(0, "device deferred probe failed - %d\n", irq);
+
+ /* Test that a parsing failure does not return -EPROBE_DEFER */
+ np = of_find_node_by_path("/testcase-data/testcase-device2");
+ pdev = of_find_device_by_node(np);
+ if (!pdev)
+ selftest(0, "device 2 creation failed\n");
+ irq = platform_get_irq(pdev, 0);
+ if (irq >= 0 || irq == -EPROBE_DEFER)
+ selftest(0, "device parsing error failed - %d\n", irq);
+
+ selftest(1, "passed");
+}
+
static int __init of_selftest(void)
{
struct device_node *np;
@@ -445,6 +476,7 @@ static int __init of_selftest(void)
of_selftest_parse_interrupts();
of_selftest_parse_interrupts_extended();
of_selftest_match_node();
+ of_selftest_platform_populate();
pr_info("end of selftest - %i passed, %i failed\n",
selftest_results.passed, selftest_results.failed);
return 0;
diff --git a/drivers/of/testcase-data/tests-interrupts.dtsi b/drivers/of/testcase-data/tests-interrupts.dtsi
index c843720bd3e5..da4695f60351 100644
--- a/drivers/of/testcase-data/tests-interrupts.dtsi
+++ b/drivers/of/testcase-data/tests-interrupts.dtsi
@@ -54,5 +54,18 @@
<&test_intmap1 1 2>;
};
};
+
+ testcase-device1 {
+ compatible = "testcase-device";
+ interrupt-parent = <&test_intc0>;
+ interrupts = <1>;
+ };
+
+ testcase-device2 {
+ compatible = "testcase-device";
+ interrupt-parent = <&test_intc2>;
+ interrupts = <1>; /* invalid specifier - too short */
+ };
};
+
};