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