diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-15 14:49:41 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-15 14:49:41 -0500 |
commit | 6df8b74b1720db1133ace0861cb6721bfe57819a (patch) | |
tree | 9bf00c9a75cd52a0917bbd6ff5ff4a693b3b8f0a | |
parent | 57d64e6f5fac7b47dd03487f5f2670a7f0c67335 (diff) | |
parent | 61eb3a04f9789c5e4f7498a2f171b82a567cea6b (diff) |
Merge tag 'devicetree-for-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux
Pull DeviceTree updates from Rob Herring:
- add various vendor prefixes.
- fix NUMA node handling when "numa=off" is passed on kernel command
line.
- coding style Clean-up of overlay handling code.
- DocBook fixes in DT platform driver code
- Altera SoCFPGA binding addtions for freeze bridge, arria10 FPGA
manager and FPGA bridges.
- a couple of printk message fixes.
* tag 'devicetree-for-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/robh/linux: (33 commits)
dt: pwm: bcm2835: fix typo in clocks property name
devicetree: add vendor prefix for National Instruments
Revert "of: base: add support to get machine model name"
of: Fix issue where code would fall through to error case.
drivers/of: fix missing pr_cont()s in of_print_phandle_args
devicetree: bindings: Add vendor prefix for Oki
devicetree: bindings: Add vendor prefix for Andes Technology Corporation
dt-bindings: add MYIR Tech hardware vendor prefix
add bindings document for altera freeze bridge
ARM: socfpga: add bindings doc for arria10 fpga manager
ARM: socfpga: add bindings document for fpga bridge drivers
of: base: add support to get machine model name
of/platform: clarify of_find_device_by_node refcounting
of/platform: fix of_platform_device_destroy comment
of: Remove unused variable overlay_symbols
of: Move setting of pointer to beside test for non-null
of: Add back an error message, restructured
of: Update comments to reflect changes and increase clarity
of: Remove redundant size check
of: Update structure of code to be clearer, also remove BUG_ON()
...
-rw-r--r-- | Documentation/devicetree/bindings/arm/arm-boards | 3 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/fpga/altera-fpga2sdram-bridge.txt | 16 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/fpga/altera-freeze-bridge.txt | 23 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/fpga/altera-hps2fpga-bridge.txt | 39 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt | 19 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/pwm/pwm-bcm2835.txt | 2 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/vendor-prefixes.txt | 11 | ||||
-rw-r--r-- | drivers/of/base.c | 9 | ||||
-rw-r--r-- | drivers/of/of_numa.c | 7 | ||||
-rw-r--r-- | drivers/of/platform.c | 6 | ||||
-rw-r--r-- | drivers/of/resolver.c | 358 |
11 files changed, 278 insertions, 215 deletions
diff --git a/Documentation/devicetree/bindings/arm/arm-boards b/Documentation/devicetree/bindings/arm/arm-boards index ab318a56fca2..b6e810c2781a 100644 --- a/Documentation/devicetree/bindings/arm/arm-boards +++ b/Documentation/devicetree/bindings/arm/arm-boards | |||
@@ -148,11 +148,12 @@ Example: | |||
148 | 148 | ||
149 | /dts-v1/; | 149 | /dts-v1/; |
150 | #include <dt-bindings/interrupt-controller/irq.h> | 150 | #include <dt-bindings/interrupt-controller/irq.h> |
151 | #include "skeleton.dtsi" | ||
152 | 151 | ||
153 | / { | 152 | / { |
154 | model = "ARM RealView PB1176 with device tree"; | 153 | model = "ARM RealView PB1176 with device tree"; |
155 | compatible = "arm,realview-pb1176"; | 154 | compatible = "arm,realview-pb1176"; |
155 | #address-cells = <1>; | ||
156 | #size-cells = <1>; | ||
156 | 157 | ||
157 | soc { | 158 | soc { |
158 | #address-cells = <1>; | 159 | #address-cells = <1>; |
diff --git a/Documentation/devicetree/bindings/fpga/altera-fpga2sdram-bridge.txt b/Documentation/devicetree/bindings/fpga/altera-fpga2sdram-bridge.txt new file mode 100644 index 000000000000..817a8d4bf903 --- /dev/null +++ b/Documentation/devicetree/bindings/fpga/altera-fpga2sdram-bridge.txt | |||
@@ -0,0 +1,16 @@ | |||
1 | Altera FPGA To SDRAM Bridge Driver | ||
2 | |||
3 | Required properties: | ||
4 | - compatible : Should contain "altr,socfpga-fpga2sdram-bridge" | ||
5 | |||
6 | Optional properties: | ||
7 | - bridge-enable : 0 if driver should disable bridge at startup | ||
8 | 1 if driver should enable bridge at startup | ||
9 | Default is to leave bridge in current state. | ||
10 | |||
11 | Example: | ||
12 | fpga_bridge3: fpga-bridge@ffc25080 { | ||
13 | compatible = "altr,socfpga-fpga2sdram-bridge"; | ||
14 | reg = <0xffc25080 0x4>; | ||
15 | bridge-enable = <0>; | ||
16 | }; | ||
diff --git a/Documentation/devicetree/bindings/fpga/altera-freeze-bridge.txt b/Documentation/devicetree/bindings/fpga/altera-freeze-bridge.txt new file mode 100644 index 000000000000..f8e288c71b2d --- /dev/null +++ b/Documentation/devicetree/bindings/fpga/altera-freeze-bridge.txt | |||
@@ -0,0 +1,23 @@ | |||
1 | Altera Freeze Bridge Controller Driver | ||
2 | |||
3 | The Altera Freeze Bridge Controller manages one or more freeze bridges. | ||
4 | The controller can freeze/disable the bridges which prevents signal | ||
5 | changes from passing through the bridge. The controller can also | ||
6 | unfreeze/enable the bridges which allows traffic to pass through the | ||
7 | bridge normally. | ||
8 | |||
9 | Required properties: | ||
10 | - compatible : Should contain "altr,freeze-bridge-controller" | ||
11 | - regs : base address and size for freeze bridge module | ||
12 | |||
13 | Optional properties: | ||
14 | - bridge-enable : 0 if driver should disable bridge at startup | ||
15 | 1 if driver should enable bridge at startup | ||
16 | Default is to leave bridge in current state. | ||
17 | |||
18 | Example: | ||
19 | freeze-controller@100000450 { | ||
20 | compatible = "altr,freeze-bridge-controller"; | ||
21 | regs = <0x1000 0x10>; | ||
22 | bridge-enable = <0>; | ||
23 | }; | ||
diff --git a/Documentation/devicetree/bindings/fpga/altera-hps2fpga-bridge.txt b/Documentation/devicetree/bindings/fpga/altera-hps2fpga-bridge.txt new file mode 100644 index 000000000000..6406f9337eeb --- /dev/null +++ b/Documentation/devicetree/bindings/fpga/altera-hps2fpga-bridge.txt | |||
@@ -0,0 +1,39 @@ | |||
1 | Altera FPGA/HPS Bridge Driver | ||
2 | |||
3 | Required properties: | ||
4 | - regs : base address and size for AXI bridge module | ||
5 | - compatible : Should contain one of: | ||
6 | "altr,socfpga-lwhps2fpga-bridge", | ||
7 | "altr,socfpga-hps2fpga-bridge", or | ||
8 | "altr,socfpga-fpga2hps-bridge" | ||
9 | - resets : Phandle and reset specifier for this bridge's reset | ||
10 | - clocks : Clocks used by this module. | ||
11 | |||
12 | Optional properties: | ||
13 | - bridge-enable : 0 if driver should disable bridge at startup. | ||
14 | 1 if driver should enable bridge at startup. | ||
15 | Default is to leave bridge in its current state. | ||
16 | |||
17 | Example: | ||
18 | fpga_bridge0: fpga-bridge@ff400000 { | ||
19 | compatible = "altr,socfpga-lwhps2fpga-bridge"; | ||
20 | reg = <0xff400000 0x100000>; | ||
21 | resets = <&rst LWHPS2FPGA_RESET>; | ||
22 | clocks = <&l4_main_clk>; | ||
23 | bridge-enable = <0>; | ||
24 | }; | ||
25 | |||
26 | fpga_bridge1: fpga-bridge@ff500000 { | ||
27 | compatible = "altr,socfpga-hps2fpga-bridge"; | ||
28 | reg = <0xff500000 0x10000>; | ||
29 | resets = <&rst HPS2FPGA_RESET>; | ||
30 | clocks = <&l4_main_clk>; | ||
31 | bridge-enable = <1>; | ||
32 | }; | ||
33 | |||
34 | fpga_bridge2: fpga-bridge@ff600000 { | ||
35 | compatible = "altr,socfpga-fpga2hps-bridge"; | ||
36 | reg = <0xff600000 0x100000>; | ||
37 | resets = <&rst FPGA2HPS_RESET>; | ||
38 | clocks = <&l4_main_clk>; | ||
39 | }; | ||
diff --git a/Documentation/devicetree/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt b/Documentation/devicetree/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt new file mode 100644 index 000000000000..2fd8e7a84734 --- /dev/null +++ b/Documentation/devicetree/bindings/fpga/altera-socfpga-a10-fpga-mgr.txt | |||
@@ -0,0 +1,19 @@ | |||
1 | Altera SOCFPGA Arria10 FPGA Manager | ||
2 | |||
3 | Required properties: | ||
4 | - compatible : should contain "altr,socfpga-a10-fpga-mgr" | ||
5 | - reg : base address and size for memory mapped io. | ||
6 | - The first index is for FPGA manager register access. | ||
7 | - The second index is for writing FPGA configuration data. | ||
8 | - resets : Phandle and reset specifier for the device's reset. | ||
9 | - clocks : Clocks used by the device. | ||
10 | |||
11 | Example: | ||
12 | |||
13 | fpga_mgr: fpga-mgr@ffd03000 { | ||
14 | compatible = "altr,socfpga-a10-fpga-mgr"; | ||
15 | reg = <0xffd03000 0x100 | ||
16 | 0xffcfe400 0x20>; | ||
17 | clocks = <&l4_mp_clk>; | ||
18 | resets = <&rst FPGAMGR_RESET>; | ||
19 | }; | ||
diff --git a/Documentation/devicetree/bindings/pwm/pwm-bcm2835.txt b/Documentation/devicetree/bindings/pwm/pwm-bcm2835.txt index fb6fb31bc4c4..cf573e85b11d 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-bcm2835.txt +++ b/Documentation/devicetree/bindings/pwm/pwm-bcm2835.txt | |||
@@ -3,7 +3,7 @@ BCM2835 PWM controller (Raspberry Pi controller) | |||
3 | Required properties: | 3 | Required properties: |
4 | - compatible: should be "brcm,bcm2835-pwm" | 4 | - compatible: should be "brcm,bcm2835-pwm" |
5 | - reg: physical base address and length of the controller's registers | 5 | - reg: physical base address and length of the controller's registers |
6 | - clock: This clock defines the base clock frequency of the PWM hardware | 6 | - clocks: This clock defines the base clock frequency of the PWM hardware |
7 | system, the period and the duty_cycle of the PWM signal is a multiple of | 7 | system, the period and the duty_cycle of the PWM signal is a multiple of |
8 | the base period. | 8 | the base period. |
9 | - #pwm-cells: Should be 2. See pwm.txt in this directory for a description of | 9 | - #pwm-cells: Should be 2. See pwm.txt in this directory for a description of |
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 078834a5fd85..6e25c912a5c2 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt | |||
@@ -24,9 +24,11 @@ ampire Ampire Co., Ltd. | |||
24 | ams AMS AG | 24 | ams AMS AG |
25 | amstaos AMS-Taos Inc. | 25 | amstaos AMS-Taos Inc. |
26 | analogix Analogix Semiconductor, Inc. | 26 | analogix Analogix Semiconductor, Inc. |
27 | andestech Andes Technology Corporation | ||
27 | apm Applied Micro Circuits Corporation (APM) | 28 | apm Applied Micro Circuits Corporation (APM) |
28 | aptina Aptina Imaging | 29 | aptina Aptina Imaging |
29 | arasan Arasan Chip Systems | 30 | arasan Arasan Chip Systems |
31 | aries Aries Embedded GmbH | ||
30 | arm ARM Ltd. | 32 | arm ARM Ltd. |
31 | armadeus ARMadeus Systems SARL | 33 | armadeus ARMadeus Systems SARL |
32 | arrow Arrow Electronics | 34 | arrow Arrow Electronics |
@@ -161,6 +163,7 @@ lg LG Corporation | |||
161 | linux Linux-specific binding | 163 | linux Linux-specific binding |
162 | lltc Linear Technology Corporation | 164 | lltc Linear Technology Corporation |
163 | lsi LSI Corp. (LSI Logic) | 165 | lsi LSI Corp. (LSI Logic) |
166 | macnica Macnica Americas | ||
164 | marvell Marvell Technology Group Ltd. | 167 | marvell Marvell Technology Group Ltd. |
165 | maxim Maxim Integrated Products | 168 | maxim Maxim Integrated Products |
166 | mcube mCube | 169 | mcube mCube |
@@ -186,6 +189,7 @@ mti Imagination Technologies Ltd. (formerly MIPS Technologies Inc.) | |||
186 | mundoreader Mundo Reader S.L. | 189 | mundoreader Mundo Reader S.L. |
187 | murata Murata Manufacturing Co., Ltd. | 190 | murata Murata Manufacturing Co., Ltd. |
188 | mxicy Macronix International Co., Ltd. | 191 | mxicy Macronix International Co., Ltd. |
192 | myir MYIR Tech Limited | ||
189 | national National Semiconductor | 193 | national National Semiconductor |
190 | nec NEC LCD Technologies, Ltd. | 194 | nec NEC LCD Technologies, Ltd. |
191 | neonode Neonode Inc. | 195 | neonode Neonode Inc. |
@@ -193,13 +197,15 @@ netgear NETGEAR | |||
193 | netlogic Broadcom Corporation (formerly NetLogic Microsystems) | 197 | netlogic Broadcom Corporation (formerly NetLogic Microsystems) |
194 | netxeon Shenzhen Netxeon Technology CO., LTD | 198 | netxeon Shenzhen Netxeon Technology CO., LTD |
195 | newhaven Newhaven Display International | 199 | newhaven Newhaven Display International |
196 | nvd New Vision Display | 200 | ni National Instruments |
197 | nintendo Nintendo | 201 | nintendo Nintendo |
198 | nokia Nokia | 202 | nokia Nokia |
199 | nuvoton Nuvoton Technology Corporation | 203 | nuvoton Nuvoton Technology Corporation |
204 | nvd New Vision Display | ||
200 | nvidia NVIDIA | 205 | nvidia NVIDIA |
201 | nxp NXP Semiconductors | 206 | nxp NXP Semiconductors |
202 | okaya Okaya Electric America, Inc. | 207 | okaya Okaya Electric America, Inc. |
208 | oki Oki Electric Industry Co., Ltd. | ||
203 | olimex OLIMEX Ltd. | 209 | olimex OLIMEX Ltd. |
204 | onion Onion Corporation | 210 | onion Onion Corporation |
205 | onnn ON Semiconductor Corp. | 211 | onnn ON Semiconductor Corp. |
@@ -238,6 +244,7 @@ richtek Richtek Technology Corporation | |||
238 | ricoh Ricoh Co. Ltd. | 244 | ricoh Ricoh Co. Ltd. |
239 | rockchip Fuzhou Rockchip Electronics Co., Ltd | 245 | rockchip Fuzhou Rockchip Electronics Co., Ltd |
240 | samsung Samsung Semiconductor | 246 | samsung Samsung Semiconductor |
247 | samtec Samtec/Softing company | ||
241 | sandisk Sandisk Corporation | 248 | sandisk Sandisk Corporation |
242 | sbs Smart Battery System | 249 | sbs Smart Battery System |
243 | schindler Schindler | 250 | schindler Schindler |
@@ -282,6 +289,7 @@ tcg Trusted Computing Group | |||
282 | tcl Toby Churchill Ltd. | 289 | tcl Toby Churchill Ltd. |
283 | technexion TechNexion | 290 | technexion TechNexion |
284 | technologic Technologic Systems | 291 | technologic Technologic Systems |
292 | terasic Terasic Inc. | ||
285 | thine THine Electronics, Inc. | 293 | thine THine Electronics, Inc. |
286 | ti Texas Instruments | 294 | ti Texas Instruments |
287 | tlm Trusted Logic Mobility | 295 | tlm Trusted Logic Mobility |
@@ -296,6 +304,7 @@ tronfy Tronfy | |||
296 | tronsmart Tronsmart | 304 | tronsmart Tronsmart |
297 | truly Truly Semiconductors Limited | 305 | truly Truly Semiconductors Limited |
298 | tyan Tyan Computer Corporation | 306 | tyan Tyan Computer Corporation |
307 | udoo Udoo | ||
299 | uniwest United Western Technologies Corp (UniWest) | 308 | uniwest United Western Technologies Corp (UniWest) |
300 | upisemi uPI Semiconductor Corp. | 309 | upisemi uPI Semiconductor Corp. |
301 | urt United Radiant Technology Corporation | 310 | urt United Radiant Technology Corporation |
diff --git a/drivers/of/base.c b/drivers/of/base.c index a0bccb54a9bd..d4bea3c797d6 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c | |||
@@ -1534,9 +1534,12 @@ void of_print_phandle_args(const char *msg, const struct of_phandle_args *args) | |||
1534 | { | 1534 | { |
1535 | int i; | 1535 | int i; |
1536 | printk("%s %s", msg, of_node_full_name(args->np)); | 1536 | printk("%s %s", msg, of_node_full_name(args->np)); |
1537 | for (i = 0; i < args->args_count; i++) | 1537 | for (i = 0; i < args->args_count; i++) { |
1538 | printk(i ? ",%08x" : ":%08x", args->args[i]); | 1538 | const char delim = i ? ',' : ':'; |
1539 | printk("\n"); | 1539 | |
1540 | pr_cont("%c%08x", delim, args->args[i]); | ||
1541 | } | ||
1542 | pr_cont("\n"); | ||
1540 | } | 1543 | } |
1541 | 1544 | ||
1542 | int of_phandle_iterator_init(struct of_phandle_iterator *it, | 1545 | int of_phandle_iterator_init(struct of_phandle_iterator *it, |
diff --git a/drivers/of/of_numa.c b/drivers/of/of_numa.c index f63d4b0deff0..a53982a330ea 100644 --- a/drivers/of/of_numa.c +++ b/drivers/of/of_numa.c | |||
@@ -176,7 +176,12 @@ int of_node_to_nid(struct device_node *device) | |||
176 | np->name); | 176 | np->name); |
177 | of_node_put(np); | 177 | of_node_put(np); |
178 | 178 | ||
179 | if (!r) | 179 | /* |
180 | * If numa=off passed on command line, or with a defective | ||
181 | * device tree, the nid may not be in the set of possible | ||
182 | * nodes. Check for this case and return NUMA_NO_NODE. | ||
183 | */ | ||
184 | if (!r && nid < MAX_NUMNODES && node_possible(nid)) | ||
180 | return nid; | 185 | return nid; |
181 | 186 | ||
182 | return NUMA_NO_NODE; | 187 | return NUMA_NO_NODE; |
diff --git a/drivers/of/platform.c b/drivers/of/platform.c index e4bf07d20f9b..b8064bc2b6eb 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c | |||
@@ -45,6 +45,9 @@ static int of_dev_node_match(struct device *dev, void *data) | |||
45 | * of_find_device_by_node - Find the platform_device associated with a node | 45 | * of_find_device_by_node - Find the platform_device associated with a node |
46 | * @np: Pointer to device tree node | 46 | * @np: Pointer to device tree node |
47 | * | 47 | * |
48 | * Takes a reference to the embedded struct device which needs to be dropped | ||
49 | * after use. | ||
50 | * | ||
48 | * Returns platform_device pointer, or NULL if not found | 51 | * Returns platform_device pointer, or NULL if not found |
49 | */ | 52 | */ |
50 | struct platform_device *of_find_device_by_node(struct device_node *np) | 53 | struct platform_device *of_find_device_by_node(struct device_node *np) |
@@ -558,9 +561,6 @@ static int of_platform_device_destroy(struct device *dev, void *data) | |||
558 | * of the given device (and, recurrently, their children) that have been | 561 | * of the given device (and, recurrently, their children) that have been |
559 | * created from their respective device tree nodes (and only those, | 562 | * created from their respective device tree nodes (and only those, |
560 | * leaving others - eg. manually created - unharmed). | 563 | * leaving others - eg. manually created - unharmed). |
561 | * | ||
562 | * Returns 0 when all children devices have been removed or | ||
563 | * -EBUSY when some children remained. | ||
564 | */ | 564 | */ |
565 | void of_platform_depopulate(struct device *parent) | 565 | void of_platform_depopulate(struct device *parent) |
566 | { | 566 | { |
diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c index 46325d6394cf..8bf12e904fd2 100644 --- a/drivers/of/resolver.c +++ b/drivers/of/resolver.c | |||
@@ -28,20 +28,19 @@ | |||
28 | * Find a node with the give full name by recursively following any of | 28 | * Find a node with the give full name by recursively following any of |
29 | * the child node links. | 29 | * the child node links. |
30 | */ | 30 | */ |
31 | static struct device_node *__of_find_node_by_full_name(struct device_node *node, | 31 | static struct device_node *find_node_by_full_name(struct device_node *node, |
32 | const char *full_name) | 32 | const char *full_name) |
33 | { | 33 | { |
34 | struct device_node *child, *found; | 34 | struct device_node *child, *found; |
35 | 35 | ||
36 | if (node == NULL) | 36 | if (!node) |
37 | return NULL; | 37 | return NULL; |
38 | 38 | ||
39 | /* check */ | 39 | if (!of_node_cmp(node->full_name, full_name)) |
40 | if (of_node_cmp(node->full_name, full_name) == 0) | ||
41 | return of_node_get(node); | 40 | return of_node_get(node); |
42 | 41 | ||
43 | for_each_child_of_node(node, child) { | 42 | for_each_child_of_node(node, child) { |
44 | found = __of_find_node_by_full_name(child, full_name); | 43 | found = find_node_by_full_name(child, full_name); |
45 | if (found != NULL) { | 44 | if (found != NULL) { |
46 | of_node_put(child); | 45 | of_node_put(child); |
47 | return found; | 46 | return found; |
@@ -51,16 +50,12 @@ static struct device_node *__of_find_node_by_full_name(struct device_node *node, | |||
51 | return NULL; | 50 | return NULL; |
52 | } | 51 | } |
53 | 52 | ||
54 | /* | 53 | static phandle live_tree_max_phandle(void) |
55 | * Find live tree's maximum phandle value. | ||
56 | */ | ||
57 | static phandle of_get_tree_max_phandle(void) | ||
58 | { | 54 | { |
59 | struct device_node *node; | 55 | struct device_node *node; |
60 | phandle phandle; | 56 | phandle phandle; |
61 | unsigned long flags; | 57 | unsigned long flags; |
62 | 58 | ||
63 | /* now search recursively */ | ||
64 | raw_spin_lock_irqsave(&devtree_lock, flags); | 59 | raw_spin_lock_irqsave(&devtree_lock, flags); |
65 | phandle = 0; | 60 | phandle = 0; |
66 | for_each_of_allnodes(node) { | 61 | for_each_of_allnodes(node) { |
@@ -73,131 +68,102 @@ static phandle of_get_tree_max_phandle(void) | |||
73 | return phandle; | 68 | return phandle; |
74 | } | 69 | } |
75 | 70 | ||
76 | /* | 71 | static void adjust_overlay_phandles(struct device_node *overlay, |
77 | * Adjust a subtree's phandle values by a given delta. | ||
78 | * Makes sure not to just adjust the device node's phandle value, | ||
79 | * but modify the phandle properties values as well. | ||
80 | */ | ||
81 | static void __of_adjust_tree_phandles(struct device_node *node, | ||
82 | int phandle_delta) | 72 | int phandle_delta) |
83 | { | 73 | { |
84 | struct device_node *child; | 74 | struct device_node *child; |
85 | struct property *prop; | 75 | struct property *prop; |
86 | phandle phandle; | 76 | phandle phandle; |
87 | 77 | ||
88 | /* first adjust the node's phandle direct value */ | 78 | /* adjust node's phandle in node */ |
89 | if (node->phandle != 0 && node->phandle != OF_PHANDLE_ILLEGAL) | 79 | if (overlay->phandle != 0 && overlay->phandle != OF_PHANDLE_ILLEGAL) |
90 | node->phandle += phandle_delta; | 80 | overlay->phandle += phandle_delta; |
91 | 81 | ||
92 | /* now adjust phandle & linux,phandle values */ | 82 | /* copy adjusted phandle into *phandle properties */ |
93 | for_each_property_of_node(node, prop) { | 83 | for_each_property_of_node(overlay, prop) { |
94 | 84 | ||
95 | /* only look for these two */ | 85 | if (of_prop_cmp(prop->name, "phandle") && |
96 | if (of_prop_cmp(prop->name, "phandle") != 0 && | 86 | of_prop_cmp(prop->name, "linux,phandle")) |
97 | of_prop_cmp(prop->name, "linux,phandle") != 0) | ||
98 | continue; | 87 | continue; |
99 | 88 | ||
100 | /* must be big enough */ | ||
101 | if (prop->length < 4) | 89 | if (prop->length < 4) |
102 | continue; | 90 | continue; |
103 | 91 | ||
104 | /* read phandle value */ | ||
105 | phandle = be32_to_cpup(prop->value); | 92 | phandle = be32_to_cpup(prop->value); |
106 | if (phandle == OF_PHANDLE_ILLEGAL) /* unresolved */ | 93 | if (phandle == OF_PHANDLE_ILLEGAL) |
107 | continue; | 94 | continue; |
108 | 95 | ||
109 | /* adjust */ | 96 | *(uint32_t *)prop->value = cpu_to_be32(overlay->phandle); |
110 | *(uint32_t *)prop->value = cpu_to_be32(node->phandle); | ||
111 | } | 97 | } |
112 | 98 | ||
113 | /* now do the children recursively */ | 99 | for_each_child_of_node(overlay, child) |
114 | for_each_child_of_node(node, child) | 100 | adjust_overlay_phandles(child, phandle_delta); |
115 | __of_adjust_tree_phandles(child, phandle_delta); | ||
116 | } | 101 | } |
117 | 102 | ||
118 | static int __of_adjust_phandle_ref(struct device_node *node, | 103 | static int update_usages_of_a_phandle_reference(struct device_node *overlay, |
119 | struct property *rprop, int value) | 104 | struct property *prop_fixup, phandle phandle) |
120 | { | 105 | { |
121 | phandle phandle; | ||
122 | struct device_node *refnode; | 106 | struct device_node *refnode; |
123 | struct property *sprop; | 107 | struct property *prop; |
124 | char *propval, *propcur, *propend, *nodestr, *propstr, *s; | 108 | char *value, *cur, *end, *node_path, *prop_name, *s; |
125 | int offset, propcurlen; | 109 | int offset, len; |
126 | int err = 0; | 110 | int err = 0; |
127 | 111 | ||
128 | /* make a copy */ | 112 | value = kmalloc(prop_fixup->length, GFP_KERNEL); |
129 | propval = kmalloc(rprop->length, GFP_KERNEL); | 113 | if (!value) |
130 | if (!propval) { | ||
131 | pr_err("%s: Could not copy value of '%s'\n", | ||
132 | __func__, rprop->name); | ||
133 | return -ENOMEM; | 114 | return -ENOMEM; |
134 | } | 115 | memcpy(value, prop_fixup->value, prop_fixup->length); |
135 | memcpy(propval, rprop->value, rprop->length); | ||
136 | 116 | ||
137 | propend = propval + rprop->length; | 117 | /* prop_fixup contains a list of tuples of path:property_name:offset */ |
138 | for (propcur = propval; propcur < propend; propcur += propcurlen + 1) { | 118 | end = value + prop_fixup->length; |
139 | propcurlen = strlen(propcur); | 119 | for (cur = value; cur < end; cur += len + 1) { |
120 | len = strlen(cur); | ||
140 | 121 | ||
141 | nodestr = propcur; | 122 | node_path = cur; |
142 | s = strchr(propcur, ':'); | 123 | s = strchr(cur, ':'); |
143 | if (!s) { | 124 | if (!s) { |
144 | pr_err("%s: Illegal symbol entry '%s' (1)\n", | ||
145 | __func__, propcur); | ||
146 | err = -EINVAL; | 125 | err = -EINVAL; |
147 | goto err_fail; | 126 | goto err_fail; |
148 | } | 127 | } |
149 | *s++ = '\0'; | 128 | *s++ = '\0'; |
150 | 129 | ||
151 | propstr = s; | 130 | prop_name = s; |
152 | s = strchr(s, ':'); | 131 | s = strchr(s, ':'); |
153 | if (!s) { | 132 | if (!s) { |
154 | pr_err("%s: Illegal symbol entry '%s' (2)\n", | ||
155 | __func__, (char *)rprop->value); | ||
156 | err = -EINVAL; | 133 | err = -EINVAL; |
157 | goto err_fail; | 134 | goto err_fail; |
158 | } | 135 | } |
159 | |||
160 | *s++ = '\0'; | 136 | *s++ = '\0'; |
137 | |||
161 | err = kstrtoint(s, 10, &offset); | 138 | err = kstrtoint(s, 10, &offset); |
162 | if (err != 0) { | 139 | if (err) |
163 | pr_err("%s: Could get offset '%s'\n", | ||
164 | __func__, (char *)rprop->value); | ||
165 | goto err_fail; | 140 | goto err_fail; |
166 | } | ||
167 | 141 | ||
168 | /* look into the resolve node for the full path */ | 142 | refnode = find_node_by_full_name(overlay, node_path); |
169 | refnode = __of_find_node_by_full_name(node, nodestr); | 143 | if (!refnode) |
170 | if (!refnode) { | ||
171 | pr_warn("%s: Could not find refnode '%s'\n", | ||
172 | __func__, (char *)rprop->value); | ||
173 | continue; | 144 | continue; |
174 | } | ||
175 | 145 | ||
176 | /* now find the property */ | 146 | for_each_property_of_node(refnode, prop) { |
177 | for_each_property_of_node(refnode, sprop) { | 147 | if (!of_prop_cmp(prop->name, prop_name)) |
178 | if (of_prop_cmp(sprop->name, propstr) == 0) | ||
179 | break; | 148 | break; |
180 | } | 149 | } |
181 | of_node_put(refnode); | 150 | of_node_put(refnode); |
182 | 151 | ||
183 | if (!sprop) { | 152 | if (!prop) { |
184 | pr_err("%s: Could not find property '%s'\n", | ||
185 | __func__, (char *)rprop->value); | ||
186 | err = -ENOENT; | 153 | err = -ENOENT; |
187 | goto err_fail; | 154 | goto err_fail; |
188 | } | 155 | } |
189 | 156 | ||
190 | phandle = value; | 157 | *(__be32 *)(prop->value + offset) = cpu_to_be32(phandle); |
191 | *(__be32 *)(sprop->value + offset) = cpu_to_be32(phandle); | ||
192 | } | 158 | } |
193 | 159 | ||
194 | err_fail: | 160 | err_fail: |
195 | kfree(propval); | 161 | kfree(value); |
196 | return err; | 162 | return err; |
197 | } | 163 | } |
198 | 164 | ||
199 | /* compare nodes taking into account that 'name' strips out the @ part */ | 165 | /* compare nodes taking into account that 'name' strips out the @ part */ |
200 | static int __of_node_name_cmp(const struct device_node *dn1, | 166 | static int node_name_cmp(const struct device_node *dn1, |
201 | const struct device_node *dn2) | 167 | const struct device_node *dn2) |
202 | { | 168 | { |
203 | const char *n1 = strrchr(dn1->full_name, '/') ? : "/"; | 169 | const char *n1 = strrchr(dn1->full_name, '/') ? : "/"; |
@@ -208,85 +174,77 @@ static int __of_node_name_cmp(const struct device_node *dn1, | |||
208 | 174 | ||
209 | /* | 175 | /* |
210 | * Adjust the local phandle references by the given phandle delta. | 176 | * Adjust the local phandle references by the given phandle delta. |
211 | * Assumes the existances of a __local_fixups__ node at the root. | 177 | * |
212 | * Assumes that __of_verify_tree_phandle_references has been called. | 178 | * Subtree @local_fixups, which is overlay node __local_fixups__, |
213 | * Does not take any devtree locks so make sure you call this on a tree | 179 | * mirrors the fragment node structure at the root of the overlay. |
214 | * which is at the detached state. | 180 | * |
181 | * For each property in the fragments that contains a phandle reference, | ||
182 | * @local_fixups has a property of the same name that contains a list | ||
183 | * of offsets of the phandle reference(s) within the respective property | ||
184 | * value(s). The values at these offsets will be fixed up. | ||
215 | */ | 185 | */ |
216 | static int __of_adjust_tree_phandle_references(struct device_node *node, | 186 | static int adjust_local_phandle_references(struct device_node *local_fixups, |
217 | struct device_node *target, int phandle_delta) | 187 | struct device_node *overlay, int phandle_delta) |
218 | { | 188 | { |
219 | struct device_node *child, *childtarget; | 189 | struct device_node *child, *overlay_child; |
220 | struct property *rprop, *sprop; | 190 | struct property *prop_fix, *prop; |
221 | int err, i, count; | 191 | int err, i, count; |
222 | unsigned int off; | 192 | unsigned int off; |
223 | phandle phandle; | 193 | phandle phandle; |
224 | 194 | ||
225 | if (node == NULL) | 195 | if (!local_fixups) |
226 | return 0; | 196 | return 0; |
227 | 197 | ||
228 | for_each_property_of_node(node, rprop) { | 198 | for_each_property_of_node(local_fixups, prop_fix) { |
229 | 199 | ||
230 | /* skip properties added automatically */ | 200 | /* skip properties added automatically */ |
231 | if (of_prop_cmp(rprop->name, "name") == 0 || | 201 | if (!of_prop_cmp(prop_fix->name, "name") || |
232 | of_prop_cmp(rprop->name, "phandle") == 0 || | 202 | !of_prop_cmp(prop_fix->name, "phandle") || |
233 | of_prop_cmp(rprop->name, "linux,phandle") == 0) | 203 | !of_prop_cmp(prop_fix->name, "linux,phandle")) |
234 | continue; | 204 | continue; |
235 | 205 | ||
236 | if ((rprop->length % 4) != 0 || rprop->length == 0) { | 206 | if ((prop_fix->length % 4) != 0 || prop_fix->length == 0) |
237 | pr_err("%s: Illegal property (size) '%s' @%s\n", | ||
238 | __func__, rprop->name, node->full_name); | ||
239 | return -EINVAL; | 207 | return -EINVAL; |
240 | } | 208 | count = prop_fix->length / sizeof(__be32); |
241 | count = rprop->length / sizeof(__be32); | ||
242 | 209 | ||
243 | /* now find the target property */ | 210 | for_each_property_of_node(overlay, prop) { |
244 | for_each_property_of_node(target, sprop) { | 211 | if (!of_prop_cmp(prop->name, prop_fix->name)) |
245 | if (of_prop_cmp(sprop->name, rprop->name) == 0) | ||
246 | break; | 212 | break; |
247 | } | 213 | } |
248 | 214 | ||
249 | if (sprop == NULL) { | 215 | if (!prop) |
250 | pr_err("%s: Could not find target property '%s' @%s\n", | ||
251 | __func__, rprop->name, node->full_name); | ||
252 | return -EINVAL; | 216 | return -EINVAL; |
253 | } | ||
254 | 217 | ||
255 | for (i = 0; i < count; i++) { | 218 | for (i = 0; i < count; i++) { |
256 | off = be32_to_cpu(((__be32 *)rprop->value)[i]); | 219 | off = be32_to_cpu(((__be32 *)prop_fix->value)[i]); |
257 | /* make sure the offset doesn't overstep (even wrap) */ | 220 | if ((off + 4) > prop->length) |
258 | if (off >= sprop->length || | ||
259 | (off + 4) > sprop->length) { | ||
260 | pr_err("%s: Illegal property '%s' @%s\n", | ||
261 | __func__, rprop->name, | ||
262 | node->full_name); | ||
263 | return -EINVAL; | 221 | return -EINVAL; |
264 | } | 222 | |
265 | 223 | phandle = be32_to_cpu(*(__be32 *)(prop->value + off)); | |
266 | if (phandle_delta) { | 224 | phandle += phandle_delta; |
267 | /* adjust */ | 225 | *(__be32 *)(prop->value + off) = cpu_to_be32(phandle); |
268 | phandle = be32_to_cpu(*(__be32 *)(sprop->value + off)); | ||
269 | phandle += phandle_delta; | ||
270 | *(__be32 *)(sprop->value + off) = cpu_to_be32(phandle); | ||
271 | } | ||
272 | } | 226 | } |
273 | } | 227 | } |
274 | 228 | ||
275 | for_each_child_of_node(node, child) { | 229 | /* |
276 | 230 | * These nested loops recurse down two subtrees in parallel, where the | |
277 | for_each_child_of_node(target, childtarget) | 231 | * node names in the two subtrees match. |
278 | if (__of_node_name_cmp(child, childtarget) == 0) | 232 | * |
233 | * The roots of the subtrees are the overlay's __local_fixups__ node | ||
234 | * and the overlay's root node. | ||
235 | */ | ||
236 | for_each_child_of_node(local_fixups, child) { | ||
237 | |||
238 | for_each_child_of_node(overlay, overlay_child) | ||
239 | if (!node_name_cmp(child, overlay_child)) | ||
279 | break; | 240 | break; |
280 | 241 | ||
281 | if (!childtarget) { | 242 | if (!overlay_child) |
282 | pr_err("%s: Could not find target child '%s' @%s\n", | ||
283 | __func__, child->name, node->full_name); | ||
284 | return -EINVAL; | 243 | return -EINVAL; |
285 | } | ||
286 | 244 | ||
287 | err = __of_adjust_tree_phandle_references(child, childtarget, | 245 | err = adjust_local_phandle_references(child, overlay_child, |
288 | phandle_delta); | 246 | phandle_delta); |
289 | if (err != 0) | 247 | if (err) |
290 | return err; | 248 | return err; |
291 | } | 249 | } |
292 | 250 | ||
@@ -294,111 +252,103 @@ static int __of_adjust_tree_phandle_references(struct device_node *node, | |||
294 | } | 252 | } |
295 | 253 | ||
296 | /** | 254 | /** |
297 | * of_resolve - Resolve the given node against the live tree. | 255 | * of_resolve_phandles - Relocate and resolve overlay against live tree |
298 | * | 256 | * |
299 | * @resolve: Node to resolve | 257 | * @overlay: Pointer to devicetree overlay to relocate and resolve |
300 | * | 258 | * |
301 | * Perform dynamic Device Tree resolution against the live tree | 259 | * Modify (relocate) values of local phandles in @overlay to a range that |
302 | * to the given node to resolve. This depends on the live tree | 260 | * does not conflict with the live expanded devicetree. Update references |
303 | * having a __symbols__ node, and the resolve node the __fixups__ & | 261 | * to the local phandles in @overlay. Update (resolve) phandle references |
304 | * __local_fixups__ nodes (if needed). | 262 | * in @overlay that refer to the live expanded devicetree. |
305 | * The result of the operation is a resolve node that it's contents | 263 | * |
306 | * are fit to be inserted or operate upon the live tree. | 264 | * Phandle values in the live tree are in the range of |
307 | * Returns 0 on success or a negative error value on error. | 265 | * 1 .. live_tree_max_phandle(). The range of phandle values in the overlay |
266 | * also begin with at 1. Adjust the phandle values in the overlay to begin | ||
267 | * at live_tree_max_phandle() + 1. Update references to the phandles to | ||
268 | * the adjusted phandle values. | ||
269 | * | ||
270 | * The name of each property in the "__fixups__" node in the overlay matches | ||
271 | * the name of a symbol (a label) in the live tree. The values of each | ||
272 | * property in the "__fixups__" node is a list of the property values in the | ||
273 | * overlay that need to be updated to contain the phandle reference | ||
274 | * corresponding to that symbol in the live tree. Update the references in | ||
275 | * the overlay with the phandle values in the live tree. | ||
276 | * | ||
277 | * @overlay must be detached. | ||
278 | * | ||
279 | * Resolving and applying @overlay to the live expanded devicetree must be | ||
280 | * protected by a mechanism to ensure that multiple overlays are processed | ||
281 | * in a single threaded manner so that multiple overlays will not relocate | ||
282 | * phandles to overlapping ranges. The mechanism to enforce this is not | ||
283 | * yet implemented. | ||
284 | * | ||
285 | * Return: %0 on success or a negative error value on error. | ||
308 | */ | 286 | */ |
309 | int of_resolve_phandles(struct device_node *resolve) | 287 | int of_resolve_phandles(struct device_node *overlay) |
310 | { | 288 | { |
311 | struct device_node *child, *childroot, *refnode; | 289 | struct device_node *child, *local_fixups, *refnode; |
312 | struct device_node *root_sym, *resolve_sym, *resolve_fix; | 290 | struct device_node *tree_symbols, *overlay_fixups; |
313 | struct property *rprop; | 291 | struct property *prop; |
314 | const char *refpath; | 292 | const char *refpath; |
315 | phandle phandle, phandle_delta; | 293 | phandle phandle, phandle_delta; |
316 | int err; | 294 | int err; |
317 | 295 | ||
318 | if (!resolve) | 296 | tree_symbols = NULL; |
319 | pr_err("%s: null node\n", __func__); | ||
320 | if (resolve && !of_node_check_flag(resolve, OF_DETACHED)) | ||
321 | pr_err("%s: node %s not detached\n", __func__, | ||
322 | resolve->full_name); | ||
323 | /* the resolve node must exist, and be detached */ | ||
324 | if (!resolve || !of_node_check_flag(resolve, OF_DETACHED)) | ||
325 | return -EINVAL; | ||
326 | |||
327 | /* first we need to adjust the phandles */ | ||
328 | phandle_delta = of_get_tree_max_phandle() + 1; | ||
329 | __of_adjust_tree_phandles(resolve, phandle_delta); | ||
330 | |||
331 | /* locate the local fixups */ | ||
332 | childroot = NULL; | ||
333 | for_each_child_of_node(resolve, childroot) | ||
334 | if (of_node_cmp(childroot->name, "__local_fixups__") == 0) | ||
335 | break; | ||
336 | |||
337 | if (childroot != NULL) { | ||
338 | /* resolve root is guaranteed to be the '/' */ | ||
339 | err = __of_adjust_tree_phandle_references(childroot, | ||
340 | resolve, 0); | ||
341 | if (err != 0) | ||
342 | return err; | ||
343 | 297 | ||
344 | BUG_ON(__of_adjust_tree_phandle_references(childroot, | 298 | if (!overlay) { |
345 | resolve, phandle_delta)); | 299 | pr_err("null overlay\n"); |
300 | err = -EINVAL; | ||
301 | goto out; | ||
302 | } | ||
303 | if (!of_node_check_flag(overlay, OF_DETACHED)) { | ||
304 | pr_err("overlay not detached\n"); | ||
305 | err = -EINVAL; | ||
306 | goto out; | ||
346 | } | 307 | } |
347 | 308 | ||
348 | root_sym = NULL; | 309 | phandle_delta = live_tree_max_phandle() + 1; |
349 | resolve_sym = NULL; | 310 | adjust_overlay_phandles(overlay, phandle_delta); |
350 | resolve_fix = NULL; | ||
351 | |||
352 | /* this may fail (if no fixups are required) */ | ||
353 | root_sym = of_find_node_by_path("/__symbols__"); | ||
354 | 311 | ||
355 | /* locate the symbols & fixups nodes on resolve */ | 312 | for_each_child_of_node(overlay, local_fixups) |
356 | for_each_child_of_node(resolve, child) { | 313 | if (!of_node_cmp(local_fixups->name, "__local_fixups__")) |
314 | break; | ||
357 | 315 | ||
358 | if (!resolve_sym && | 316 | err = adjust_local_phandle_references(local_fixups, overlay, phandle_delta); |
359 | of_node_cmp(child->name, "__symbols__") == 0) | 317 | if (err) |
360 | resolve_sym = child; | 318 | goto out; |
361 | 319 | ||
362 | if (!resolve_fix && | 320 | overlay_fixups = NULL; |
363 | of_node_cmp(child->name, "__fixups__") == 0) | ||
364 | resolve_fix = child; | ||
365 | 321 | ||
366 | /* both found, don't bother anymore */ | 322 | for_each_child_of_node(overlay, child) { |
367 | if (resolve_sym && resolve_fix) | 323 | if (!of_node_cmp(child->name, "__fixups__")) |
368 | break; | 324 | overlay_fixups = child; |
369 | } | 325 | } |
370 | 326 | ||
371 | /* we do allow for the case where no fixups are needed */ | 327 | if (!overlay_fixups) { |
372 | if (!resolve_fix) { | 328 | err = 0; |
373 | err = 0; /* no error */ | ||
374 | goto out; | 329 | goto out; |
375 | } | 330 | } |
376 | 331 | ||
377 | /* we need to fixup, but no root symbols... */ | 332 | tree_symbols = of_find_node_by_path("/__symbols__"); |
378 | if (!root_sym) { | 333 | if (!tree_symbols) { |
379 | pr_err("%s: no symbols in root of device tree.\n", __func__); | 334 | pr_err("no symbols in root of device tree.\n"); |
380 | err = -EINVAL; | 335 | err = -EINVAL; |
381 | goto out; | 336 | goto out; |
382 | } | 337 | } |
383 | 338 | ||
384 | for_each_property_of_node(resolve_fix, rprop) { | 339 | for_each_property_of_node(overlay_fixups, prop) { |
385 | 340 | ||
386 | /* skip properties added automatically */ | 341 | /* skip properties added automatically */ |
387 | if (of_prop_cmp(rprop->name, "name") == 0) | 342 | if (!of_prop_cmp(prop->name, "name")) |
388 | continue; | 343 | continue; |
389 | 344 | ||
390 | err = of_property_read_string(root_sym, | 345 | err = of_property_read_string(tree_symbols, |
391 | rprop->name, &refpath); | 346 | prop->name, &refpath); |
392 | if (err != 0) { | 347 | if (err) |
393 | pr_err("%s: Could not find symbol '%s'\n", | ||
394 | __func__, rprop->name); | ||
395 | goto out; | 348 | goto out; |
396 | } | ||
397 | 349 | ||
398 | refnode = of_find_node_by_path(refpath); | 350 | refnode = of_find_node_by_path(refpath); |
399 | if (!refnode) { | 351 | if (!refnode) { |
400 | pr_err("%s: Could not find node by path '%s'\n", | ||
401 | __func__, refpath); | ||
402 | err = -ENOENT; | 352 | err = -ENOENT; |
403 | goto out; | 353 | goto out; |
404 | } | 354 | } |
@@ -406,17 +356,15 @@ int of_resolve_phandles(struct device_node *resolve) | |||
406 | phandle = refnode->phandle; | 356 | phandle = refnode->phandle; |
407 | of_node_put(refnode); | 357 | of_node_put(refnode); |
408 | 358 | ||
409 | pr_debug("%s: %s phandle is 0x%08x\n", | 359 | err = update_usages_of_a_phandle_reference(overlay, prop, phandle); |
410 | __func__, rprop->name, phandle); | ||
411 | |||
412 | err = __of_adjust_phandle_ref(resolve, rprop, phandle); | ||
413 | if (err) | 360 | if (err) |
414 | break; | 361 | break; |
415 | } | 362 | } |
416 | 363 | ||
417 | out: | 364 | out: |
418 | /* NULL is handled by of_node_put as NOP */ | 365 | if (err) |
419 | of_node_put(root_sym); | 366 | pr_err("overlay phandle fixup failed: %d\n", err); |
367 | of_node_put(tree_symbols); | ||
420 | 368 | ||
421 | return err; | 369 | return err; |
422 | } | 370 | } |