Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Generic Counter sysfs interface
0004  * Copyright (C) 2020 William Breathitt Gray
0005  */
0006 #include <linux/counter.h>
0007 #include <linux/device.h>
0008 #include <linux/err.h>
0009 #include <linux/gfp.h>
0010 #include <linux/kernel.h>
0011 #include <linux/kfifo.h>
0012 #include <linux/kstrtox.h>
0013 #include <linux/list.h>
0014 #include <linux/mutex.h>
0015 #include <linux/spinlock.h>
0016 #include <linux/string.h>
0017 #include <linux/sysfs.h>
0018 #include <linux/types.h>
0019 
0020 #include "counter-sysfs.h"
0021 
0022 static inline struct counter_device *counter_from_dev(struct device *dev)
0023 {
0024     return container_of(dev, struct counter_device, dev);
0025 }
0026 
0027 /**
0028  * struct counter_attribute - Counter sysfs attribute
0029  * @dev_attr:   device attribute for sysfs
0030  * @l:      node to add Counter attribute to attribute group list
0031  * @comp:   Counter component callbacks and data
0032  * @scope:  Counter scope of the attribute
0033  * @parent: pointer to the parent component
0034  */
0035 struct counter_attribute {
0036     struct device_attribute dev_attr;
0037     struct list_head l;
0038 
0039     struct counter_comp comp;
0040     enum counter_scope scope;
0041     void *parent;
0042 };
0043 
0044 #define to_counter_attribute(_dev_attr) \
0045     container_of(_dev_attr, struct counter_attribute, dev_attr)
0046 
0047 /**
0048  * struct counter_attribute_group - container for attribute group
0049  * @name:   name of the attribute group
0050  * @attr_list:  list to keep track of created attributes
0051  * @num_attr:   number of attributes
0052  */
0053 struct counter_attribute_group {
0054     const char *name;
0055     struct list_head attr_list;
0056     size_t num_attr;
0057 };
0058 
0059 static const char *const counter_function_str[] = {
0060     [COUNTER_FUNCTION_INCREASE] = "increase",
0061     [COUNTER_FUNCTION_DECREASE] = "decrease",
0062     [COUNTER_FUNCTION_PULSE_DIRECTION] = "pulse-direction",
0063     [COUNTER_FUNCTION_QUADRATURE_X1_A] = "quadrature x1 a",
0064     [COUNTER_FUNCTION_QUADRATURE_X1_B] = "quadrature x1 b",
0065     [COUNTER_FUNCTION_QUADRATURE_X2_A] = "quadrature x2 a",
0066     [COUNTER_FUNCTION_QUADRATURE_X2_B] = "quadrature x2 b",
0067     [COUNTER_FUNCTION_QUADRATURE_X4] = "quadrature x4"
0068 };
0069 
0070 static const char *const counter_signal_value_str[] = {
0071     [COUNTER_SIGNAL_LEVEL_LOW] = "low",
0072     [COUNTER_SIGNAL_LEVEL_HIGH] = "high"
0073 };
0074 
0075 static const char *const counter_synapse_action_str[] = {
0076     [COUNTER_SYNAPSE_ACTION_NONE] = "none",
0077     [COUNTER_SYNAPSE_ACTION_RISING_EDGE] = "rising edge",
0078     [COUNTER_SYNAPSE_ACTION_FALLING_EDGE] = "falling edge",
0079     [COUNTER_SYNAPSE_ACTION_BOTH_EDGES] = "both edges"
0080 };
0081 
0082 static const char *const counter_count_direction_str[] = {
0083     [COUNTER_COUNT_DIRECTION_FORWARD] = "forward",
0084     [COUNTER_COUNT_DIRECTION_BACKWARD] = "backward"
0085 };
0086 
0087 static const char *const counter_count_mode_str[] = {
0088     [COUNTER_COUNT_MODE_NORMAL] = "normal",
0089     [COUNTER_COUNT_MODE_RANGE_LIMIT] = "range limit",
0090     [COUNTER_COUNT_MODE_NON_RECYCLE] = "non-recycle",
0091     [COUNTER_COUNT_MODE_MODULO_N] = "modulo-n"
0092 };
0093 
0094 static ssize_t counter_comp_u8_show(struct device *dev,
0095                     struct device_attribute *attr, char *buf)
0096 {
0097     const struct counter_attribute *const a = to_counter_attribute(attr);
0098     struct counter_device *const counter = counter_from_dev(dev);
0099     int err;
0100     u8 data = 0;
0101 
0102     switch (a->scope) {
0103     case COUNTER_SCOPE_DEVICE:
0104         err = a->comp.device_u8_read(counter, &data);
0105         break;
0106     case COUNTER_SCOPE_SIGNAL:
0107         err = a->comp.signal_u8_read(counter, a->parent, &data);
0108         break;
0109     case COUNTER_SCOPE_COUNT:
0110         err = a->comp.count_u8_read(counter, a->parent, &data);
0111         break;
0112     default:
0113         return -EINVAL;
0114     }
0115     if (err < 0)
0116         return err;
0117 
0118     if (a->comp.type == COUNTER_COMP_BOOL)
0119         /* data should already be boolean but ensure just to be safe */
0120         data = !!data;
0121 
0122     return sysfs_emit(buf, "%u\n", (unsigned int)data);
0123 }
0124 
0125 static ssize_t counter_comp_u8_store(struct device *dev,
0126                      struct device_attribute *attr,
0127                      const char *buf, size_t len)
0128 {
0129     const struct counter_attribute *const a = to_counter_attribute(attr);
0130     struct counter_device *const counter = counter_from_dev(dev);
0131     int err;
0132     bool bool_data = 0;
0133     u8 data = 0;
0134 
0135     if (a->comp.type == COUNTER_COMP_BOOL) {
0136         err = kstrtobool(buf, &bool_data);
0137         data = bool_data;
0138     } else
0139         err = kstrtou8(buf, 0, &data);
0140     if (err < 0)
0141         return err;
0142 
0143     switch (a->scope) {
0144     case COUNTER_SCOPE_DEVICE:
0145         err = a->comp.device_u8_write(counter, data);
0146         break;
0147     case COUNTER_SCOPE_SIGNAL:
0148         err = a->comp.signal_u8_write(counter, a->parent, data);
0149         break;
0150     case COUNTER_SCOPE_COUNT:
0151         err = a->comp.count_u8_write(counter, a->parent, data);
0152         break;
0153     default:
0154         return -EINVAL;
0155     }
0156     if (err < 0)
0157         return err;
0158 
0159     return len;
0160 }
0161 
0162 static ssize_t counter_comp_u32_show(struct device *dev,
0163                      struct device_attribute *attr, char *buf)
0164 {
0165     const struct counter_attribute *const a = to_counter_attribute(attr);
0166     struct counter_device *const counter = counter_from_dev(dev);
0167     const struct counter_available *const avail = a->comp.priv;
0168     int err;
0169     u32 data = 0;
0170 
0171     switch (a->scope) {
0172     case COUNTER_SCOPE_DEVICE:
0173         err = a->comp.device_u32_read(counter, &data);
0174         break;
0175     case COUNTER_SCOPE_SIGNAL:
0176         err = a->comp.signal_u32_read(counter, a->parent, &data);
0177         break;
0178     case COUNTER_SCOPE_COUNT:
0179         if (a->comp.type == COUNTER_COMP_SYNAPSE_ACTION)
0180             err = a->comp.action_read(counter, a->parent,
0181                           a->comp.priv, &data);
0182         else
0183             err = a->comp.count_u32_read(counter, a->parent, &data);
0184         break;
0185     default:
0186         return -EINVAL;
0187     }
0188     if (err < 0)
0189         return err;
0190 
0191     switch (a->comp.type) {
0192     case COUNTER_COMP_FUNCTION:
0193         return sysfs_emit(buf, "%s\n", counter_function_str[data]);
0194     case COUNTER_COMP_SIGNAL_LEVEL:
0195         return sysfs_emit(buf, "%s\n", counter_signal_value_str[data]);
0196     case COUNTER_COMP_SYNAPSE_ACTION:
0197         return sysfs_emit(buf, "%s\n", counter_synapse_action_str[data]);
0198     case COUNTER_COMP_ENUM:
0199         return sysfs_emit(buf, "%s\n", avail->strs[data]);
0200     case COUNTER_COMP_COUNT_DIRECTION:
0201         return sysfs_emit(buf, "%s\n", counter_count_direction_str[data]);
0202     case COUNTER_COMP_COUNT_MODE:
0203         return sysfs_emit(buf, "%s\n", counter_count_mode_str[data]);
0204     default:
0205         return sysfs_emit(buf, "%u\n", (unsigned int)data);
0206     }
0207 }
0208 
0209 static int counter_find_enum(u32 *const enum_item, const u32 *const enums,
0210                  const size_t num_enums, const char *const buf,
0211                  const char *const string_array[])
0212 {
0213     size_t index;
0214 
0215     for (index = 0; index < num_enums; index++) {
0216         *enum_item = enums[index];
0217         if (sysfs_streq(buf, string_array[*enum_item]))
0218             return 0;
0219     }
0220 
0221     return -EINVAL;
0222 }
0223 
0224 static ssize_t counter_comp_u32_store(struct device *dev,
0225                       struct device_attribute *attr,
0226                       const char *buf, size_t len)
0227 {
0228     const struct counter_attribute *const a = to_counter_attribute(attr);
0229     struct counter_device *const counter = counter_from_dev(dev);
0230     struct counter_count *const count = a->parent;
0231     struct counter_synapse *const synapse = a->comp.priv;
0232     const struct counter_available *const avail = a->comp.priv;
0233     int err;
0234     u32 data = 0;
0235 
0236     switch (a->comp.type) {
0237     case COUNTER_COMP_FUNCTION:
0238         err = counter_find_enum(&data, count->functions_list,
0239                     count->num_functions, buf,
0240                     counter_function_str);
0241         break;
0242     case COUNTER_COMP_SYNAPSE_ACTION:
0243         err = counter_find_enum(&data, synapse->actions_list,
0244                     synapse->num_actions, buf,
0245                     counter_synapse_action_str);
0246         break;
0247     case COUNTER_COMP_ENUM:
0248         err = __sysfs_match_string(avail->strs, avail->num_items, buf);
0249         data = err;
0250         break;
0251     case COUNTER_COMP_COUNT_MODE:
0252         err = counter_find_enum(&data, avail->enums, avail->num_items,
0253                     buf, counter_count_mode_str);
0254         break;
0255     default:
0256         err = kstrtou32(buf, 0, &data);
0257         break;
0258     }
0259     if (err < 0)
0260         return err;
0261 
0262     switch (a->scope) {
0263     case COUNTER_SCOPE_DEVICE:
0264         err = a->comp.device_u32_write(counter, data);
0265         break;
0266     case COUNTER_SCOPE_SIGNAL:
0267         err = a->comp.signal_u32_write(counter, a->parent, data);
0268         break;
0269     case COUNTER_SCOPE_COUNT:
0270         if (a->comp.type == COUNTER_COMP_SYNAPSE_ACTION)
0271             err = a->comp.action_write(counter, count, synapse,
0272                            data);
0273         else
0274             err = a->comp.count_u32_write(counter, count, data);
0275         break;
0276     default:
0277         return -EINVAL;
0278     }
0279     if (err < 0)
0280         return err;
0281 
0282     return len;
0283 }
0284 
0285 static ssize_t counter_comp_u64_show(struct device *dev,
0286                      struct device_attribute *attr, char *buf)
0287 {
0288     const struct counter_attribute *const a = to_counter_attribute(attr);
0289     struct counter_device *const counter = counter_from_dev(dev);
0290     int err;
0291     u64 data = 0;
0292 
0293     switch (a->scope) {
0294     case COUNTER_SCOPE_DEVICE:
0295         err = a->comp.device_u64_read(counter, &data);
0296         break;
0297     case COUNTER_SCOPE_SIGNAL:
0298         err = a->comp.signal_u64_read(counter, a->parent, &data);
0299         break;
0300     case COUNTER_SCOPE_COUNT:
0301         err = a->comp.count_u64_read(counter, a->parent, &data);
0302         break;
0303     default:
0304         return -EINVAL;
0305     }
0306     if (err < 0)
0307         return err;
0308 
0309     return sysfs_emit(buf, "%llu\n", (unsigned long long)data);
0310 }
0311 
0312 static ssize_t counter_comp_u64_store(struct device *dev,
0313                       struct device_attribute *attr,
0314                       const char *buf, size_t len)
0315 {
0316     const struct counter_attribute *const a = to_counter_attribute(attr);
0317     struct counter_device *const counter = counter_from_dev(dev);
0318     int err;
0319     u64 data = 0;
0320 
0321     err = kstrtou64(buf, 0, &data);
0322     if (err < 0)
0323         return err;
0324 
0325     switch (a->scope) {
0326     case COUNTER_SCOPE_DEVICE:
0327         err = a->comp.device_u64_write(counter, data);
0328         break;
0329     case COUNTER_SCOPE_SIGNAL:
0330         err = a->comp.signal_u64_write(counter, a->parent, data);
0331         break;
0332     case COUNTER_SCOPE_COUNT:
0333         err = a->comp.count_u64_write(counter, a->parent, data);
0334         break;
0335     default:
0336         return -EINVAL;
0337     }
0338     if (err < 0)
0339         return err;
0340 
0341     return len;
0342 }
0343 
0344 static ssize_t enums_available_show(const u32 *const enums,
0345                     const size_t num_enums,
0346                     const char *const strs[], char *buf)
0347 {
0348     size_t len = 0;
0349     size_t index;
0350 
0351     for (index = 0; index < num_enums; index++)
0352         len += sysfs_emit_at(buf, len, "%s\n", strs[enums[index]]);
0353 
0354     return len;
0355 }
0356 
0357 static ssize_t strs_available_show(const struct counter_available *const avail,
0358                    char *buf)
0359 {
0360     size_t len = 0;
0361     size_t index;
0362 
0363     for (index = 0; index < avail->num_items; index++)
0364         len += sysfs_emit_at(buf, len, "%s\n", avail->strs[index]);
0365 
0366     return len;
0367 }
0368 
0369 static ssize_t counter_comp_available_show(struct device *dev,
0370                        struct device_attribute *attr,
0371                        char *buf)
0372 {
0373     const struct counter_attribute *const a = to_counter_attribute(attr);
0374     const struct counter_count *const count = a->parent;
0375     const struct counter_synapse *const synapse = a->comp.priv;
0376     const struct counter_available *const avail = a->comp.priv;
0377 
0378     switch (a->comp.type) {
0379     case COUNTER_COMP_FUNCTION:
0380         return enums_available_show(count->functions_list,
0381                         count->num_functions,
0382                         counter_function_str, buf);
0383     case COUNTER_COMP_SYNAPSE_ACTION:
0384         return enums_available_show(synapse->actions_list,
0385                         synapse->num_actions,
0386                         counter_synapse_action_str, buf);
0387     case COUNTER_COMP_ENUM:
0388         return strs_available_show(avail, buf);
0389     case COUNTER_COMP_COUNT_MODE:
0390         return enums_available_show(avail->enums, avail->num_items,
0391                         counter_count_mode_str, buf);
0392     default:
0393         return -EINVAL;
0394     }
0395 }
0396 
0397 static int counter_avail_attr_create(struct device *const dev,
0398     struct counter_attribute_group *const group,
0399     const struct counter_comp *const comp, void *const parent)
0400 {
0401     struct counter_attribute *counter_attr;
0402     struct device_attribute *dev_attr;
0403 
0404     counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
0405     if (!counter_attr)
0406         return -ENOMEM;
0407 
0408     /* Configure Counter attribute */
0409     counter_attr->comp.type = comp->type;
0410     counter_attr->comp.priv = comp->priv;
0411     counter_attr->parent = parent;
0412 
0413     /* Initialize sysfs attribute */
0414     dev_attr = &counter_attr->dev_attr;
0415     sysfs_attr_init(&dev_attr->attr);
0416 
0417     /* Configure device attribute */
0418     dev_attr->attr.name = devm_kasprintf(dev, GFP_KERNEL, "%s_available",
0419                          comp->name);
0420     if (!dev_attr->attr.name)
0421         return -ENOMEM;
0422     dev_attr->attr.mode = 0444;
0423     dev_attr->show = counter_comp_available_show;
0424 
0425     /* Store list node */
0426     list_add(&counter_attr->l, &group->attr_list);
0427     group->num_attr++;
0428 
0429     return 0;
0430 }
0431 
0432 static int counter_attr_create(struct device *const dev,
0433                    struct counter_attribute_group *const group,
0434                    const struct counter_comp *const comp,
0435                    const enum counter_scope scope,
0436                    void *const parent)
0437 {
0438     struct counter_attribute *counter_attr;
0439     struct device_attribute *dev_attr;
0440 
0441     counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
0442     if (!counter_attr)
0443         return -ENOMEM;
0444 
0445     /* Configure Counter attribute */
0446     counter_attr->comp = *comp;
0447     counter_attr->scope = scope;
0448     counter_attr->parent = parent;
0449 
0450     /* Configure device attribute */
0451     dev_attr = &counter_attr->dev_attr;
0452     sysfs_attr_init(&dev_attr->attr);
0453     dev_attr->attr.name = comp->name;
0454     switch (comp->type) {
0455     case COUNTER_COMP_U8:
0456     case COUNTER_COMP_BOOL:
0457         if (comp->device_u8_read) {
0458             dev_attr->attr.mode |= 0444;
0459             dev_attr->show = counter_comp_u8_show;
0460         }
0461         if (comp->device_u8_write) {
0462             dev_attr->attr.mode |= 0200;
0463             dev_attr->store = counter_comp_u8_store;
0464         }
0465         break;
0466     case COUNTER_COMP_SIGNAL_LEVEL:
0467     case COUNTER_COMP_FUNCTION:
0468     case COUNTER_COMP_SYNAPSE_ACTION:
0469     case COUNTER_COMP_ENUM:
0470     case COUNTER_COMP_COUNT_DIRECTION:
0471     case COUNTER_COMP_COUNT_MODE:
0472         if (comp->device_u32_read) {
0473             dev_attr->attr.mode |= 0444;
0474             dev_attr->show = counter_comp_u32_show;
0475         }
0476         if (comp->device_u32_write) {
0477             dev_attr->attr.mode |= 0200;
0478             dev_attr->store = counter_comp_u32_store;
0479         }
0480         break;
0481     case COUNTER_COMP_U64:
0482         if (comp->device_u64_read) {
0483             dev_attr->attr.mode |= 0444;
0484             dev_attr->show = counter_comp_u64_show;
0485         }
0486         if (comp->device_u64_write) {
0487             dev_attr->attr.mode |= 0200;
0488             dev_attr->store = counter_comp_u64_store;
0489         }
0490         break;
0491     default:
0492         return -EINVAL;
0493     }
0494 
0495     /* Store list node */
0496     list_add(&counter_attr->l, &group->attr_list);
0497     group->num_attr++;
0498 
0499     /* Create "*_available" attribute if needed */
0500     switch (comp->type) {
0501     case COUNTER_COMP_FUNCTION:
0502     case COUNTER_COMP_SYNAPSE_ACTION:
0503     case COUNTER_COMP_ENUM:
0504     case COUNTER_COMP_COUNT_MODE:
0505         return counter_avail_attr_create(dev, group, comp, parent);
0506     default:
0507         return 0;
0508     }
0509 }
0510 
0511 static ssize_t counter_comp_name_show(struct device *dev,
0512                       struct device_attribute *attr, char *buf)
0513 {
0514     return sysfs_emit(buf, "%s\n", to_counter_attribute(attr)->comp.name);
0515 }
0516 
0517 static int counter_name_attr_create(struct device *const dev,
0518                     struct counter_attribute_group *const group,
0519                     const char *const name)
0520 {
0521     struct counter_attribute *counter_attr;
0522 
0523     counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
0524     if (!counter_attr)
0525         return -ENOMEM;
0526 
0527     /* Configure Counter attribute */
0528     counter_attr->comp.name = name;
0529 
0530     /* Configure device attribute */
0531     sysfs_attr_init(&counter_attr->dev_attr.attr);
0532     counter_attr->dev_attr.attr.name = "name";
0533     counter_attr->dev_attr.attr.mode = 0444;
0534     counter_attr->dev_attr.show = counter_comp_name_show;
0535 
0536     /* Store list node */
0537     list_add(&counter_attr->l, &group->attr_list);
0538     group->num_attr++;
0539 
0540     return 0;
0541 }
0542 
0543 static ssize_t counter_comp_id_show(struct device *dev,
0544                     struct device_attribute *attr, char *buf)
0545 {
0546     const size_t id = (size_t)to_counter_attribute(attr)->comp.priv;
0547 
0548     return sysfs_emit(buf, "%zu\n", id);
0549 }
0550 
0551 static int counter_comp_id_attr_create(struct device *const dev,
0552                        struct counter_attribute_group *const group,
0553                        const char *name, const size_t id)
0554 {
0555     struct counter_attribute *counter_attr;
0556 
0557     /* Allocate Counter attribute */
0558     counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
0559     if (!counter_attr)
0560         return -ENOMEM;
0561 
0562     /* Generate component ID name */
0563     name = devm_kasprintf(dev, GFP_KERNEL, "%s_component_id", name);
0564     if (!name)
0565         return -ENOMEM;
0566 
0567     /* Configure Counter attribute */
0568     counter_attr->comp.priv = (void *)id;
0569 
0570     /* Configure device attribute */
0571     sysfs_attr_init(&counter_attr->dev_attr.attr);
0572     counter_attr->dev_attr.attr.name = name;
0573     counter_attr->dev_attr.attr.mode = 0444;
0574     counter_attr->dev_attr.show = counter_comp_id_show;
0575 
0576     /* Store list node */
0577     list_add(&counter_attr->l, &group->attr_list);
0578     group->num_attr++;
0579 
0580     return 0;
0581 }
0582 
0583 static struct counter_comp counter_signal_comp = {
0584     .type = COUNTER_COMP_SIGNAL_LEVEL,
0585     .name = "signal",
0586 };
0587 
0588 static int counter_signal_attrs_create(struct counter_device *const counter,
0589     struct counter_attribute_group *const cattr_group,
0590     struct counter_signal *const signal)
0591 {
0592     const enum counter_scope scope = COUNTER_SCOPE_SIGNAL;
0593     struct device *const dev = &counter->dev;
0594     int err;
0595     struct counter_comp comp;
0596     size_t i;
0597     struct counter_comp *ext;
0598 
0599     /* Create main Signal attribute */
0600     comp = counter_signal_comp;
0601     comp.signal_u32_read = counter->ops->signal_read;
0602     err = counter_attr_create(dev, cattr_group, &comp, scope, signal);
0603     if (err < 0)
0604         return err;
0605 
0606     /* Create Signal name attribute */
0607     err = counter_name_attr_create(dev, cattr_group, signal->name);
0608     if (err < 0)
0609         return err;
0610 
0611     /* Create an attribute for each extension */
0612     for (i = 0; i < signal->num_ext; i++) {
0613         ext = &signal->ext[i];
0614 
0615         err = counter_attr_create(dev, cattr_group, ext, scope, signal);
0616         if (err < 0)
0617             return err;
0618 
0619         err = counter_comp_id_attr_create(dev, cattr_group, ext->name,
0620                           i);
0621         if (err < 0)
0622             return err;
0623     }
0624 
0625     return 0;
0626 }
0627 
0628 static int counter_sysfs_signals_add(struct counter_device *const counter,
0629     struct counter_attribute_group *const groups)
0630 {
0631     size_t i;
0632     int err;
0633 
0634     /* Add each Signal */
0635     for (i = 0; i < counter->num_signals; i++) {
0636         /* Generate Signal attribute directory name */
0637         groups[i].name = devm_kasprintf(&counter->dev, GFP_KERNEL,
0638                         "signal%zu", i);
0639         if (!groups[i].name)
0640             return -ENOMEM;
0641 
0642         /* Create all attributes associated with Signal */
0643         err = counter_signal_attrs_create(counter, groups + i,
0644                           counter->signals + i);
0645         if (err < 0)
0646             return err;
0647     }
0648 
0649     return 0;
0650 }
0651 
0652 static int counter_sysfs_synapses_add(struct counter_device *const counter,
0653     struct counter_attribute_group *const group,
0654     struct counter_count *const count)
0655 {
0656     size_t i;
0657 
0658     /* Add each Synapse */
0659     for (i = 0; i < count->num_synapses; i++) {
0660         struct device *const dev = &counter->dev;
0661         struct counter_synapse *synapse;
0662         size_t id;
0663         struct counter_comp comp;
0664         int err;
0665 
0666         synapse = count->synapses + i;
0667 
0668         /* Generate Synapse action name */
0669         id = synapse->signal - counter->signals;
0670         comp.name = devm_kasprintf(dev, GFP_KERNEL, "signal%zu_action",
0671                        id);
0672         if (!comp.name)
0673             return -ENOMEM;
0674 
0675         /* Create action attribute */
0676         comp.type = COUNTER_COMP_SYNAPSE_ACTION;
0677         comp.action_read = counter->ops->action_read;
0678         comp.action_write = counter->ops->action_write;
0679         comp.priv = synapse;
0680         err = counter_attr_create(dev, group, &comp,
0681                       COUNTER_SCOPE_COUNT, count);
0682         if (err < 0)
0683             return err;
0684 
0685         /* Create Synapse component ID attribute */
0686         err = counter_comp_id_attr_create(dev, group, comp.name, i);
0687         if (err < 0)
0688             return err;
0689     }
0690 
0691     return 0;
0692 }
0693 
0694 static struct counter_comp counter_count_comp =
0695     COUNTER_COMP_COUNT_U64("count", NULL, NULL);
0696 
0697 static struct counter_comp counter_function_comp = {
0698     .type = COUNTER_COMP_FUNCTION,
0699     .name = "function",
0700 };
0701 
0702 static int counter_count_attrs_create(struct counter_device *const counter,
0703     struct counter_attribute_group *const cattr_group,
0704     struct counter_count *const count)
0705 {
0706     const enum counter_scope scope = COUNTER_SCOPE_COUNT;
0707     struct device *const dev = &counter->dev;
0708     int err;
0709     struct counter_comp comp;
0710     size_t i;
0711     struct counter_comp *ext;
0712 
0713     /* Create main Count attribute */
0714     comp = counter_count_comp;
0715     comp.count_u64_read = counter->ops->count_read;
0716     comp.count_u64_write = counter->ops->count_write;
0717     err = counter_attr_create(dev, cattr_group, &comp, scope, count);
0718     if (err < 0)
0719         return err;
0720 
0721     /* Create Count name attribute */
0722     err = counter_name_attr_create(dev, cattr_group, count->name);
0723     if (err < 0)
0724         return err;
0725 
0726     /* Create Count function attribute */
0727     comp = counter_function_comp;
0728     comp.count_u32_read = counter->ops->function_read;
0729     comp.count_u32_write = counter->ops->function_write;
0730     err = counter_attr_create(dev, cattr_group, &comp, scope, count);
0731     if (err < 0)
0732         return err;
0733 
0734     /* Create an attribute for each extension */
0735     for (i = 0; i < count->num_ext; i++) {
0736         ext = &count->ext[i];
0737 
0738         err = counter_attr_create(dev, cattr_group, ext, scope, count);
0739         if (err < 0)
0740             return err;
0741 
0742         err = counter_comp_id_attr_create(dev, cattr_group, ext->name,
0743                           i);
0744         if (err < 0)
0745             return err;
0746     }
0747 
0748     return 0;
0749 }
0750 
0751 static int counter_sysfs_counts_add(struct counter_device *const counter,
0752     struct counter_attribute_group *const groups)
0753 {
0754     size_t i;
0755     struct counter_count *count;
0756     int err;
0757 
0758     /* Add each Count */
0759     for (i = 0; i < counter->num_counts; i++) {
0760         count = counter->counts + i;
0761 
0762         /* Generate Count attribute directory name */
0763         groups[i].name = devm_kasprintf(&counter->dev, GFP_KERNEL,
0764                         "count%zu", i);
0765         if (!groups[i].name)
0766             return -ENOMEM;
0767 
0768         /* Add sysfs attributes of the Synapses */
0769         err = counter_sysfs_synapses_add(counter, groups + i, count);
0770         if (err < 0)
0771             return err;
0772 
0773         /* Create all attributes associated with Count */
0774         err = counter_count_attrs_create(counter, groups + i, count);
0775         if (err < 0)
0776             return err;
0777     }
0778 
0779     return 0;
0780 }
0781 
0782 static int counter_num_signals_read(struct counter_device *counter, u8 *val)
0783 {
0784     *val = counter->num_signals;
0785     return 0;
0786 }
0787 
0788 static int counter_num_counts_read(struct counter_device *counter, u8 *val)
0789 {
0790     *val = counter->num_counts;
0791     return 0;
0792 }
0793 
0794 static int counter_events_queue_size_read(struct counter_device *counter,
0795                       u64 *val)
0796 {
0797     *val = kfifo_size(&counter->events);
0798     return 0;
0799 }
0800 
0801 static int counter_events_queue_size_write(struct counter_device *counter,
0802                        u64 val)
0803 {
0804     DECLARE_KFIFO_PTR(events, struct counter_event);
0805     int err;
0806     unsigned long flags;
0807 
0808     /* Allocate new events queue */
0809     err = kfifo_alloc(&events, val, GFP_KERNEL);
0810     if (err)
0811         return err;
0812 
0813     /* Swap in new events queue */
0814     mutex_lock(&counter->events_out_lock);
0815     spin_lock_irqsave(&counter->events_in_lock, flags);
0816     kfifo_free(&counter->events);
0817     counter->events.kfifo = events.kfifo;
0818     spin_unlock_irqrestore(&counter->events_in_lock, flags);
0819     mutex_unlock(&counter->events_out_lock);
0820 
0821     return 0;
0822 }
0823 
0824 static struct counter_comp counter_num_signals_comp =
0825     COUNTER_COMP_DEVICE_U8("num_signals", counter_num_signals_read, NULL);
0826 
0827 static struct counter_comp counter_num_counts_comp =
0828     COUNTER_COMP_DEVICE_U8("num_counts", counter_num_counts_read, NULL);
0829 
0830 static struct counter_comp counter_events_queue_size_comp =
0831     COUNTER_COMP_DEVICE_U64("events_queue_size",
0832                 counter_events_queue_size_read,
0833                 counter_events_queue_size_write);
0834 
0835 static int counter_sysfs_attr_add(struct counter_device *const counter,
0836                   struct counter_attribute_group *cattr_group)
0837 {
0838     const enum counter_scope scope = COUNTER_SCOPE_DEVICE;
0839     struct device *const dev = &counter->dev;
0840     int err;
0841     size_t i;
0842     struct counter_comp *ext;
0843 
0844     /* Add Signals sysfs attributes */
0845     err = counter_sysfs_signals_add(counter, cattr_group);
0846     if (err < 0)
0847         return err;
0848     cattr_group += counter->num_signals;
0849 
0850     /* Add Counts sysfs attributes */
0851     err = counter_sysfs_counts_add(counter, cattr_group);
0852     if (err < 0)
0853         return err;
0854     cattr_group += counter->num_counts;
0855 
0856     /* Create name attribute */
0857     err = counter_name_attr_create(dev, cattr_group, counter->name);
0858     if (err < 0)
0859         return err;
0860 
0861     /* Create num_signals attribute */
0862     err = counter_attr_create(dev, cattr_group, &counter_num_signals_comp,
0863                   scope, NULL);
0864     if (err < 0)
0865         return err;
0866 
0867     /* Create num_counts attribute */
0868     err = counter_attr_create(dev, cattr_group, &counter_num_counts_comp,
0869                   scope, NULL);
0870     if (err < 0)
0871         return err;
0872 
0873     /* Create events_queue_size attribute */
0874     err = counter_attr_create(dev, cattr_group,
0875                   &counter_events_queue_size_comp, scope, NULL);
0876     if (err < 0)
0877         return err;
0878 
0879     /* Create an attribute for each extension */
0880     for (i = 0; i < counter->num_ext; i++) {
0881         ext = &counter->ext[i];
0882 
0883         err = counter_attr_create(dev, cattr_group, ext, scope, NULL);
0884         if (err < 0)
0885             return err;
0886 
0887         err = counter_comp_id_attr_create(dev, cattr_group, ext->name,
0888                           i);
0889         if (err < 0)
0890             return err;
0891     }
0892 
0893     return 0;
0894 }
0895 
0896 /**
0897  * counter_sysfs_add - Adds Counter sysfs attributes to the device structure
0898  * @counter:    Pointer to the Counter device structure
0899  *
0900  * Counter sysfs attributes are created and added to the respective device
0901  * structure for later registration to the system. Resource-managed memory
0902  * allocation is performed by this function, and this memory should be freed
0903  * when no longer needed (automatically by a device_unregister call, or
0904  * manually by a devres_release_all call).
0905  */
0906 int counter_sysfs_add(struct counter_device *const counter)
0907 {
0908     struct device *const dev = &counter->dev;
0909     const size_t num_groups = counter->num_signals + counter->num_counts + 1;
0910     struct counter_attribute_group *cattr_groups;
0911     size_t i, j;
0912     int err;
0913     struct attribute_group *groups;
0914     struct counter_attribute *p;
0915 
0916     /* Allocate space for attribute groups (signals, counts, and ext) */
0917     cattr_groups = devm_kcalloc(dev, num_groups, sizeof(*cattr_groups),
0918                     GFP_KERNEL);
0919     if (!cattr_groups)
0920         return -ENOMEM;
0921 
0922     /* Initialize attribute lists */
0923     for (i = 0; i < num_groups; i++)
0924         INIT_LIST_HEAD(&cattr_groups[i].attr_list);
0925 
0926     /* Add Counter device sysfs attributes */
0927     err = counter_sysfs_attr_add(counter, cattr_groups);
0928     if (err < 0)
0929         return err;
0930 
0931     /* Allocate attribute group pointers for association with device */
0932     dev->groups = devm_kcalloc(dev, num_groups + 1, sizeof(*dev->groups),
0933                    GFP_KERNEL);
0934     if (!dev->groups)
0935         return -ENOMEM;
0936 
0937     /* Allocate space for attribute groups */
0938     groups = devm_kcalloc(dev, num_groups, sizeof(*groups), GFP_KERNEL);
0939     if (!groups)
0940         return -ENOMEM;
0941 
0942     /* Prepare each group of attributes for association */
0943     for (i = 0; i < num_groups; i++) {
0944         groups[i].name = cattr_groups[i].name;
0945 
0946         /* Allocate space for attribute pointers */
0947         groups[i].attrs = devm_kcalloc(dev,
0948                            cattr_groups[i].num_attr + 1,
0949                            sizeof(*groups[i].attrs),
0950                            GFP_KERNEL);
0951         if (!groups[i].attrs)
0952             return -ENOMEM;
0953 
0954         /* Add attribute pointers to attribute group */
0955         j = 0;
0956         list_for_each_entry(p, &cattr_groups[i].attr_list, l)
0957             groups[i].attrs[j++] = &p->dev_attr.attr;
0958 
0959         /* Associate attribute group */
0960         dev->groups[i] = &groups[i];
0961     }
0962 
0963     return 0;
0964 }