diff options
author | Pantelis Antoniou <pantelis.antoniou@konsulko.com> | 2014-07-04 12:58:47 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@linaro.org> | 2014-07-16 10:16:17 -0400 |
commit | 698433963b98d6de7b102c242805c99fda4fa1fb (patch) | |
tree | 05a223f160742f6659e47cd5accc245934c941ef /drivers/of | |
parent | 6afc0dc381573559251de9a8259404f49e6aed14 (diff) |
OF: Utility helper functions for dynamic nodes
Introduce helper functions for working with the live DT tree,
all of them related to dynamically adding/removing nodes and
properties.
__of_prop_dup() copies a property dynamically
__of_node_alloc() creates an empty node
Bug fix about prop->len == 0 by Ionut Nicu <ioan.nicu.ext@nsn.com>
Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
[glikely: Added unittest for of_copy_property and dropped fine-grained allocations]
[glikely: removed name, type and phandle arguments from __of_node_alloc]
Signed-off-by: Grant Likely <grant.likely@linaro.org>
Diffstat (limited to 'drivers/of')
-rw-r--r-- | drivers/of/dynamic.c | 77 | ||||
-rw-r--r-- | drivers/of/of_private.h | 10 | ||||
-rw-r--r-- | drivers/of/selftest.c | 28 |
3 files changed, 115 insertions, 0 deletions
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c index 125994330437..e0c4c6e25980 100644 --- a/drivers/of/dynamic.c +++ b/drivers/of/dynamic.c | |||
@@ -214,3 +214,80 @@ void of_node_release(struct kobject *kobj) | |||
214 | kfree(node->data); | 214 | kfree(node->data); |
215 | kfree(node); | 215 | kfree(node); |
216 | } | 216 | } |
217 | |||
218 | /** | ||
219 | * __of_prop_dup - Copy a property dynamically. | ||
220 | * @prop: Property to copy | ||
221 | * @allocflags: Allocation flags (typically pass GFP_KERNEL) | ||
222 | * | ||
223 | * Copy a property by dynamically allocating the memory of both the | ||
224 | * property stucture and the property name & contents. The property's | ||
225 | * flags have the OF_DYNAMIC bit set so that we can differentiate between | ||
226 | * dynamically allocated properties and not. | ||
227 | * Returns the newly allocated property or NULL on out of memory error. | ||
228 | */ | ||
229 | struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags) | ||
230 | { | ||
231 | struct property *new; | ||
232 | |||
233 | new = kzalloc(sizeof(*new), allocflags); | ||
234 | if (!new) | ||
235 | return NULL; | ||
236 | |||
237 | /* | ||
238 | * NOTE: There is no check for zero length value. | ||
239 | * In case of a boolean property This will allocate a value | ||
240 | * of zero bytes. We do this to work around the use | ||
241 | * of of_get_property() calls on boolean values. | ||
242 | */ | ||
243 | new->name = kstrdup(prop->name, allocflags); | ||
244 | new->value = kmemdup(prop->value, prop->length, allocflags); | ||
245 | new->length = prop->length; | ||
246 | if (!new->name || !new->value) | ||
247 | goto err_free; | ||
248 | |||
249 | /* mark the property as dynamic */ | ||
250 | of_property_set_flag(new, OF_DYNAMIC); | ||
251 | |||
252 | return new; | ||
253 | |||
254 | err_free: | ||
255 | kfree(new->name); | ||
256 | kfree(new->value); | ||
257 | kfree(new); | ||
258 | return NULL; | ||
259 | } | ||
260 | |||
261 | /** | ||
262 | * __of_node_alloc() - Create an empty device node dynamically. | ||
263 | * @full_name: Full name of the new device node | ||
264 | * @allocflags: Allocation flags (typically pass GFP_KERNEL) | ||
265 | * | ||
266 | * Create an empty device tree node, suitable for further modification. | ||
267 | * The node data are dynamically allocated and all the node flags | ||
268 | * have the OF_DYNAMIC & OF_DETACHED bits set. | ||
269 | * Returns the newly allocated node or NULL on out of memory error. | ||
270 | */ | ||
271 | struct device_node *__of_node_alloc(const char *full_name, gfp_t allocflags) | ||
272 | { | ||
273 | struct device_node *node; | ||
274 | |||
275 | node = kzalloc(sizeof(*node), allocflags); | ||
276 | if (!node) | ||
277 | return NULL; | ||
278 | |||
279 | node->full_name = kstrdup(full_name, allocflags); | ||
280 | of_node_set_flag(node, OF_DYNAMIC); | ||
281 | of_node_set_flag(node, OF_DETACHED); | ||
282 | if (!node->full_name) | ||
283 | goto err_free; | ||
284 | |||
285 | of_node_init(node); | ||
286 | |||
287 | return node; | ||
288 | |||
289 | err_free: | ||
290 | kfree(node->full_name); | ||
291 | kfree(node); | ||
292 | return NULL; | ||
293 | } | ||
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h index c270f2037779..1799ed2b3808 100644 --- a/drivers/of/of_private.h +++ b/drivers/of/of_private.h | |||
@@ -51,4 +51,14 @@ static inline int of_property_notify(int action, struct device_node *np, | |||
51 | } | 51 | } |
52 | #endif /* CONFIG_OF_DYNAMIC */ | 52 | #endif /* CONFIG_OF_DYNAMIC */ |
53 | 53 | ||
54 | /** | ||
55 | * General utilities for working with live trees. | ||
56 | * | ||
57 | * All functions with two leading underscores operate | ||
58 | * without taking node references, so you either have to | ||
59 | * own the devtree lock or work on detached trees only. | ||
60 | */ | ||
61 | struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags); | ||
62 | struct device_node *__of_node_alloc(const char *full_name, gfp_t allocflags); | ||
63 | |||
54 | #endif /* _LINUX_OF_PRIVATE_H */ | 64 | #endif /* _LINUX_OF_PRIVATE_H */ |
diff --git a/drivers/of/selftest.c b/drivers/of/selftest.c index 077314eebb95..ee2166f0f36a 100644 --- a/drivers/of/selftest.c +++ b/drivers/of/selftest.c | |||
@@ -16,6 +16,8 @@ | |||
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/device.h> | 17 | #include <linux/device.h> |
18 | 18 | ||
19 | #include "of_private.h" | ||
20 | |||
19 | static struct selftest_results { | 21 | static struct selftest_results { |
20 | int passed; | 22 | int passed; |
21 | int failed; | 23 | int failed; |
@@ -266,6 +268,31 @@ static void __init of_selftest_property_match_string(void) | |||
266 | selftest(rc == -EILSEQ, "unterminated string; rc=%i", rc); | 268 | selftest(rc == -EILSEQ, "unterminated string; rc=%i", rc); |
267 | } | 269 | } |
268 | 270 | ||
271 | #define propcmp(p1, p2) (((p1)->length == (p2)->length) && \ | ||
272 | (p1)->value && (p2)->value && \ | ||
273 | !memcmp((p1)->value, (p2)->value, (p1)->length) && \ | ||
274 | !strcmp((p1)->name, (p2)->name)) | ||
275 | static void __init of_selftest_property_copy(void) | ||
276 | { | ||
277 | #ifdef CONFIG_OF_DYNAMIC | ||
278 | struct property p1 = { .name = "p1", .length = 0, .value = "" }; | ||
279 | struct property p2 = { .name = "p2", .length = 5, .value = "abcd" }; | ||
280 | struct property *new; | ||
281 | |||
282 | new = __of_prop_dup(&p1, GFP_KERNEL); | ||
283 | selftest(new && propcmp(&p1, new), "empty property didn't copy correctly\n"); | ||
284 | kfree(new->value); | ||
285 | kfree(new->name); | ||
286 | kfree(new); | ||
287 | |||
288 | new = __of_prop_dup(&p2, GFP_KERNEL); | ||
289 | selftest(new && propcmp(&p2, new), "non-empty property didn't copy correctly\n"); | ||
290 | kfree(new->value); | ||
291 | kfree(new->name); | ||
292 | kfree(new); | ||
293 | #endif | ||
294 | } | ||
295 | |||
269 | static void __init of_selftest_parse_interrupts(void) | 296 | static void __init of_selftest_parse_interrupts(void) |
270 | { | 297 | { |
271 | struct device_node *np; | 298 | struct device_node *np; |
@@ -533,6 +560,7 @@ static int __init of_selftest(void) | |||
533 | of_selftest_dynamic(); | 560 | of_selftest_dynamic(); |
534 | of_selftest_parse_phandle_with_args(); | 561 | of_selftest_parse_phandle_with_args(); |
535 | of_selftest_property_match_string(); | 562 | of_selftest_property_match_string(); |
563 | of_selftest_property_copy(); | ||
536 | of_selftest_parse_interrupts(); | 564 | of_selftest_parse_interrupts(); |
537 | of_selftest_parse_interrupts_extended(); | 565 | of_selftest_parse_interrupts_extended(); |
538 | of_selftest_match_node(); | 566 | of_selftest_match_node(); |