blob: f41692e0f63be4252404ebe29d1470ad8436955c [file] [log] [blame]
Heikki Krogerus59abd832018-11-09 17:21:36 +03001// 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
Heikki Krogerus80488a62019-05-31 17:15:34 +030014struct swnode {
Heikki Krogerus59abd832018-11-09 17:21:36 +030015 int id;
16 struct kobject kobj;
17 struct fwnode_handle fwnode;
Heikki Krogerus80488a62019-05-31 17:15:34 +030018 const struct software_node *node;
Heikki Krogerus59abd832018-11-09 17:21:36 +030019
20 /* hierarchy */
21 struct ida child_ids;
22 struct list_head entry;
23 struct list_head children;
Heikki Krogerus80488a62019-05-31 17:15:34 +030024 struct swnode *parent;
Heikki Krogerus59abd832018-11-09 17:21:36 +030025
Heikki Krogerus80488a62019-05-31 17:15:34 +030026 unsigned int allocated:1;
Heikki Krogerus59abd832018-11-09 17:21:36 +030027};
28
29static DEFINE_IDA(swnode_root_ids);
30static struct kset *swnode_kset;
31
Heikki Krogerus80488a62019-05-31 17:15:34 +030032#define kobj_to_swnode(_kobj_) container_of(_kobj_, struct swnode, kobj)
Heikki Krogerus59abd832018-11-09 17:21:36 +030033
34static const struct fwnode_operations software_node_ops;
35
36bool is_software_node(const struct fwnode_handle *fwnode)
37{
38 return !IS_ERR_OR_NULL(fwnode) && fwnode->ops == &software_node_ops;
39}
Heikki Krogerus80488a62019-05-31 17:15:34 +030040EXPORT_SYMBOL_GPL(is_software_node);
Heikki Krogerus59abd832018-11-09 17:21:36 +030041
Heikki Krogerus80488a62019-05-31 17:15:34 +030042#define to_swnode(__fwnode) \
Heikki Krogerus59abd832018-11-09 17:21:36 +030043 ({ \
Heikki Krogerus80488a62019-05-31 17:15:34 +030044 typeof(__fwnode) __to_swnode_fwnode = __fwnode; \
Heikki Krogerus59abd832018-11-09 17:21:36 +030045 \
Heikki Krogerus80488a62019-05-31 17:15:34 +030046 is_software_node(__to_swnode_fwnode) ? \
47 container_of(__to_swnode_fwnode, \
48 struct swnode, fwnode) : NULL; \
Heikki Krogerus59abd832018-11-09 17:21:36 +030049 })
50
Heikki Krogerus80488a62019-05-31 17:15:34 +030051static struct swnode *
52software_node_to_swnode(const struct software_node *node)
53{
Heikki Krogerus61636872019-08-30 10:51:55 +030054 struct swnode *swnode = NULL;
Heikki Krogerus80488a62019-05-31 17:15:34 +030055 struct kobject *k;
56
57 if (!node)
58 return NULL;
59
60 spin_lock(&swnode_kset->list_lock);
61
62 list_for_each_entry(k, &swnode_kset->list, entry) {
63 swnode = kobj_to_swnode(k);
64 if (swnode->node == node)
65 break;
66 swnode = NULL;
67 }
68
69 spin_unlock(&swnode_kset->list_lock);
70
71 return swnode;
72}
73
Sakari Ailus56c9aa02019-10-03 15:32:09 +030074const struct software_node *to_software_node(const struct fwnode_handle *fwnode)
Heikki Krogerus80488a62019-05-31 17:15:34 +030075{
Sakari Ailus56c9aa02019-10-03 15:32:09 +030076 const struct swnode *swnode = to_swnode(fwnode);
Heikki Krogerus80488a62019-05-31 17:15:34 +030077
78 return swnode ? swnode->node : NULL;
79}
80EXPORT_SYMBOL_GPL(to_software_node);
81
82struct fwnode_handle *software_node_fwnode(const struct software_node *node)
83{
84 struct swnode *swnode = software_node_to_swnode(node);
85
86 return swnode ? &swnode->fwnode : NULL;
87}
88EXPORT_SYMBOL_GPL(software_node_fwnode);
89
Heikki Krogerus59abd832018-11-09 17:21:36 +030090/* -------------------------------------------------------------------------- */
91/* property_entry processing */
92
93static const struct property_entry *
94property_entry_get(const struct property_entry *prop, const char *name)
95{
96 if (!prop)
97 return NULL;
98
99 for (; prop->name; prop++)
100 if (!strcmp(name, prop->name))
101 return prop;
102
103 return NULL;
104}
105
Heikki Krogerused1cdf32018-11-09 17:21:37 +0300106static void
107property_set_pointer(struct property_entry *prop, const void *pointer)
108{
109 switch (prop->type) {
110 case DEV_PROP_U8:
111 if (prop->is_array)
112 prop->pointer.u8_data = pointer;
113 else
114 prop->value.u8_data = *((u8 *)pointer);
115 break;
116 case DEV_PROP_U16:
117 if (prop->is_array)
118 prop->pointer.u16_data = pointer;
119 else
120 prop->value.u16_data = *((u16 *)pointer);
121 break;
122 case DEV_PROP_U32:
123 if (prop->is_array)
124 prop->pointer.u32_data = pointer;
125 else
126 prop->value.u32_data = *((u32 *)pointer);
127 break;
128 case DEV_PROP_U64:
129 if (prop->is_array)
130 prop->pointer.u64_data = pointer;
131 else
132 prop->value.u64_data = *((u64 *)pointer);
133 break;
134 case DEV_PROP_STRING:
135 if (prop->is_array)
136 prop->pointer.str = pointer;
137 else
138 prop->value.str = pointer;
139 break;
140 default:
141 break;
142 }
143}
144
Heikki Krogerus59abd832018-11-09 17:21:36 +0300145static const void *property_get_pointer(const struct property_entry *prop)
146{
147 switch (prop->type) {
148 case DEV_PROP_U8:
149 if (prop->is_array)
150 return prop->pointer.u8_data;
151 return &prop->value.u8_data;
152 case DEV_PROP_U16:
153 if (prop->is_array)
154 return prop->pointer.u16_data;
155 return &prop->value.u16_data;
156 case DEV_PROP_U32:
157 if (prop->is_array)
158 return prop->pointer.u32_data;
159 return &prop->value.u32_data;
160 case DEV_PROP_U64:
161 if (prop->is_array)
162 return prop->pointer.u64_data;
163 return &prop->value.u64_data;
164 case DEV_PROP_STRING:
165 if (prop->is_array)
166 return prop->pointer.str;
167 return &prop->value.str;
168 default:
169 return NULL;
170 }
171}
172
173static const void *property_entry_find(const struct property_entry *props,
174 const char *propname, size_t length)
175{
176 const struct property_entry *prop;
177 const void *pointer;
178
179 prop = property_entry_get(props, propname);
180 if (!prop)
181 return ERR_PTR(-EINVAL);
182 pointer = property_get_pointer(prop);
183 if (!pointer)
184 return ERR_PTR(-ENODATA);
185 if (length > prop->length)
186 return ERR_PTR(-EOVERFLOW);
187 return pointer;
188}
189
190static int property_entry_read_u8_array(const struct property_entry *props,
191 const char *propname,
192 u8 *values, size_t nval)
193{
194 const void *pointer;
195 size_t length = nval * sizeof(*values);
196
197 pointer = property_entry_find(props, propname, length);
198 if (IS_ERR(pointer))
199 return PTR_ERR(pointer);
200
201 memcpy(values, pointer, length);
202 return 0;
203}
204
205static int property_entry_read_u16_array(const struct property_entry *props,
206 const char *propname,
207 u16 *values, size_t nval)
208{
209 const void *pointer;
210 size_t length = nval * sizeof(*values);
211
212 pointer = property_entry_find(props, propname, length);
213 if (IS_ERR(pointer))
214 return PTR_ERR(pointer);
215
216 memcpy(values, pointer, length);
217 return 0;
218}
219
220static int property_entry_read_u32_array(const struct property_entry *props,
221 const char *propname,
222 u32 *values, size_t nval)
223{
224 const void *pointer;
225 size_t length = nval * sizeof(*values);
226
227 pointer = property_entry_find(props, propname, length);
228 if (IS_ERR(pointer))
229 return PTR_ERR(pointer);
230
231 memcpy(values, pointer, length);
232 return 0;
233}
234
235static int property_entry_read_u64_array(const struct property_entry *props,
236 const char *propname,
237 u64 *values, size_t nval)
238{
239 const void *pointer;
240 size_t length = nval * sizeof(*values);
241
242 pointer = property_entry_find(props, propname, length);
243 if (IS_ERR(pointer))
244 return PTR_ERR(pointer);
245
246 memcpy(values, pointer, length);
247 return 0;
248}
249
250static int
251property_entry_count_elems_of_size(const struct property_entry *props,
252 const char *propname, size_t length)
253{
254 const struct property_entry *prop;
255
256 prop = property_entry_get(props, propname);
257 if (!prop)
258 return -EINVAL;
259
260 return prop->length / length;
261}
262
263static int property_entry_read_int_array(const struct property_entry *props,
264 const char *name,
265 unsigned int elem_size, void *val,
266 size_t nval)
267{
268 if (!val)
269 return property_entry_count_elems_of_size(props, name,
270 elem_size);
271 switch (elem_size) {
272 case sizeof(u8):
273 return property_entry_read_u8_array(props, name, val, nval);
274 case sizeof(u16):
275 return property_entry_read_u16_array(props, name, val, nval);
276 case sizeof(u32):
277 return property_entry_read_u32_array(props, name, val, nval);
278 case sizeof(u64):
279 return property_entry_read_u64_array(props, name, val, nval);
280 }
281
282 return -ENXIO;
283}
284
285static int property_entry_read_string_array(const struct property_entry *props,
286 const char *propname,
287 const char **strings, size_t nval)
288{
289 const struct property_entry *prop;
290 const void *pointer;
291 size_t array_len, length;
292
293 /* Find out the array length. */
294 prop = property_entry_get(props, propname);
295 if (!prop)
296 return -EINVAL;
297
298 if (prop->is_array)
299 /* Find the length of an array. */
300 array_len = property_entry_count_elems_of_size(props, propname,
301 sizeof(const char *));
302 else
303 /* The array length for a non-array string property is 1. */
304 array_len = 1;
305
306 /* Return how many there are if strings is NULL. */
307 if (!strings)
308 return array_len;
309
310 array_len = min(nval, array_len);
311 length = array_len * sizeof(*strings);
312
313 pointer = property_entry_find(props, propname, length);
314 if (IS_ERR(pointer))
315 return PTR_ERR(pointer);
316
317 memcpy(strings, pointer, length);
318
319 return array_len;
320}
321
Heikki Krogerused1cdf32018-11-09 17:21:37 +0300322static void property_entry_free_data(const struct property_entry *p)
323{
324 const void *pointer = property_get_pointer(p);
325 size_t i, nval;
326
327 if (p->is_array) {
328 if (p->type == DEV_PROP_STRING && p->pointer.str) {
329 nval = p->length / sizeof(const char *);
330 for (i = 0; i < nval; i++)
331 kfree(p->pointer.str[i]);
332 }
333 kfree(pointer);
334 } else if (p->type == DEV_PROP_STRING) {
335 kfree(p->value.str);
336 }
337 kfree(p->name);
338}
339
Dmitry Torokhov75dd63c2019-10-23 13:02:23 -0700340static const char * const *
341property_copy_string_array(const struct property_entry *src)
Heikki Krogerused1cdf32018-11-09 17:21:37 +0300342{
343 const char **d;
344 size_t nval = src->length / sizeof(*d);
345 int i;
346
347 d = kcalloc(nval, sizeof(*d), GFP_KERNEL);
348 if (!d)
Dmitry Torokhov75dd63c2019-10-23 13:02:23 -0700349 return NULL;
Heikki Krogerused1cdf32018-11-09 17:21:37 +0300350
351 for (i = 0; i < nval; i++) {
352 d[i] = kstrdup(src->pointer.str[i], GFP_KERNEL);
353 if (!d[i] && src->pointer.str[i]) {
354 while (--i >= 0)
355 kfree(d[i]);
356 kfree(d);
Dmitry Torokhov75dd63c2019-10-23 13:02:23 -0700357 return NULL;
Heikki Krogerused1cdf32018-11-09 17:21:37 +0300358 }
359 }
360
Dmitry Torokhov75dd63c2019-10-23 13:02:23 -0700361 return d;
Heikki Krogerused1cdf32018-11-09 17:21:37 +0300362}
363
364static int property_entry_copy_data(struct property_entry *dst,
365 const struct property_entry *src)
366{
367 const void *pointer = property_get_pointer(src);
368 const void *new;
Heikki Krogerused1cdf32018-11-09 17:21:37 +0300369
370 if (src->is_array) {
371 if (!src->length)
372 return -ENODATA;
373
374 if (src->type == DEV_PROP_STRING) {
Dmitry Torokhov75dd63c2019-10-23 13:02:23 -0700375 new = property_copy_string_array(src);
376 if (!new)
377 return -ENOMEM;
Heikki Krogerused1cdf32018-11-09 17:21:37 +0300378 } else {
379 new = kmemdup(pointer, src->length, GFP_KERNEL);
380 if (!new)
381 return -ENOMEM;
382 }
383 } else if (src->type == DEV_PROP_STRING) {
384 new = kstrdup(src->value.str, GFP_KERNEL);
385 if (!new && src->value.str)
386 return -ENOMEM;
387 } else {
388 new = pointer;
389 }
390
391 dst->length = src->length;
392 dst->is_array = src->is_array;
393 dst->type = src->type;
394
395 property_set_pointer(dst, new);
396
397 dst->name = kstrdup(src->name, GFP_KERNEL);
398 if (!dst->name)
399 goto out_free_data;
400
401 return 0;
402
403out_free_data:
404 property_entry_free_data(dst);
405 return -ENOMEM;
406}
407
408/**
409 * property_entries_dup - duplicate array of properties
410 * @properties: array of properties to copy
411 *
412 * This function creates a deep copy of the given NULL-terminated array
413 * of property entries.
414 */
415struct property_entry *
416property_entries_dup(const struct property_entry *properties)
417{
418 struct property_entry *p;
419 int i, n = 0;
420 int ret;
421
Heikki Krogerusa7996982019-05-31 17:15:32 +0300422 if (!properties)
423 return NULL;
424
Heikki Krogerused1cdf32018-11-09 17:21:37 +0300425 while (properties[n].name)
426 n++;
427
428 p = kcalloc(n + 1, sizeof(*p), GFP_KERNEL);
429 if (!p)
430 return ERR_PTR(-ENOMEM);
431
432 for (i = 0; i < n; i++) {
433 ret = property_entry_copy_data(&p[i], &properties[i]);
434 if (ret) {
435 while (--i >= 0)
436 property_entry_free_data(&p[i]);
437 kfree(p);
438 return ERR_PTR(ret);
439 }
440 }
441
442 return p;
443}
444EXPORT_SYMBOL_GPL(property_entries_dup);
445
446/**
447 * property_entries_free - free previously allocated array of properties
448 * @properties: array of properties to destroy
449 *
450 * This function frees given NULL-terminated array of property entries,
451 * along with their data.
452 */
453void property_entries_free(const struct property_entry *properties)
454{
455 const struct property_entry *p;
456
457 if (!properties)
458 return;
459
460 for (p = properties; p->name; p++)
461 property_entry_free_data(p);
462
463 kfree(properties);
464}
465EXPORT_SYMBOL_GPL(property_entries_free);
466
Heikki Krogerus59abd832018-11-09 17:21:36 +0300467/* -------------------------------------------------------------------------- */
468/* fwnode operations */
469
470static struct fwnode_handle *software_node_get(struct fwnode_handle *fwnode)
471{
Heikki Krogerus80488a62019-05-31 17:15:34 +0300472 struct swnode *swnode = to_swnode(fwnode);
Heikki Krogerus59abd832018-11-09 17:21:36 +0300473
474 kobject_get(&swnode->kobj);
475
476 return &swnode->fwnode;
477}
478
479static void software_node_put(struct fwnode_handle *fwnode)
480{
Heikki Krogerus80488a62019-05-31 17:15:34 +0300481 struct swnode *swnode = to_swnode(fwnode);
Heikki Krogerus59abd832018-11-09 17:21:36 +0300482
483 kobject_put(&swnode->kobj);
484}
485
486static bool software_node_property_present(const struct fwnode_handle *fwnode,
487 const char *propname)
488{
Heikki Krogerus80488a62019-05-31 17:15:34 +0300489 struct swnode *swnode = to_swnode(fwnode);
490
491 return !!property_entry_get(swnode->node->properties, propname);
Heikki Krogerus59abd832018-11-09 17:21:36 +0300492}
493
494static int software_node_read_int_array(const struct fwnode_handle *fwnode,
495 const char *propname,
496 unsigned int elem_size, void *val,
497 size_t nval)
498{
Heikki Krogerus80488a62019-05-31 17:15:34 +0300499 struct swnode *swnode = to_swnode(fwnode);
Heikki Krogerus59abd832018-11-09 17:21:36 +0300500
Heikki Krogerus80488a62019-05-31 17:15:34 +0300501 return property_entry_read_int_array(swnode->node->properties, propname,
Heikki Krogerus59abd832018-11-09 17:21:36 +0300502 elem_size, val, nval);
503}
504
505static int software_node_read_string_array(const struct fwnode_handle *fwnode,
506 const char *propname,
507 const char **val, size_t nval)
508{
Heikki Krogerus80488a62019-05-31 17:15:34 +0300509 struct swnode *swnode = to_swnode(fwnode);
Heikki Krogerus59abd832018-11-09 17:21:36 +0300510
Heikki Krogerus80488a62019-05-31 17:15:34 +0300511 return property_entry_read_string_array(swnode->node->properties,
512 propname, val, nval);
Heikki Krogerus59abd832018-11-09 17:21:36 +0300513}
514
Sakari Ailusbc0500c2019-10-03 15:32:12 +0300515static const char *
516software_node_get_name(const struct fwnode_handle *fwnode)
517{
518 const struct swnode *swnode = to_swnode(fwnode);
519
520 if (!swnode)
521 return "(null)";
522
523 return kobject_name(&swnode->kobj);
524}
525
Sakari Ailuse7e242b2019-10-03 15:32:13 +0300526static const char *
527software_node_get_name_prefix(const struct fwnode_handle *fwnode)
528{
529 struct fwnode_handle *parent;
530 const char *prefix;
531
532 parent = fwnode_get_parent(fwnode);
533 if (!parent)
534 return "";
535
536 /* Figure out the prefix from the parents. */
537 while (is_software_node(parent))
538 parent = fwnode_get_next_parent(parent);
539
540 prefix = fwnode_get_name_prefix(parent);
541 fwnode_handle_put(parent);
542
543 /* Guess something if prefix was NULL. */
544 return prefix ?: "/";
545}
546
YueHaibing0e3edd92019-03-19 23:20:42 +0800547static struct fwnode_handle *
Heikki Krogerus59abd832018-11-09 17:21:36 +0300548software_node_get_parent(const struct fwnode_handle *fwnode)
549{
Heikki Krogerus80488a62019-05-31 17:15:34 +0300550 struct swnode *swnode = to_swnode(fwnode);
Heikki Krogerus59abd832018-11-09 17:21:36 +0300551
Sakari Ailus51c100a2019-10-03 15:32:08 +0300552 if (!swnode || !swnode->parent)
553 return NULL;
554
555 return fwnode_handle_get(&swnode->parent->fwnode);
Heikki Krogerus59abd832018-11-09 17:21:36 +0300556}
557
YueHaibing0e3edd92019-03-19 23:20:42 +0800558static struct fwnode_handle *
Heikki Krogerus59abd832018-11-09 17:21:36 +0300559software_node_get_next_child(const struct fwnode_handle *fwnode,
560 struct fwnode_handle *child)
561{
Heikki Krogerus80488a62019-05-31 17:15:34 +0300562 struct swnode *p = to_swnode(fwnode);
563 struct swnode *c = to_swnode(child);
Heikki Krogerus59abd832018-11-09 17:21:36 +0300564
Colin Ian King1d8f0622018-12-22 12:49:39 +0000565 if (!p || list_empty(&p->children) ||
Heikki Krogerus59abd832018-11-09 17:21:36 +0300566 (c && list_is_last(&c->entry, &p->children)))
567 return NULL;
568
569 if (c)
570 c = list_next_entry(c, entry);
571 else
Heikki Krogerus80488a62019-05-31 17:15:34 +0300572 c = list_first_entry(&p->children, struct swnode, entry);
Heikki Krogerus59abd832018-11-09 17:21:36 +0300573 return &c->fwnode;
574}
575
Heikki Krogerus34479822019-02-13 14:55:49 +0300576static struct fwnode_handle *
577software_node_get_named_child_node(const struct fwnode_handle *fwnode,
578 const char *childname)
579{
Heikki Krogerus80488a62019-05-31 17:15:34 +0300580 struct swnode *swnode = to_swnode(fwnode);
Heikki Krogerus80488a62019-05-31 17:15:34 +0300581 struct swnode *child;
Heikki Krogerus34479822019-02-13 14:55:49 +0300582
583 if (!swnode || list_empty(&swnode->children))
584 return NULL;
585
586 list_for_each_entry(child, &swnode->children, entry) {
Heikki Krogerusc959d0c2019-05-31 17:15:35 +0300587 if (!strcmp(childname, kobject_name(&child->kobj))) {
Heikki Krogerus34479822019-02-13 14:55:49 +0300588 kobject_get(&child->kobj);
589 return &child->fwnode;
590 }
591 }
592 return NULL;
593}
Heikki Krogerus59abd832018-11-09 17:21:36 +0300594
Heikki Krogerusb06184a2019-05-31 17:15:36 +0300595static int
596software_node_get_reference_args(const struct fwnode_handle *fwnode,
597 const char *propname, const char *nargs_prop,
598 unsigned int nargs, unsigned int index,
599 struct fwnode_reference_args *args)
600{
601 struct swnode *swnode = to_swnode(fwnode);
602 const struct software_node_reference *ref;
603 const struct property_entry *prop;
604 struct fwnode_handle *refnode;
605 int i;
606
607 if (!swnode || !swnode->node->references)
608 return -ENOENT;
609
610 for (ref = swnode->node->references; ref->name; ref++)
611 if (!strcmp(ref->name, propname))
612 break;
613
614 if (!ref->name || index > (ref->nrefs - 1))
615 return -ENOENT;
616
617 refnode = software_node_fwnode(ref->refs[index].node);
618 if (!refnode)
619 return -ENOENT;
620
621 if (nargs_prop) {
622 prop = property_entry_get(swnode->node->properties, nargs_prop);
623 if (!prop)
624 return -EINVAL;
625
626 nargs = prop->value.u32_data;
627 }
628
629 if (nargs > NR_FWNODE_REFERENCE_ARGS)
630 return -EINVAL;
631
632 args->fwnode = software_node_get(refnode);
633 args->nargs = nargs;
634
635 for (i = 0; i < nargs; i++)
636 args->args[i] = ref->refs[index].args[i];
637
638 return 0;
639}
640
Heikki Krogerus59abd832018-11-09 17:21:36 +0300641static const struct fwnode_operations software_node_ops = {
642 .get = software_node_get,
643 .put = software_node_put,
644 .property_present = software_node_property_present,
645 .property_read_int_array = software_node_read_int_array,
646 .property_read_string_array = software_node_read_string_array,
Sakari Ailusbc0500c2019-10-03 15:32:12 +0300647 .get_name = software_node_get_name,
Sakari Ailuse7e242b2019-10-03 15:32:13 +0300648 .get_name_prefix = software_node_get_name_prefix,
Heikki Krogerus59abd832018-11-09 17:21:36 +0300649 .get_parent = software_node_get_parent,
650 .get_next_child_node = software_node_get_next_child,
Heikki Krogerus34479822019-02-13 14:55:49 +0300651 .get_named_child_node = software_node_get_named_child_node,
Heikki Krogerusb06184a2019-05-31 17:15:36 +0300652 .get_reference_args = software_node_get_reference_args
Heikki Krogerus59abd832018-11-09 17:21:36 +0300653};
654
655/* -------------------------------------------------------------------------- */
656
Heikki Krogerus1666fae2019-08-19 13:07:22 +0300657/**
658 * software_node_find_by_name - Find software node by name
659 * @parent: Parent of the software node
660 * @name: Name of the software node
661 *
662 * The function will find a node that is child of @parent and that is named
663 * @name. If no node is found, the function returns NULL.
664 *
665 * NOTE: you will need to drop the reference with fwnode_handle_put() after use.
666 */
667const struct software_node *
668software_node_find_by_name(const struct software_node *parent, const char *name)
669{
Heikki Krogerus016049a2019-08-30 10:51:56 +0300670 struct swnode *swnode = NULL;
Heikki Krogerus1666fae2019-08-19 13:07:22 +0300671 struct kobject *k;
672
673 if (!name)
674 return NULL;
675
676 spin_lock(&swnode_kset->list_lock);
677
678 list_for_each_entry(k, &swnode_kset->list, entry) {
679 swnode = kobj_to_swnode(k);
680 if (parent == swnode->node->parent && swnode->node->name &&
681 !strcmp(name, swnode->node->name)) {
682 kobject_get(&swnode->kobj);
683 break;
684 }
685 swnode = NULL;
686 }
687
688 spin_unlock(&swnode_kset->list_lock);
689
690 return swnode ? swnode->node : NULL;
691}
692EXPORT_SYMBOL_GPL(software_node_find_by_name);
693
Heikki Krogerus59abd832018-11-09 17:21:36 +0300694static int
Heikki Krogerus80488a62019-05-31 17:15:34 +0300695software_node_register_properties(struct software_node *node,
Heikki Krogerus59abd832018-11-09 17:21:36 +0300696 const struct property_entry *properties)
697{
698 struct property_entry *props;
699
700 props = property_entries_dup(properties);
701 if (IS_ERR(props))
702 return PTR_ERR(props);
703
Heikki Krogerus80488a62019-05-31 17:15:34 +0300704 node->properties = props;
Heikki Krogerus59abd832018-11-09 17:21:36 +0300705
706 return 0;
707}
708
709static void software_node_release(struct kobject *kobj)
710{
Heikki Krogerus80488a62019-05-31 17:15:34 +0300711 struct swnode *swnode = kobj_to_swnode(kobj);
Heikki Krogerus59abd832018-11-09 17:21:36 +0300712
Heikki Krogerus80488a62019-05-31 17:15:34 +0300713 if (swnode->allocated) {
714 property_entries_free(swnode->node->properties);
715 kfree(swnode->node);
716 }
Heikki Krogerus59abd832018-11-09 17:21:36 +0300717 ida_destroy(&swnode->child_ids);
Heikki Krogerus59abd832018-11-09 17:21:36 +0300718 kfree(swnode);
719}
720
721static struct kobj_type software_node_type = {
722 .release = software_node_release,
723 .sysfs_ops = &kobj_sysfs_ops,
724};
725
Heikki Krogerus80488a62019-05-31 17:15:34 +0300726static struct fwnode_handle *
727swnode_register(const struct software_node *node, struct swnode *parent,
728 unsigned int allocated)
729{
730 struct swnode *swnode;
731 int ret;
732
733 swnode = kzalloc(sizeof(*swnode), GFP_KERNEL);
734 if (!swnode) {
735 ret = -ENOMEM;
736 goto out_err;
737 }
738
739 ret = ida_simple_get(parent ? &parent->child_ids : &swnode_root_ids,
740 0, 0, GFP_KERNEL);
741 if (ret < 0) {
742 kfree(swnode);
743 goto out_err;
744 }
745
746 swnode->id = ret;
747 swnode->node = node;
748 swnode->parent = parent;
749 swnode->allocated = allocated;
750 swnode->kobj.kset = swnode_kset;
751 swnode->fwnode.ops = &software_node_ops;
752
753 ida_init(&swnode->child_ids);
754 INIT_LIST_HEAD(&swnode->entry);
755 INIT_LIST_HEAD(&swnode->children);
756
757 if (node->name)
758 ret = kobject_init_and_add(&swnode->kobj, &software_node_type,
759 parent ? &parent->kobj : NULL,
760 "%s", node->name);
761 else
762 ret = kobject_init_and_add(&swnode->kobj, &software_node_type,
763 parent ? &parent->kobj : NULL,
764 "node%d", swnode->id);
765 if (ret) {
766 kobject_put(&swnode->kobj);
767 return ERR_PTR(ret);
768 }
769
770 if (parent)
771 list_add_tail(&swnode->entry, &parent->children);
772
773 kobject_uevent(&swnode->kobj, KOBJ_ADD);
774 return &swnode->fwnode;
775
776out_err:
777 if (allocated)
778 property_entries_free(node->properties);
779 return ERR_PTR(ret);
780}
781
782/**
783 * software_node_register_nodes - Register an array of software nodes
784 * @nodes: Zero terminated array of software nodes to be registered
785 *
786 * Register multiple software nodes at once.
787 */
788int software_node_register_nodes(const struct software_node *nodes)
789{
790 int ret;
791 int i;
792
793 for (i = 0; nodes[i].name; i++) {
794 ret = software_node_register(&nodes[i]);
795 if (ret) {
796 software_node_unregister_nodes(nodes);
797 return ret;
798 }
799 }
800
801 return 0;
802}
803EXPORT_SYMBOL_GPL(software_node_register_nodes);
804
805/**
806 * software_node_unregister_nodes - Unregister an array of software nodes
807 * @nodes: Zero terminated array of software nodes to be unregistered
808 *
809 * Unregister multiple software nodes at once.
810 */
811void software_node_unregister_nodes(const struct software_node *nodes)
812{
813 struct swnode *swnode;
814 int i;
815
816 for (i = 0; nodes[i].name; i++) {
817 swnode = software_node_to_swnode(&nodes[i]);
818 if (swnode)
819 fwnode_remove_software_node(&swnode->fwnode);
820 }
821}
822EXPORT_SYMBOL_GPL(software_node_unregister_nodes);
823
824/**
825 * software_node_register - Register static software node
826 * @node: The software node to be registered
827 */
828int software_node_register(const struct software_node *node)
829{
830 struct swnode *parent = software_node_to_swnode(node->parent);
831
832 if (software_node_to_swnode(node))
833 return -EEXIST;
834
835 return PTR_ERR_OR_ZERO(swnode_register(node, parent, 0));
836}
837EXPORT_SYMBOL_GPL(software_node_register);
838
Heikki Krogerus59abd832018-11-09 17:21:36 +0300839struct fwnode_handle *
840fwnode_create_software_node(const struct property_entry *properties,
841 const struct fwnode_handle *parent)
842{
Heikki Krogerus80488a62019-05-31 17:15:34 +0300843 struct software_node *node;
844 struct swnode *p = NULL;
Heikki Krogerus59abd832018-11-09 17:21:36 +0300845 int ret;
846
847 if (parent) {
848 if (IS_ERR(parent))
849 return ERR_CAST(parent);
850 if (!is_software_node(parent))
851 return ERR_PTR(-EINVAL);
Heikki Krogerus80488a62019-05-31 17:15:34 +0300852 p = to_swnode(parent);
Heikki Krogerus59abd832018-11-09 17:21:36 +0300853 }
854
Heikki Krogerus80488a62019-05-31 17:15:34 +0300855 node = kzalloc(sizeof(*node), GFP_KERNEL);
856 if (!node)
Heikki Krogerus59abd832018-11-09 17:21:36 +0300857 return ERR_PTR(-ENOMEM);
858
Heikki Krogerus80488a62019-05-31 17:15:34 +0300859 ret = software_node_register_properties(node, properties);
Heikki Krogerus59abd832018-11-09 17:21:36 +0300860 if (ret) {
Heikki Krogerus80488a62019-05-31 17:15:34 +0300861 kfree(node);
Heikki Krogerus59abd832018-11-09 17:21:36 +0300862 return ERR_PTR(ret);
863 }
864
Heikki Krogerus80488a62019-05-31 17:15:34 +0300865 node->parent = p ? p->node : NULL;
Heikki Krogerus59abd832018-11-09 17:21:36 +0300866
Heikki Krogerus80488a62019-05-31 17:15:34 +0300867 return swnode_register(node, p, 1);
Heikki Krogerus59abd832018-11-09 17:21:36 +0300868}
869EXPORT_SYMBOL_GPL(fwnode_create_software_node);
870
871void fwnode_remove_software_node(struct fwnode_handle *fwnode)
872{
Heikki Krogerus80488a62019-05-31 17:15:34 +0300873 struct swnode *swnode = to_swnode(fwnode);
Heikki Krogerus59abd832018-11-09 17:21:36 +0300874
875 if (!swnode)
876 return;
877
Heikki Krogerus3df85a12019-05-31 17:15:33 +0300878 if (swnode->parent) {
879 ida_simple_remove(&swnode->parent->child_ids, swnode->id);
880 list_del(&swnode->entry);
881 } else {
882 ida_simple_remove(&swnode_root_ids, swnode->id);
883 }
884
Heikki Krogerus59abd832018-11-09 17:21:36 +0300885 kobject_put(&swnode->kobj);
886}
887EXPORT_SYMBOL_GPL(fwnode_remove_software_node);
888
889int software_node_notify(struct device *dev, unsigned long action)
890{
891 struct fwnode_handle *fwnode = dev_fwnode(dev);
Heikki Krogerus80488a62019-05-31 17:15:34 +0300892 struct swnode *swnode;
Heikki Krogerus59abd832018-11-09 17:21:36 +0300893 int ret;
894
895 if (!fwnode)
896 return 0;
897
898 if (!is_software_node(fwnode))
899 fwnode = fwnode->secondary;
900 if (!is_software_node(fwnode))
901 return 0;
902
Heikki Krogerus80488a62019-05-31 17:15:34 +0300903 swnode = to_swnode(fwnode);
Heikki Krogerus59abd832018-11-09 17:21:36 +0300904
905 switch (action) {
906 case KOBJ_ADD:
907 ret = sysfs_create_link(&dev->kobj, &swnode->kobj,
908 "software_node");
909 if (ret)
910 break;
911
912 ret = sysfs_create_link(&swnode->kobj, &dev->kobj,
913 dev_name(dev));
914 if (ret) {
915 sysfs_remove_link(&dev->kobj, "software_node");
916 break;
917 }
918 kobject_get(&swnode->kobj);
919 break;
920 case KOBJ_REMOVE:
921 sysfs_remove_link(&swnode->kobj, dev_name(dev));
922 sysfs_remove_link(&dev->kobj, "software_node");
923 kobject_put(&swnode->kobj);
924 break;
925 default:
926 break;
927 }
928
929 return 0;
930}
931
932static int __init software_node_init(void)
933{
934 swnode_kset = kset_create_and_add("software_nodes", NULL, kernel_kobj);
935 if (!swnode_kset)
936 return -ENOMEM;
937 return 0;
938}
939postcore_initcall(software_node_init);
940
941static void __exit software_node_exit(void)
942{
943 ida_destroy(&swnode_root_ids);
944 kset_unregister(swnode_kset);
945}
946__exitcall(software_node_exit);