LCOV - code coverage report
Current view: top level - drivers/base - swnode.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 13 383 3.4 %
Date: 2023-04-06 08:38:28 Functions: 4 46 8.7 %

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

Generated by: LCOV version 1.14