diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-11 16:06:58 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-11 16:06:58 -0500 |
commit | 7ef58b32f571bffb7763c6252ad7527562081f34 (patch) | |
tree | 6d1493304ec7a47e4d9e3e84dc9f6e53547dff91 /drivers/of/dynamic.c | |
parent | 413fd0e3fbf52873f2310eb75bfa6c7b72847277 (diff) | |
parent | c46ca3c8310b61d253a39ff1375ea97912794cd1 (diff) |
Merge tag 'devicetree-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/glikely/linux
Pull devicetree changes from Grant Likely:
"Lots of activity in the devicetree code for v3.18. Most of it is
related to getting all of the overlay support code in place, but there
are other important things in there.
Highlights:
- OF_RECONFIG notifiers for SPI, I2C and Platform devices. Those
subsystems can now respond to live changes to the device tree.
- CONFIG_OF_OVERLAY method for applying live changes to the device
tree
- Removal of the of_allnodes list. This used to be used to iterate
over all the nodes in the device tree, but it is unnecessary
because the same thing can be done by iterating over the list of
child pointers. Getting rid of of_allnodes saves some memory and
avoids the possibility of of_allnodes being sorted differently from
the child lists.
- Support for retrieving original DTB blob via sysfs. Needed by
kexec.
- More unittests
- Documentation and minor bug fixes"
* tag 'devicetree-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/glikely/linux: (42 commits)
of: Delete unnecessary check before calling "of_node_put()"
of: Drop ->next pointer from struct device_node
spi: Check for spi_of_notifier when CONFIG_OF_DYNAMIC=y
of: support passing console options with stdout-path
of: add optional options parameter to of_find_node_by_path()
of: Add bindings for chosen node, stdout-path
of: Remove unneeded and incorrect MODULE_DEVICE_TABLE
ARM: dt: fix up PL011 device tree bindings
of: base, fix of_property_read_string_helper kernel-doc
of: remove select of non-existant OF_DEVICE config symbol
spi/of: Add OF notifier handler
spi/of: Create new device registration method and accessors
i2c/of: Add OF_RECONFIG notifier handler
i2c/of: Factor out Devicetree registration code
of/overlay: Add overlay unittests
of/overlay: Introduce DT overlay support
of/reconfig: Add OF_DYNAMIC notifier for platform_bus_type
of/reconfig: Always use the same structure for notifiers
of/reconfig: Add debug output for OF_RECONFIG notifiers
of/reconfig: Add empty stubs for the of_reconfig methods
...
Diffstat (limited to 'drivers/of/dynamic.c')
-rw-r--r-- | drivers/of/dynamic.c | 218 |
1 files changed, 168 insertions, 50 deletions
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c index d4994177dec2..3351ef408125 100644 --- a/drivers/of/dynamic.c +++ b/drivers/of/dynamic.c | |||
@@ -77,18 +77,132 @@ int of_reconfig_notifier_unregister(struct notifier_block *nb) | |||
77 | } | 77 | } |
78 | EXPORT_SYMBOL_GPL(of_reconfig_notifier_unregister); | 78 | EXPORT_SYMBOL_GPL(of_reconfig_notifier_unregister); |
79 | 79 | ||
80 | int of_reconfig_notify(unsigned long action, void *p) | 80 | #ifdef DEBUG |
81 | const char *action_names[] = { | ||
82 | [OF_RECONFIG_ATTACH_NODE] = "ATTACH_NODE", | ||
83 | [OF_RECONFIG_DETACH_NODE] = "DETACH_NODE", | ||
84 | [OF_RECONFIG_ADD_PROPERTY] = "ADD_PROPERTY", | ||
85 | [OF_RECONFIG_REMOVE_PROPERTY] = "REMOVE_PROPERTY", | ||
86 | [OF_RECONFIG_UPDATE_PROPERTY] = "UPDATE_PROPERTY", | ||
87 | }; | ||
88 | #endif | ||
89 | |||
90 | int of_reconfig_notify(unsigned long action, struct of_reconfig_data *p) | ||
81 | { | 91 | { |
82 | int rc; | 92 | int rc; |
93 | #ifdef DEBUG | ||
94 | struct of_reconfig_data *pr = p; | ||
95 | |||
96 | switch (action) { | ||
97 | case OF_RECONFIG_ATTACH_NODE: | ||
98 | case OF_RECONFIG_DETACH_NODE: | ||
99 | pr_debug("of/notify %-15s %s\n", action_names[action], | ||
100 | pr->dn->full_name); | ||
101 | break; | ||
102 | case OF_RECONFIG_ADD_PROPERTY: | ||
103 | case OF_RECONFIG_REMOVE_PROPERTY: | ||
104 | case OF_RECONFIG_UPDATE_PROPERTY: | ||
105 | pr_debug("of/notify %-15s %s:%s\n", action_names[action], | ||
106 | pr->dn->full_name, pr->prop->name); | ||
107 | break; | ||
83 | 108 | ||
109 | } | ||
110 | #endif | ||
84 | rc = blocking_notifier_call_chain(&of_reconfig_chain, action, p); | 111 | rc = blocking_notifier_call_chain(&of_reconfig_chain, action, p); |
85 | return notifier_to_errno(rc); | 112 | return notifier_to_errno(rc); |
86 | } | 113 | } |
87 | 114 | ||
115 | /* | ||
116 | * of_reconfig_get_state_change() - Returns new state of device | ||
117 | * @action - action of the of notifier | ||
118 | * @arg - argument of the of notifier | ||
119 | * | ||
120 | * Returns the new state of a device based on the notifier used. | ||
121 | * Returns 0 on device going from enabled to disabled, 1 on device | ||
122 | * going from disabled to enabled and -1 on no change. | ||
123 | */ | ||
124 | int of_reconfig_get_state_change(unsigned long action, struct of_reconfig_data *pr) | ||
125 | { | ||
126 | struct property *prop, *old_prop = NULL; | ||
127 | int is_status, status_state, old_status_state, prev_state, new_state; | ||
128 | |||
129 | /* figure out if a device should be created or destroyed */ | ||
130 | switch (action) { | ||
131 | case OF_RECONFIG_ATTACH_NODE: | ||
132 | case OF_RECONFIG_DETACH_NODE: | ||
133 | prop = of_find_property(pr->dn, "status", NULL); | ||
134 | break; | ||
135 | case OF_RECONFIG_ADD_PROPERTY: | ||
136 | case OF_RECONFIG_REMOVE_PROPERTY: | ||
137 | prop = pr->prop; | ||
138 | break; | ||
139 | case OF_RECONFIG_UPDATE_PROPERTY: | ||
140 | prop = pr->prop; | ||
141 | old_prop = pr->old_prop; | ||
142 | break; | ||
143 | default: | ||
144 | return OF_RECONFIG_NO_CHANGE; | ||
145 | } | ||
146 | |||
147 | is_status = 0; | ||
148 | status_state = -1; | ||
149 | old_status_state = -1; | ||
150 | prev_state = -1; | ||
151 | new_state = -1; | ||
152 | |||
153 | if (prop && !strcmp(prop->name, "status")) { | ||
154 | is_status = 1; | ||
155 | status_state = !strcmp(prop->value, "okay") || | ||
156 | !strcmp(prop->value, "ok"); | ||
157 | if (old_prop) | ||
158 | old_status_state = !strcmp(old_prop->value, "okay") || | ||
159 | !strcmp(old_prop->value, "ok"); | ||
160 | } | ||
161 | |||
162 | switch (action) { | ||
163 | case OF_RECONFIG_ATTACH_NODE: | ||
164 | prev_state = 0; | ||
165 | /* -1 & 0 status either missing or okay */ | ||
166 | new_state = status_state != 0; | ||
167 | break; | ||
168 | case OF_RECONFIG_DETACH_NODE: | ||
169 | /* -1 & 0 status either missing or okay */ | ||
170 | prev_state = status_state != 0; | ||
171 | new_state = 0; | ||
172 | break; | ||
173 | case OF_RECONFIG_ADD_PROPERTY: | ||
174 | if (is_status) { | ||
175 | /* no status property -> enabled (legacy) */ | ||
176 | prev_state = 1; | ||
177 | new_state = status_state; | ||
178 | } | ||
179 | break; | ||
180 | case OF_RECONFIG_REMOVE_PROPERTY: | ||
181 | if (is_status) { | ||
182 | prev_state = status_state; | ||
183 | /* no status property -> enabled (legacy) */ | ||
184 | new_state = 1; | ||
185 | } | ||
186 | break; | ||
187 | case OF_RECONFIG_UPDATE_PROPERTY: | ||
188 | if (is_status) { | ||
189 | prev_state = old_status_state != 0; | ||
190 | new_state = status_state != 0; | ||
191 | } | ||
192 | break; | ||
193 | } | ||
194 | |||
195 | if (prev_state == new_state) | ||
196 | return OF_RECONFIG_NO_CHANGE; | ||
197 | |||
198 | return new_state ? OF_RECONFIG_CHANGE_ADD : OF_RECONFIG_CHANGE_REMOVE; | ||
199 | } | ||
200 | EXPORT_SYMBOL_GPL(of_reconfig_get_state_change); | ||
201 | |||
88 | int of_property_notify(int action, struct device_node *np, | 202 | int of_property_notify(int action, struct device_node *np, |
89 | struct property *prop, struct property *oldprop) | 203 | struct property *prop, struct property *oldprop) |
90 | { | 204 | { |
91 | struct of_prop_reconfig pr; | 205 | struct of_reconfig_data pr; |
92 | 206 | ||
93 | /* only call notifiers if the node is attached */ | 207 | /* only call notifiers if the node is attached */ |
94 | if (!of_node_is_attached(np)) | 208 | if (!of_node_is_attached(np)) |
@@ -117,8 +231,6 @@ void __of_attach_node(struct device_node *np) | |||
117 | 231 | ||
118 | np->child = NULL; | 232 | np->child = NULL; |
119 | np->sibling = np->parent->child; | 233 | np->sibling = np->parent->child; |
120 | np->allnext = np->parent->allnext; | ||
121 | np->parent->allnext = np; | ||
122 | np->parent->child = np; | 234 | np->parent->child = np; |
123 | of_node_clear_flag(np, OF_DETACHED); | 235 | of_node_clear_flag(np, OF_DETACHED); |
124 | } | 236 | } |
@@ -128,8 +240,12 @@ void __of_attach_node(struct device_node *np) | |||
128 | */ | 240 | */ |
129 | int of_attach_node(struct device_node *np) | 241 | int of_attach_node(struct device_node *np) |
130 | { | 242 | { |
243 | struct of_reconfig_data rd; | ||
131 | unsigned long flags; | 244 | unsigned long flags; |
132 | 245 | ||
246 | memset(&rd, 0, sizeof(rd)); | ||
247 | rd.dn = np; | ||
248 | |||
133 | mutex_lock(&of_mutex); | 249 | mutex_lock(&of_mutex); |
134 | raw_spin_lock_irqsave(&devtree_lock, flags); | 250 | raw_spin_lock_irqsave(&devtree_lock, flags); |
135 | __of_attach_node(np); | 251 | __of_attach_node(np); |
@@ -138,7 +254,7 @@ int of_attach_node(struct device_node *np) | |||
138 | __of_attach_node_sysfs(np); | 254 | __of_attach_node_sysfs(np); |
139 | mutex_unlock(&of_mutex); | 255 | mutex_unlock(&of_mutex); |
140 | 256 | ||
141 | of_reconfig_notify(OF_RECONFIG_ATTACH_NODE, np); | 257 | of_reconfig_notify(OF_RECONFIG_ATTACH_NODE, &rd); |
142 | 258 | ||
143 | return 0; | 259 | return 0; |
144 | } | 260 | } |
@@ -154,17 +270,6 @@ void __of_detach_node(struct device_node *np) | |||
154 | if (WARN_ON(!parent)) | 270 | if (WARN_ON(!parent)) |
155 | return; | 271 | return; |
156 | 272 | ||
157 | if (of_allnodes == np) | ||
158 | of_allnodes = np->allnext; | ||
159 | else { | ||
160 | struct device_node *prev; | ||
161 | for (prev = of_allnodes; | ||
162 | prev->allnext != np; | ||
163 | prev = prev->allnext) | ||
164 | ; | ||
165 | prev->allnext = np->allnext; | ||
166 | } | ||
167 | |||
168 | if (parent->child == np) | 273 | if (parent->child == np) |
169 | parent->child = np->sibling; | 274 | parent->child = np->sibling; |
170 | else { | 275 | else { |
@@ -187,9 +292,13 @@ void __of_detach_node(struct device_node *np) | |||
187 | */ | 292 | */ |
188 | int of_detach_node(struct device_node *np) | 293 | int of_detach_node(struct device_node *np) |
189 | { | 294 | { |
295 | struct of_reconfig_data rd; | ||
190 | unsigned long flags; | 296 | unsigned long flags; |
191 | int rc = 0; | 297 | int rc = 0; |
192 | 298 | ||
299 | memset(&rd, 0, sizeof(rd)); | ||
300 | rd.dn = np; | ||
301 | |||
193 | mutex_lock(&of_mutex); | 302 | mutex_lock(&of_mutex); |
194 | raw_spin_lock_irqsave(&devtree_lock, flags); | 303 | raw_spin_lock_irqsave(&devtree_lock, flags); |
195 | __of_detach_node(np); | 304 | __of_detach_node(np); |
@@ -198,7 +307,7 @@ int of_detach_node(struct device_node *np) | |||
198 | __of_detach_node_sysfs(np); | 307 | __of_detach_node_sysfs(np); |
199 | mutex_unlock(&of_mutex); | 308 | mutex_unlock(&of_mutex); |
200 | 309 | ||
201 | of_reconfig_notify(OF_RECONFIG_DETACH_NODE, np); | 310 | of_reconfig_notify(OF_RECONFIG_DETACH_NODE, &rd); |
202 | 311 | ||
203 | return rc; | 312 | return rc; |
204 | } | 313 | } |
@@ -285,36 +394,54 @@ struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags) | |||
285 | } | 394 | } |
286 | 395 | ||
287 | /** | 396 | /** |
288 | * __of_node_alloc() - Create an empty device node dynamically. | 397 | * __of_node_dup() - Duplicate or create an empty device node dynamically. |
289 | * @full_name: Full name of the new device node | 398 | * @fmt: Format string (plus vargs) for new full name of the device node |
290 | * @allocflags: Allocation flags (typically pass GFP_KERNEL) | ||
291 | * | 399 | * |
292 | * Create an empty device tree node, suitable for further modification. | 400 | * Create an device tree node, either by duplicating an empty node or by allocating |
293 | * The node data are dynamically allocated and all the node flags | 401 | * an empty one suitable for further modification. The node data are |
294 | * have the OF_DYNAMIC & OF_DETACHED bits set. | 402 | * dynamically allocated and all the node flags have the OF_DYNAMIC & |
295 | * Returns the newly allocated node or NULL on out of memory error. | 403 | * OF_DETACHED bits set. Returns the newly allocated node or NULL on out of |
404 | * memory error. | ||
296 | */ | 405 | */ |
297 | struct device_node *__of_node_alloc(const char *full_name, gfp_t allocflags) | 406 | struct device_node *__of_node_dup(const struct device_node *np, const char *fmt, ...) |
298 | { | 407 | { |
408 | va_list vargs; | ||
299 | struct device_node *node; | 409 | struct device_node *node; |
300 | 410 | ||
301 | node = kzalloc(sizeof(*node), allocflags); | 411 | node = kzalloc(sizeof(*node), GFP_KERNEL); |
302 | if (!node) | 412 | if (!node) |
303 | return NULL; | 413 | return NULL; |
414 | va_start(vargs, fmt); | ||
415 | node->full_name = kvasprintf(GFP_KERNEL, fmt, vargs); | ||
416 | va_end(vargs); | ||
417 | if (!node->full_name) { | ||
418 | kfree(node); | ||
419 | return NULL; | ||
420 | } | ||
304 | 421 | ||
305 | node->full_name = kstrdup(full_name, allocflags); | ||
306 | of_node_set_flag(node, OF_DYNAMIC); | 422 | of_node_set_flag(node, OF_DYNAMIC); |
307 | of_node_set_flag(node, OF_DETACHED); | 423 | of_node_set_flag(node, OF_DETACHED); |
308 | if (!node->full_name) | ||
309 | goto err_free; | ||
310 | |||
311 | of_node_init(node); | 424 | of_node_init(node); |
312 | 425 | ||
426 | /* Iterate over and duplicate all properties */ | ||
427 | if (np) { | ||
428 | struct property *pp, *new_pp; | ||
429 | for_each_property_of_node(np, pp) { | ||
430 | new_pp = __of_prop_dup(pp, GFP_KERNEL); | ||
431 | if (!new_pp) | ||
432 | goto err_prop; | ||
433 | if (__of_add_property(node, new_pp)) { | ||
434 | kfree(new_pp->name); | ||
435 | kfree(new_pp->value); | ||
436 | kfree(new_pp); | ||
437 | goto err_prop; | ||
438 | } | ||
439 | } | ||
440 | } | ||
313 | return node; | 441 | return node; |
314 | 442 | ||
315 | err_free: | 443 | err_prop: |
316 | kfree(node->full_name); | 444 | of_node_put(node); /* Frees the node and properties */ |
317 | kfree(node); | ||
318 | return NULL; | 445 | return NULL; |
319 | } | 446 | } |
320 | 447 | ||
@@ -330,27 +457,15 @@ static void __of_changeset_entry_dump(struct of_changeset_entry *ce) | |||
330 | { | 457 | { |
331 | switch (ce->action) { | 458 | switch (ce->action) { |
332 | case OF_RECONFIG_ADD_PROPERTY: | 459 | case OF_RECONFIG_ADD_PROPERTY: |
333 | pr_debug("%p: %s %s/%s\n", | ||
334 | ce, "ADD_PROPERTY ", ce->np->full_name, | ||
335 | ce->prop->name); | ||
336 | break; | ||
337 | case OF_RECONFIG_REMOVE_PROPERTY: | 460 | case OF_RECONFIG_REMOVE_PROPERTY: |
338 | pr_debug("%p: %s %s/%s\n", | ||
339 | ce, "REMOVE_PROPERTY", ce->np->full_name, | ||
340 | ce->prop->name); | ||
341 | break; | ||
342 | case OF_RECONFIG_UPDATE_PROPERTY: | 461 | case OF_RECONFIG_UPDATE_PROPERTY: |
343 | pr_debug("%p: %s %s/%s\n", | 462 | pr_debug("of/cset<%p> %-15s %s/%s\n", ce, action_names[ce->action], |
344 | ce, "UPDATE_PROPERTY", ce->np->full_name, | 463 | ce->np->full_name, ce->prop->name); |
345 | ce->prop->name); | ||
346 | break; | 464 | break; |
347 | case OF_RECONFIG_ATTACH_NODE: | 465 | case OF_RECONFIG_ATTACH_NODE: |
348 | pr_debug("%p: %s %s\n", | ||
349 | ce, "ATTACH_NODE ", ce->np->full_name); | ||
350 | break; | ||
351 | case OF_RECONFIG_DETACH_NODE: | 466 | case OF_RECONFIG_DETACH_NODE: |
352 | pr_debug("%p: %s %s\n", | 467 | pr_debug("of/cset<%p> %-15s %s\n", ce, action_names[ce->action], |
353 | ce, "DETACH_NODE ", ce->np->full_name); | 468 | ce->np->full_name); |
354 | break; | 469 | break; |
355 | } | 470 | } |
356 | } | 471 | } |
@@ -388,6 +503,7 @@ static void __of_changeset_entry_invert(struct of_changeset_entry *ce, | |||
388 | 503 | ||
389 | static void __of_changeset_entry_notify(struct of_changeset_entry *ce, bool revert) | 504 | static void __of_changeset_entry_notify(struct of_changeset_entry *ce, bool revert) |
390 | { | 505 | { |
506 | struct of_reconfig_data rd; | ||
391 | struct of_changeset_entry ce_inverted; | 507 | struct of_changeset_entry ce_inverted; |
392 | int ret; | 508 | int ret; |
393 | 509 | ||
@@ -399,7 +515,9 @@ static void __of_changeset_entry_notify(struct of_changeset_entry *ce, bool reve | |||
399 | switch (ce->action) { | 515 | switch (ce->action) { |
400 | case OF_RECONFIG_ATTACH_NODE: | 516 | case OF_RECONFIG_ATTACH_NODE: |
401 | case OF_RECONFIG_DETACH_NODE: | 517 | case OF_RECONFIG_DETACH_NODE: |
402 | ret = of_reconfig_notify(ce->action, ce->np); | 518 | memset(&rd, 0, sizeof(rd)); |
519 | rd.dn = ce->np; | ||
520 | ret = of_reconfig_notify(ce->action, &rd); | ||
403 | break; | 521 | break; |
404 | case OF_RECONFIG_ADD_PROPERTY: | 522 | case OF_RECONFIG_ADD_PROPERTY: |
405 | case OF_RECONFIG_REMOVE_PROPERTY: | 523 | case OF_RECONFIG_REMOVE_PROPERTY: |