LCOV - code coverage report
Current view: top level - drivers/base - swnode.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_real_modules_combined.info Lines: 12 346 3.5 %
Date: 2020-09-30 20:25:40 Functions: 3 39 7.7 %
Branches: 9 356 2.5 %

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

Generated by: LCOV version 1.14