Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : /*
3 : : * Software nodes for the firmware node framework.
4 : : *
5 : : * Copyright (C) 2018, Intel Corporation
6 : : * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
7 : : */
8 : :
9 : : #include <linux/device.h>
10 : : #include <linux/kernel.h>
11 : : #include <linux/property.h>
12 : : #include <linux/slab.h>
13 : :
14 : : struct swnode {
15 : : int id;
16 : : struct kobject kobj;
17 : : struct fwnode_handle fwnode;
18 : : const struct software_node *node;
19 : :
20 : : /* hierarchy */
21 : : struct ida child_ids;
22 : : struct list_head entry;
23 : : struct list_head children;
24 : : struct swnode *parent;
25 : :
26 : : unsigned int allocated:1;
27 : : };
28 : :
29 : : static DEFINE_IDA(swnode_root_ids);
30 : : static struct kset *swnode_kset;
31 : :
32 : : #define kobj_to_swnode(_kobj_) container_of(_kobj_, struct swnode, kobj)
33 : :
34 : : static const struct fwnode_operations software_node_ops;
35 : :
36 : 2808 : bool is_software_node(const struct fwnode_handle *fwnode)
37 : : {
38 [ + - + - : 2808 : return !IS_ERR_OR_NULL(fwnode) && fwnode->ops == &software_node_ops;
- + - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - - -
- - - -
- ]
39 : : }
40 : : EXPORT_SYMBOL_GPL(is_software_node);
41 : :
42 : : #define to_swnode(__fwnode) \
43 : : ({ \
44 : : typeof(__fwnode) __to_swnode_fwnode = __fwnode; \
45 : : \
46 : : is_software_node(__to_swnode_fwnode) ? \
47 : : container_of(__to_swnode_fwnode, \
48 : : struct swnode, fwnode) : NULL; \
49 : : })
50 : :
51 : : static struct swnode *
52 : 0 : software_node_to_swnode(const struct software_node *node)
53 : : {
54 : 0 : struct swnode *swnode = NULL;
55 : 0 : struct kobject *k;
56 : :
57 [ # # ]: 0 : if (!node)
58 : : return NULL;
59 : :
60 : 0 : spin_lock(&swnode_kset->list_lock);
61 : :
62 [ # # ]: 0 : list_for_each_entry(k, &swnode_kset->list, entry) {
63 : 0 : swnode = kobj_to_swnode(k);
64 [ # # ]: 0 : if (swnode->node == node)
65 : : break;
66 : 0 : swnode = NULL;
67 : : }
68 : :
69 : 0 : spin_unlock(&swnode_kset->list_lock);
70 : :
71 : 0 : return swnode;
72 : : }
73 : :
74 : 0 : const struct software_node *to_software_node(const struct fwnode_handle *fwnode)
75 : : {
76 [ # # # # ]: 0 : const struct swnode *swnode = to_swnode(fwnode);
77 : :
78 [ # # ]: 0 : return swnode ? swnode->node : NULL;
79 : : }
80 : : EXPORT_SYMBOL_GPL(to_software_node);
81 : :
82 : 0 : struct fwnode_handle *software_node_fwnode(const struct software_node *node)
83 : : {
84 : 0 : struct swnode *swnode = software_node_to_swnode(node);
85 : :
86 [ # # # # ]: 0 : return swnode ? &swnode->fwnode : NULL;
87 : : }
88 : : EXPORT_SYMBOL_GPL(software_node_fwnode);
89 : :
90 : : /* -------------------------------------------------------------------------- */
91 : : /* property_entry processing */
92 : :
93 : : static const struct property_entry *
94 : 0 : property_entry_get(const struct property_entry *prop, const char *name)
95 : : {
96 [ # # ]: 0 : if (!prop)
97 : : return NULL;
98 : :
99 [ # # ]: 0 : for (; prop->name; prop++)
100 [ # # ]: 0 : if (!strcmp(name, prop->name))
101 : 0 : return prop;
102 : :
103 : : return NULL;
104 : : }
105 : :
106 : 0 : static const void *property_get_pointer(const struct property_entry *prop)
107 : : {
108 : 0 : if (!prop->length)
109 : : return NULL;
110 : :
111 [ # # # # : 0 : return prop->is_inline ? &prop->value : prop->pointer;
# # ]
112 : : }
113 : :
114 : 0 : static const void *property_entry_find(const struct property_entry *props,
115 : : const char *propname, size_t length)
116 : : {
117 : 0 : const struct property_entry *prop;
118 : 0 : const void *pointer;
119 : :
120 : 0 : prop = property_entry_get(props, propname);
121 [ # # ]: 0 : if (!prop)
122 : : return ERR_PTR(-EINVAL);
123 [ # # ]: 0 : pointer = property_get_pointer(prop);
124 [ # # ]: 0 : if (!pointer)
125 : : return ERR_PTR(-ENODATA);
126 [ # # ]: 0 : if (length > prop->length)
127 : 0 : return ERR_PTR(-EOVERFLOW);
128 : : return pointer;
129 : : }
130 : :
131 : : static int
132 : 0 : property_entry_count_elems_of_size(const struct property_entry *props,
133 : : const char *propname, size_t length)
134 : : {
135 : 0 : const struct property_entry *prop;
136 : :
137 : 0 : prop = property_entry_get(props, propname);
138 [ # # # # ]: 0 : if (!prop)
139 : : return -EINVAL;
140 : :
141 : 0 : return prop->length / length;
142 : : }
143 : :
144 : 0 : static int property_entry_read_int_array(const struct property_entry *props,
145 : : const char *name,
146 : : unsigned int elem_size, void *val,
147 : : size_t nval)
148 : : {
149 : 0 : const void *pointer;
150 : 0 : size_t length;
151 : :
152 [ # # ]: 0 : if (!val)
153 : 0 : return property_entry_count_elems_of_size(props, name,
154 : : elem_size);
155 : :
156 [ # # # # : 0 : if (!is_power_of_2(elem_size) || elem_size > sizeof(u64))
# # ]
157 : : return -ENXIO;
158 : :
159 : 0 : length = nval * elem_size;
160 : :
161 : 0 : pointer = property_entry_find(props, name, length);
162 [ # # ]: 0 : if (IS_ERR(pointer))
163 : 0 : return PTR_ERR(pointer);
164 : :
165 : 0 : memcpy(val, pointer, length);
166 : 0 : return 0;
167 : : }
168 : :
169 : 0 : static int property_entry_read_string_array(const struct property_entry *props,
170 : : const char *propname,
171 : : const char **strings, size_t nval)
172 : : {
173 : 0 : const void *pointer;
174 : 0 : size_t length;
175 : 0 : int array_len;
176 : :
177 : : /* Find out the array length. */
178 : 0 : array_len = property_entry_count_elems_of_size(props, propname,
179 : : sizeof(const char *));
180 [ # # ]: 0 : if (array_len < 0)
181 : 0 : return array_len;
182 : :
183 : : /* Return how many there are if strings is NULL. */
184 [ # # ]: 0 : if (!strings)
185 : : return array_len;
186 : :
187 : 0 : array_len = min_t(size_t, nval, array_len);
188 : 0 : length = array_len * sizeof(*strings);
189 : :
190 : 0 : pointer = property_entry_find(props, propname, length);
191 [ # # ]: 0 : if (IS_ERR(pointer))
192 : 0 : return PTR_ERR(pointer);
193 : :
194 : 0 : memcpy(strings, pointer, length);
195 : :
196 : 0 : return array_len;
197 : : }
198 : :
199 : 0 : static void property_entry_free_data(const struct property_entry *p)
200 : : {
201 : 0 : const char * const *src_str;
202 : 0 : size_t i, nval;
203 : :
204 [ # # ]: 0 : if (p->type == DEV_PROP_STRING) {
205 [ # # ]: 0 : src_str = property_get_pointer(p);
206 : 0 : nval = p->length / sizeof(*src_str);
207 [ # # ]: 0 : for (i = 0; i < nval; i++)
208 : 0 : kfree(src_str[i]);
209 : : }
210 : :
211 [ # # ]: 0 : if (!p->is_inline)
212 : 0 : kfree(p->pointer);
213 : :
214 : 0 : kfree(p->name);
215 : 0 : }
216 : :
217 : 0 : static bool property_copy_string_array(const char **dst_ptr,
218 : : const char * const *src_ptr,
219 : : size_t nval)
220 : : {
221 : 0 : int i;
222 : :
223 [ # # ]: 0 : for (i = 0; i < nval; i++) {
224 : 0 : dst_ptr[i] = kstrdup(src_ptr[i], GFP_KERNEL);
225 [ # # # # ]: 0 : if (!dst_ptr[i] && src_ptr[i]) {
226 [ # # ]: 0 : while (--i >= 0)
227 : 0 : kfree(dst_ptr[i]);
228 : : return false;
229 : : }
230 : : }
231 : :
232 : : return true;
233 : : }
234 : :
235 : 0 : static int property_entry_copy_data(struct property_entry *dst,
236 : : const struct property_entry *src)
237 : : {
238 [ # # ]: 0 : const void *pointer = property_get_pointer(src);
239 : 0 : void *dst_ptr;
240 : 0 : size_t nval;
241 : :
242 : : /*
243 : : * Properties with no data should not be marked as stored
244 : : * out of line.
245 : : */
246 [ # # # # ]: 0 : if (!src->is_inline && !src->length)
247 : : return -ENODATA;
248 : :
249 : : /*
250 : : * Reference properties are never stored inline as
251 : : * they are too big.
252 : : */
253 [ # # # # ]: 0 : if (src->type == DEV_PROP_REF && src->is_inline)
254 : : return -EINVAL;
255 : :
256 [ # # ]: 0 : if (src->length <= sizeof(dst->value)) {
257 : 0 : dst_ptr = &dst->value;
258 : 0 : dst->is_inline = true;
259 : : } else {
260 [ # # ]: 0 : dst_ptr = kmalloc(src->length, GFP_KERNEL);
261 [ # # ]: 0 : if (!dst_ptr)
262 : : return -ENOMEM;
263 : 0 : dst->pointer = dst_ptr;
264 : : }
265 : :
266 [ # # ]: 0 : if (src->type == DEV_PROP_STRING) {
267 : 0 : nval = src->length / sizeof(const char *);
268 [ # # ]: 0 : if (!property_copy_string_array(dst_ptr, pointer, nval)) {
269 [ # # ]: 0 : if (!dst->is_inline)
270 : 0 : kfree(dst->pointer);
271 : 0 : return -ENOMEM;
272 : : }
273 : : } else {
274 : 0 : memcpy(dst_ptr, pointer, src->length);
275 : : }
276 : :
277 : 0 : dst->length = src->length;
278 : 0 : dst->type = src->type;
279 : 0 : dst->name = kstrdup(src->name, GFP_KERNEL);
280 [ # # ]: 0 : if (!dst->name) {
281 : 0 : property_entry_free_data(dst);
282 : 0 : return -ENOMEM;
283 : : }
284 : :
285 : : return 0;
286 : : }
287 : :
288 : : /**
289 : : * property_entries_dup - duplicate array of properties
290 : : * @properties: array of properties to copy
291 : : *
292 : : * This function creates a deep copy of the given NULL-terminated array
293 : : * of property entries.
294 : : */
295 : : struct property_entry *
296 : 0 : property_entries_dup(const struct property_entry *properties)
297 : : {
298 : 0 : struct property_entry *p;
299 : 0 : int i, n = 0;
300 : 0 : int ret;
301 : :
302 [ # # ]: 0 : if (!properties)
303 : : return NULL;
304 : :
305 [ # # ]: 0 : while (properties[n].name)
306 : 0 : n++;
307 : :
308 : 0 : p = kcalloc(n + 1, sizeof(*p), GFP_KERNEL);
309 [ # # ]: 0 : if (!p)
310 : : return ERR_PTR(-ENOMEM);
311 : :
312 [ # # ]: 0 : for (i = 0; i < n; i++) {
313 : 0 : ret = property_entry_copy_data(&p[i], &properties[i]);
314 [ # # ]: 0 : if (ret) {
315 [ # # ]: 0 : while (--i >= 0)
316 : 0 : property_entry_free_data(&p[i]);
317 : 0 : kfree(p);
318 : 0 : return ERR_PTR(ret);
319 : : }
320 : : }
321 : :
322 : : return p;
323 : : }
324 : : EXPORT_SYMBOL_GPL(property_entries_dup);
325 : :
326 : : /**
327 : : * property_entries_free - free previously allocated array of properties
328 : : * @properties: array of properties to destroy
329 : : *
330 : : * This function frees given NULL-terminated array of property entries,
331 : : * along with their data.
332 : : */
333 : 0 : void property_entries_free(const struct property_entry *properties)
334 : : {
335 : 0 : const struct property_entry *p;
336 : :
337 [ # # ]: 0 : if (!properties)
338 : : return;
339 : :
340 [ # # ]: 0 : for (p = properties; p->name; p++)
341 : 0 : property_entry_free_data(p);
342 : :
343 : 0 : kfree(properties);
344 : : }
345 : : EXPORT_SYMBOL_GPL(property_entries_free);
346 : :
347 : : /* -------------------------------------------------------------------------- */
348 : : /* fwnode operations */
349 : :
350 : 0 : static struct fwnode_handle *software_node_get(struct fwnode_handle *fwnode)
351 : : {
352 [ # # # # ]: 0 : struct swnode *swnode = to_swnode(fwnode);
353 : :
354 : 0 : kobject_get(&swnode->kobj);
355 : :
356 : 0 : return &swnode->fwnode;
357 : : }
358 : :
359 : 0 : static void software_node_put(struct fwnode_handle *fwnode)
360 : : {
361 [ # # # # ]: 0 : struct swnode *swnode = to_swnode(fwnode);
362 : :
363 : 0 : kobject_put(&swnode->kobj);
364 : 0 : }
365 : :
366 : 0 : static bool software_node_property_present(const struct fwnode_handle *fwnode,
367 : : const char *propname)
368 : : {
369 [ # # # # ]: 0 : struct swnode *swnode = to_swnode(fwnode);
370 : :
371 : 0 : return !!property_entry_get(swnode->node->properties, propname);
372 : : }
373 : :
374 : 0 : static int software_node_read_int_array(const struct fwnode_handle *fwnode,
375 : : const char *propname,
376 : : unsigned int elem_size, void *val,
377 : : size_t nval)
378 : : {
379 [ # # # # ]: 0 : struct swnode *swnode = to_swnode(fwnode);
380 : :
381 : 0 : return property_entry_read_int_array(swnode->node->properties, propname,
382 : : elem_size, val, nval);
383 : : }
384 : :
385 : 0 : static int software_node_read_string_array(const struct fwnode_handle *fwnode,
386 : : const char *propname,
387 : : const char **val, size_t nval)
388 : : {
389 [ # # # # ]: 0 : struct swnode *swnode = to_swnode(fwnode);
390 : :
391 : 0 : return property_entry_read_string_array(swnode->node->properties,
392 : : propname, val, nval);
393 : : }
394 : :
395 : : static const char *
396 : 0 : software_node_get_name(const struct fwnode_handle *fwnode)
397 : : {
398 [ # # # # ]: 0 : const struct swnode *swnode = to_swnode(fwnode);
399 : :
400 [ # # ]: 0 : if (!swnode)
401 : : return "(null)";
402 : :
403 : 0 : return kobject_name(&swnode->kobj);
404 : : }
405 : :
406 : : static const char *
407 : 0 : software_node_get_name_prefix(const struct fwnode_handle *fwnode)
408 : : {
409 : 0 : struct fwnode_handle *parent;
410 : 0 : const char *prefix;
411 : :
412 : 0 : parent = fwnode_get_parent(fwnode);
413 [ # # ]: 0 : if (!parent)
414 : : return "";
415 : :
416 : : /* Figure out the prefix from the parents. */
417 [ # # # # ]: 0 : while (is_software_node(parent))
418 : 0 : parent = fwnode_get_next_parent(parent);
419 : :
420 : 0 : prefix = fwnode_get_name_prefix(parent);
421 : 0 : fwnode_handle_put(parent);
422 : :
423 : : /* Guess something if prefix was NULL. */
424 [ # # ]: 0 : return prefix ?: "/";
425 : : }
426 : :
427 : : static struct fwnode_handle *
428 : 0 : software_node_get_parent(const struct fwnode_handle *fwnode)
429 : : {
430 [ # # # # ]: 0 : struct swnode *swnode = to_swnode(fwnode);
431 : :
432 [ # # # # ]: 0 : if (!swnode || !swnode->parent)
433 : : return NULL;
434 : :
435 : 0 : return fwnode_handle_get(&swnode->parent->fwnode);
436 : : }
437 : :
438 : : static struct fwnode_handle *
439 : 0 : software_node_get_next_child(const struct fwnode_handle *fwnode,
440 : : struct fwnode_handle *child)
441 : : {
442 [ # # # # ]: 0 : struct swnode *p = to_swnode(fwnode);
443 [ # # # # ]: 0 : struct swnode *c = to_swnode(child);
444 : :
445 [ # # # # : 0 : if (!p || list_empty(&p->children) ||
# # ]
446 [ # # ]: 0 : (c && list_is_last(&c->entry, &p->children)))
447 : : return NULL;
448 : :
449 [ # # ]: 0 : if (c)
450 : 0 : c = list_next_entry(c, entry);
451 : : else
452 : 0 : c = list_first_entry(&p->children, struct swnode, entry);
453 : 0 : return &c->fwnode;
454 : : }
455 : :
456 : : static struct fwnode_handle *
457 : 0 : software_node_get_named_child_node(const struct fwnode_handle *fwnode,
458 : : const char *childname)
459 : : {
460 [ # # # # ]: 0 : struct swnode *swnode = to_swnode(fwnode);
461 : 0 : struct swnode *child;
462 : :
463 [ # # # # ]: 0 : if (!swnode || list_empty(&swnode->children))
464 : : return NULL;
465 : :
466 [ # # ]: 0 : list_for_each_entry(child, &swnode->children, entry) {
467 [ # # ]: 0 : if (!strcmp(childname, kobject_name(&child->kobj))) {
468 : 0 : kobject_get(&child->kobj);
469 : 0 : return &child->fwnode;
470 : : }
471 : : }
472 : : return NULL;
473 : : }
474 : :
475 : : static int
476 : 0 : software_node_get_reference_args(const struct fwnode_handle *fwnode,
477 : : const char *propname, const char *nargs_prop,
478 : : unsigned int nargs, unsigned int index,
479 : : struct fwnode_reference_args *args)
480 : : {
481 [ # # # # ]: 0 : struct swnode *swnode = to_swnode(fwnode);
482 : 0 : const struct software_node_ref_args *ref_array;
483 : 0 : const struct software_node_ref_args *ref;
484 : 0 : const struct property_entry *prop;
485 : 0 : struct fwnode_handle *refnode;
486 : 0 : u32 nargs_prop_val;
487 : 0 : int error;
488 : 0 : int i;
489 : :
490 [ # # ]: 0 : if (!swnode)
491 : : return -ENOENT;
492 : :
493 : 0 : prop = property_entry_get(swnode->node->properties, propname);
494 [ # # ]: 0 : if (!prop)
495 : : return -ENOENT;
496 : :
497 [ # # ]: 0 : if (prop->type != DEV_PROP_REF)
498 : : return -EINVAL;
499 : :
500 : : /*
501 : : * We expect that references are never stored inline, even
502 : : * single ones, as they are too big.
503 : : */
504 [ # # ]: 0 : if (prop->is_inline)
505 : : return -EINVAL;
506 : :
507 [ # # ]: 0 : if (index * sizeof(*ref) >= prop->length)
508 : : return -ENOENT;
509 : :
510 : 0 : ref_array = prop->pointer;
511 : 0 : ref = &ref_array[index];
512 : :
513 : 0 : refnode = software_node_fwnode(ref->node);
514 [ # # ]: 0 : if (!refnode)
515 : : return -ENOENT;
516 : :
517 [ # # ]: 0 : if (nargs_prop) {
518 : 0 : error = property_entry_read_int_array(swnode->node->properties,
519 : : nargs_prop, sizeof(u32),
520 : : &nargs_prop_val, 1);
521 [ # # ]: 0 : if (error)
522 : : return error;
523 : :
524 : 0 : nargs = nargs_prop_val;
525 : : }
526 : :
527 [ # # ]: 0 : if (nargs > NR_FWNODE_REFERENCE_ARGS)
528 : : return -EINVAL;
529 : :
530 : 0 : args->fwnode = software_node_get(refnode);
531 : 0 : args->nargs = nargs;
532 : :
533 [ # # ]: 0 : for (i = 0; i < nargs; i++)
534 : 0 : args->args[i] = ref->args[i];
535 : :
536 : : return 0;
537 : : }
538 : :
539 : : static const struct fwnode_operations software_node_ops = {
540 : : .get = software_node_get,
541 : : .put = software_node_put,
542 : : .property_present = software_node_property_present,
543 : : .property_read_int_array = software_node_read_int_array,
544 : : .property_read_string_array = software_node_read_string_array,
545 : : .get_name = software_node_get_name,
546 : : .get_name_prefix = software_node_get_name_prefix,
547 : : .get_parent = software_node_get_parent,
548 : : .get_next_child_node = software_node_get_next_child,
549 : : .get_named_child_node = software_node_get_named_child_node,
550 : : .get_reference_args = software_node_get_reference_args
551 : : };
552 : :
553 : : /* -------------------------------------------------------------------------- */
554 : :
555 : : /**
556 : : * software_node_find_by_name - Find software node by name
557 : : * @parent: Parent of the software node
558 : : * @name: Name of the software node
559 : : *
560 : : * The function will find a node that is child of @parent and that is named
561 : : * @name. If no node is found, the function returns NULL.
562 : : *
563 : : * NOTE: you will need to drop the reference with fwnode_handle_put() after use.
564 : : */
565 : : const struct software_node *
566 : 0 : software_node_find_by_name(const struct software_node *parent, const char *name)
567 : : {
568 : 0 : struct swnode *swnode = NULL;
569 : 0 : struct kobject *k;
570 : :
571 [ # # ]: 0 : if (!name)
572 : : return NULL;
573 : :
574 : 0 : spin_lock(&swnode_kset->list_lock);
575 : :
576 [ # # ]: 0 : list_for_each_entry(k, &swnode_kset->list, entry) {
577 : 0 : swnode = kobj_to_swnode(k);
578 [ # # # # ]: 0 : if (parent == swnode->node->parent && swnode->node->name &&
579 [ # # ]: 0 : !strcmp(name, swnode->node->name)) {
580 : 0 : kobject_get(&swnode->kobj);
581 : 0 : break;
582 : : }
583 : 0 : swnode = NULL;
584 : : }
585 : :
586 : 0 : spin_unlock(&swnode_kset->list_lock);
587 : :
588 [ # # ]: 0 : return swnode ? swnode->node : NULL;
589 : : }
590 : : EXPORT_SYMBOL_GPL(software_node_find_by_name);
591 : :
592 : : static int
593 : 0 : software_node_register_properties(struct software_node *node,
594 : : const struct property_entry *properties)
595 : : {
596 : 0 : struct property_entry *props;
597 : :
598 : 0 : props = property_entries_dup(properties);
599 [ # # ]: 0 : if (IS_ERR(props))
600 [ # # ]: 0 : return PTR_ERR(props);
601 : :
602 : 0 : node->properties = props;
603 : :
604 : 0 : return 0;
605 : : }
606 : :
607 : 0 : static void software_node_release(struct kobject *kobj)
608 : : {
609 : 0 : struct swnode *swnode = kobj_to_swnode(kobj);
610 : :
611 [ # # ]: 0 : if (swnode->parent) {
612 : 0 : ida_simple_remove(&swnode->parent->child_ids, swnode->id);
613 : 0 : list_del(&swnode->entry);
614 : : } else {
615 : 0 : ida_simple_remove(&swnode_root_ids, swnode->id);
616 : : }
617 : :
618 [ # # ]: 0 : if (swnode->allocated) {
619 : 0 : property_entries_free(swnode->node->properties);
620 : 0 : kfree(swnode->node);
621 : : }
622 : 0 : ida_destroy(&swnode->child_ids);
623 : 0 : kfree(swnode);
624 : 0 : }
625 : :
626 : : static struct kobj_type software_node_type = {
627 : : .release = software_node_release,
628 : : .sysfs_ops = &kobj_sysfs_ops,
629 : : };
630 : :
631 : : static struct fwnode_handle *
632 : 0 : swnode_register(const struct software_node *node, struct swnode *parent,
633 : : unsigned int allocated)
634 : : {
635 : 0 : struct swnode *swnode;
636 : 0 : int ret;
637 : :
638 : 0 : swnode = kzalloc(sizeof(*swnode), GFP_KERNEL);
639 [ # # ]: 0 : if (!swnode) {
640 : 0 : ret = -ENOMEM;
641 : 0 : goto out_err;
642 : : }
643 : :
644 [ # # ]: 0 : ret = ida_simple_get(parent ? &parent->child_ids : &swnode_root_ids,
645 : : 0, 0, GFP_KERNEL);
646 [ # # ]: 0 : if (ret < 0) {
647 : 0 : kfree(swnode);
648 : 0 : goto out_err;
649 : : }
650 : :
651 : 0 : swnode->id = ret;
652 : 0 : swnode->node = node;
653 : 0 : swnode->parent = parent;
654 : 0 : swnode->allocated = allocated;
655 : 0 : swnode->kobj.kset = swnode_kset;
656 : 0 : swnode->fwnode.ops = &software_node_ops;
657 : :
658 [ # # ]: 0 : ida_init(&swnode->child_ids);
659 [ # # ]: 0 : INIT_LIST_HEAD(&swnode->entry);
660 : 0 : INIT_LIST_HEAD(&swnode->children);
661 : :
662 [ # # ]: 0 : if (node->name)
663 [ # # ]: 0 : ret = kobject_init_and_add(&swnode->kobj, &software_node_type,
664 : : parent ? &parent->kobj : NULL,
665 : : "%s", node->name);
666 : : else
667 [ # # ]: 0 : ret = kobject_init_and_add(&swnode->kobj, &software_node_type,
668 : : parent ? &parent->kobj : NULL,
669 : : "node%d", swnode->id);
670 [ # # ]: 0 : if (ret) {
671 : 0 : kobject_put(&swnode->kobj);
672 : 0 : return ERR_PTR(ret);
673 : : }
674 : :
675 [ # # ]: 0 : if (parent)
676 : 0 : list_add_tail(&swnode->entry, &parent->children);
677 : :
678 : 0 : kobject_uevent(&swnode->kobj, KOBJ_ADD);
679 : 0 : return &swnode->fwnode;
680 : :
681 : 0 : out_err:
682 [ # # ]: 0 : if (allocated)
683 : 0 : property_entries_free(node->properties);
684 : 0 : return ERR_PTR(ret);
685 : : }
686 : :
687 : : /**
688 : : * software_node_register_nodes - Register an array of software nodes
689 : : * @nodes: Zero terminated array of software nodes to be registered
690 : : *
691 : : * Register multiple software nodes at once.
692 : : */
693 : 0 : int software_node_register_nodes(const struct software_node *nodes)
694 : : {
695 : 0 : int ret;
696 : 0 : int i;
697 : :
698 [ # # ]: 0 : for (i = 0; nodes[i].name; i++) {
699 : 0 : ret = software_node_register(&nodes[i]);
700 [ # # ]: 0 : if (ret) {
701 : 0 : software_node_unregister_nodes(nodes);
702 : 0 : return ret;
703 : : }
704 : : }
705 : :
706 : : return 0;
707 : : }
708 : : EXPORT_SYMBOL_GPL(software_node_register_nodes);
709 : :
710 : : /**
711 : : * software_node_unregister_nodes - Unregister an array of software nodes
712 : : * @nodes: Zero terminated array of software nodes to be unregistered
713 : : *
714 : : * Unregister multiple software nodes at once.
715 : : */
716 : 0 : void software_node_unregister_nodes(const struct software_node *nodes)
717 : : {
718 : 0 : struct swnode *swnode;
719 : 0 : int i;
720 : :
721 [ # # ]: 0 : for (i = 0; nodes[i].name; i++) {
722 : 0 : swnode = software_node_to_swnode(&nodes[i]);
723 [ # # ]: 0 : if (swnode)
724 : 0 : fwnode_remove_software_node(&swnode->fwnode);
725 : : }
726 : 0 : }
727 : : EXPORT_SYMBOL_GPL(software_node_unregister_nodes);
728 : :
729 : : /**
730 : : * software_node_register - Register static software node
731 : : * @node: The software node to be registered
732 : : */
733 : 0 : int software_node_register(const struct software_node *node)
734 : : {
735 : 0 : struct swnode *parent = software_node_to_swnode(node->parent);
736 : :
737 [ # # ]: 0 : if (software_node_to_swnode(node))
738 : : return -EEXIST;
739 : :
740 : 0 : return PTR_ERR_OR_ZERO(swnode_register(node, parent, 0));
741 : : }
742 : : EXPORT_SYMBOL_GPL(software_node_register);
743 : :
744 : : struct fwnode_handle *
745 : 0 : fwnode_create_software_node(const struct property_entry *properties,
746 : : const struct fwnode_handle *parent)
747 : : {
748 : 0 : struct software_node *node;
749 : 0 : struct swnode *p = NULL;
750 : 0 : int ret;
751 : :
752 [ # # ]: 0 : if (parent) {
753 [ # # ]: 0 : if (IS_ERR(parent))
754 : : return ERR_CAST(parent);
755 [ # # # # ]: 0 : if (!is_software_node(parent))
756 : : return ERR_PTR(-EINVAL);
757 [ # # # # ]: 0 : p = to_swnode(parent);
758 : : }
759 : :
760 : 0 : node = kzalloc(sizeof(*node), GFP_KERNEL);
761 [ # # ]: 0 : if (!node)
762 : : return ERR_PTR(-ENOMEM);
763 : :
764 : 0 : ret = software_node_register_properties(node, properties);
765 [ # # ]: 0 : if (ret) {
766 : 0 : kfree(node);
767 : 0 : return ERR_PTR(ret);
768 : : }
769 : :
770 [ # # ]: 0 : node->parent = p ? p->node : NULL;
771 : :
772 : 0 : return swnode_register(node, p, 1);
773 : : }
774 : : EXPORT_SYMBOL_GPL(fwnode_create_software_node);
775 : :
776 : 0 : void fwnode_remove_software_node(struct fwnode_handle *fwnode)
777 : : {
778 [ # # # # ]: 0 : struct swnode *swnode = to_swnode(fwnode);
779 : :
780 [ # # ]: 0 : if (!swnode)
781 : : return;
782 : :
783 : 0 : kobject_put(&swnode->kobj);
784 : : }
785 : : EXPORT_SYMBOL_GPL(fwnode_remove_software_node);
786 : :
787 : 24012 : int software_node_notify(struct device *dev, unsigned long action)
788 : : {
789 : 24012 : struct fwnode_handle *fwnode = dev_fwnode(dev);
790 : 24012 : struct swnode *swnode;
791 : 24012 : int ret;
792 : :
793 [ + + ]: 24012 : if (!fwnode)
794 : : return 0;
795 : :
796 [ + - + - ]: 2808 : if (!is_software_node(fwnode))
797 : 1404 : fwnode = fwnode->secondary;
798 [ - + - + ]: 2808 : if (!is_software_node(fwnode))
799 : : return 0;
800 : :
801 [ # # # # ]: 0 : swnode = to_swnode(fwnode);
802 : :
803 [ # # # ]: 0 : switch (action) {
804 : 0 : case KOBJ_ADD:
805 : 0 : ret = sysfs_create_link(&dev->kobj, &swnode->kobj,
806 : : "software_node");
807 [ # # ]: 0 : if (ret)
808 : : break;
809 : :
810 [ # # ]: 0 : ret = sysfs_create_link(&swnode->kobj, &dev->kobj,
811 : : dev_name(dev));
812 [ # # ]: 0 : if (ret) {
813 : 0 : sysfs_remove_link(&dev->kobj, "software_node");
814 : 0 : break;
815 : : }
816 : 0 : kobject_get(&swnode->kobj);
817 : 0 : break;
818 : : case KOBJ_REMOVE:
819 [ # # ]: 0 : sysfs_remove_link(&swnode->kobj, dev_name(dev));
820 : 0 : sysfs_remove_link(&dev->kobj, "software_node");
821 : 0 : kobject_put(&swnode->kobj);
822 : 0 : break;
823 : : default:
824 : : break;
825 : : }
826 : :
827 : 0 : return 0;
828 : : }
829 : :
830 : 78 : static int __init software_node_init(void)
831 : : {
832 : 78 : swnode_kset = kset_create_and_add("software_nodes", NULL, kernel_kobj);
833 [ - + ]: 78 : if (!swnode_kset)
834 : 0 : return -ENOMEM;
835 : : return 0;
836 : : }
837 : : postcore_initcall(software_node_init);
838 : :
839 : 0 : static void __exit software_node_exit(void)
840 : : {
841 : 0 : ida_destroy(&swnode_root_ids);
842 : 0 : kset_unregister(swnode_kset);
843 : 0 : }
844 : : __exitcall(software_node_exit);
|