counter-sysfs.c (26087B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Generic Counter sysfs interface 4 * Copyright (C) 2020 William Breathitt Gray 5 */ 6#include <linux/counter.h> 7#include <linux/device.h> 8#include <linux/err.h> 9#include <linux/gfp.h> 10#include <linux/kernel.h> 11#include <linux/kfifo.h> 12#include <linux/kstrtox.h> 13#include <linux/list.h> 14#include <linux/mutex.h> 15#include <linux/spinlock.h> 16#include <linux/string.h> 17#include <linux/sysfs.h> 18#include <linux/types.h> 19 20#include "counter-sysfs.h" 21 22static inline struct counter_device *counter_from_dev(struct device *dev) 23{ 24 return container_of(dev, struct counter_device, dev); 25} 26 27/** 28 * struct counter_attribute - Counter sysfs attribute 29 * @dev_attr: device attribute for sysfs 30 * @l: node to add Counter attribute to attribute group list 31 * @comp: Counter component callbacks and data 32 * @scope: Counter scope of the attribute 33 * @parent: pointer to the parent component 34 */ 35struct counter_attribute { 36 struct device_attribute dev_attr; 37 struct list_head l; 38 39 struct counter_comp comp; 40 enum counter_scope scope; 41 void *parent; 42}; 43 44#define to_counter_attribute(_dev_attr) \ 45 container_of(_dev_attr, struct counter_attribute, dev_attr) 46 47/** 48 * struct counter_attribute_group - container for attribute group 49 * @name: name of the attribute group 50 * @attr_list: list to keep track of created attributes 51 * @num_attr: number of attributes 52 */ 53struct counter_attribute_group { 54 const char *name; 55 struct list_head attr_list; 56 size_t num_attr; 57}; 58 59static const char *const counter_function_str[] = { 60 [COUNTER_FUNCTION_INCREASE] = "increase", 61 [COUNTER_FUNCTION_DECREASE] = "decrease", 62 [COUNTER_FUNCTION_PULSE_DIRECTION] = "pulse-direction", 63 [COUNTER_FUNCTION_QUADRATURE_X1_A] = "quadrature x1 a", 64 [COUNTER_FUNCTION_QUADRATURE_X1_B] = "quadrature x1 b", 65 [COUNTER_FUNCTION_QUADRATURE_X2_A] = "quadrature x2 a", 66 [COUNTER_FUNCTION_QUADRATURE_X2_B] = "quadrature x2 b", 67 [COUNTER_FUNCTION_QUADRATURE_X4] = "quadrature x4" 68}; 69 70static const char *const counter_signal_value_str[] = { 71 [COUNTER_SIGNAL_LEVEL_LOW] = "low", 72 [COUNTER_SIGNAL_LEVEL_HIGH] = "high" 73}; 74 75static const char *const counter_synapse_action_str[] = { 76 [COUNTER_SYNAPSE_ACTION_NONE] = "none", 77 [COUNTER_SYNAPSE_ACTION_RISING_EDGE] = "rising edge", 78 [COUNTER_SYNAPSE_ACTION_FALLING_EDGE] = "falling edge", 79 [COUNTER_SYNAPSE_ACTION_BOTH_EDGES] = "both edges" 80}; 81 82static const char *const counter_count_direction_str[] = { 83 [COUNTER_COUNT_DIRECTION_FORWARD] = "forward", 84 [COUNTER_COUNT_DIRECTION_BACKWARD] = "backward" 85}; 86 87static const char *const counter_count_mode_str[] = { 88 [COUNTER_COUNT_MODE_NORMAL] = "normal", 89 [COUNTER_COUNT_MODE_RANGE_LIMIT] = "range limit", 90 [COUNTER_COUNT_MODE_NON_RECYCLE] = "non-recycle", 91 [COUNTER_COUNT_MODE_MODULO_N] = "modulo-n" 92}; 93 94static ssize_t counter_comp_u8_show(struct device *dev, 95 struct device_attribute *attr, char *buf) 96{ 97 const struct counter_attribute *const a = to_counter_attribute(attr); 98 struct counter_device *const counter = counter_from_dev(dev); 99 int err; 100 u8 data = 0; 101 102 switch (a->scope) { 103 case COUNTER_SCOPE_DEVICE: 104 err = a->comp.device_u8_read(counter, &data); 105 break; 106 case COUNTER_SCOPE_SIGNAL: 107 err = a->comp.signal_u8_read(counter, a->parent, &data); 108 break; 109 case COUNTER_SCOPE_COUNT: 110 err = a->comp.count_u8_read(counter, a->parent, &data); 111 break; 112 default: 113 return -EINVAL; 114 } 115 if (err < 0) 116 return err; 117 118 if (a->comp.type == COUNTER_COMP_BOOL) 119 /* data should already be boolean but ensure just to be safe */ 120 data = !!data; 121 122 return sysfs_emit(buf, "%u\n", (unsigned int)data); 123} 124 125static ssize_t counter_comp_u8_store(struct device *dev, 126 struct device_attribute *attr, 127 const char *buf, size_t len) 128{ 129 const struct counter_attribute *const a = to_counter_attribute(attr); 130 struct counter_device *const counter = counter_from_dev(dev); 131 int err; 132 bool bool_data = 0; 133 u8 data = 0; 134 135 if (a->comp.type == COUNTER_COMP_BOOL) { 136 err = kstrtobool(buf, &bool_data); 137 data = bool_data; 138 } else 139 err = kstrtou8(buf, 0, &data); 140 if (err < 0) 141 return err; 142 143 switch (a->scope) { 144 case COUNTER_SCOPE_DEVICE: 145 err = a->comp.device_u8_write(counter, data); 146 break; 147 case COUNTER_SCOPE_SIGNAL: 148 err = a->comp.signal_u8_write(counter, a->parent, data); 149 break; 150 case COUNTER_SCOPE_COUNT: 151 err = a->comp.count_u8_write(counter, a->parent, data); 152 break; 153 default: 154 return -EINVAL; 155 } 156 if (err < 0) 157 return err; 158 159 return len; 160} 161 162static ssize_t counter_comp_u32_show(struct device *dev, 163 struct device_attribute *attr, char *buf) 164{ 165 const struct counter_attribute *const a = to_counter_attribute(attr); 166 struct counter_device *const counter = counter_from_dev(dev); 167 const struct counter_available *const avail = a->comp.priv; 168 int err; 169 u32 data = 0; 170 171 switch (a->scope) { 172 case COUNTER_SCOPE_DEVICE: 173 err = a->comp.device_u32_read(counter, &data); 174 break; 175 case COUNTER_SCOPE_SIGNAL: 176 err = a->comp.signal_u32_read(counter, a->parent, &data); 177 break; 178 case COUNTER_SCOPE_COUNT: 179 if (a->comp.type == COUNTER_COMP_SYNAPSE_ACTION) 180 err = a->comp.action_read(counter, a->parent, 181 a->comp.priv, &data); 182 else 183 err = a->comp.count_u32_read(counter, a->parent, &data); 184 break; 185 default: 186 return -EINVAL; 187 } 188 if (err < 0) 189 return err; 190 191 switch (a->comp.type) { 192 case COUNTER_COMP_FUNCTION: 193 return sysfs_emit(buf, "%s\n", counter_function_str[data]); 194 case COUNTER_COMP_SIGNAL_LEVEL: 195 return sysfs_emit(buf, "%s\n", counter_signal_value_str[data]); 196 case COUNTER_COMP_SYNAPSE_ACTION: 197 return sysfs_emit(buf, "%s\n", counter_synapse_action_str[data]); 198 case COUNTER_COMP_ENUM: 199 return sysfs_emit(buf, "%s\n", avail->strs[data]); 200 case COUNTER_COMP_COUNT_DIRECTION: 201 return sysfs_emit(buf, "%s\n", counter_count_direction_str[data]); 202 case COUNTER_COMP_COUNT_MODE: 203 return sysfs_emit(buf, "%s\n", counter_count_mode_str[data]); 204 default: 205 return sysfs_emit(buf, "%u\n", (unsigned int)data); 206 } 207} 208 209static int counter_find_enum(u32 *const enum_item, const u32 *const enums, 210 const size_t num_enums, const char *const buf, 211 const char *const string_array[]) 212{ 213 size_t index; 214 215 for (index = 0; index < num_enums; index++) { 216 *enum_item = enums[index]; 217 if (sysfs_streq(buf, string_array[*enum_item])) 218 return 0; 219 } 220 221 return -EINVAL; 222} 223 224static ssize_t counter_comp_u32_store(struct device *dev, 225 struct device_attribute *attr, 226 const char *buf, size_t len) 227{ 228 const struct counter_attribute *const a = to_counter_attribute(attr); 229 struct counter_device *const counter = counter_from_dev(dev); 230 struct counter_count *const count = a->parent; 231 struct counter_synapse *const synapse = a->comp.priv; 232 const struct counter_available *const avail = a->comp.priv; 233 int err; 234 u32 data = 0; 235 236 switch (a->comp.type) { 237 case COUNTER_COMP_FUNCTION: 238 err = counter_find_enum(&data, count->functions_list, 239 count->num_functions, buf, 240 counter_function_str); 241 break; 242 case COUNTER_COMP_SYNAPSE_ACTION: 243 err = counter_find_enum(&data, synapse->actions_list, 244 synapse->num_actions, buf, 245 counter_synapse_action_str); 246 break; 247 case COUNTER_COMP_ENUM: 248 err = __sysfs_match_string(avail->strs, avail->num_items, buf); 249 data = err; 250 break; 251 case COUNTER_COMP_COUNT_MODE: 252 err = counter_find_enum(&data, avail->enums, avail->num_items, 253 buf, counter_count_mode_str); 254 break; 255 default: 256 err = kstrtou32(buf, 0, &data); 257 break; 258 } 259 if (err < 0) 260 return err; 261 262 switch (a->scope) { 263 case COUNTER_SCOPE_DEVICE: 264 err = a->comp.device_u32_write(counter, data); 265 break; 266 case COUNTER_SCOPE_SIGNAL: 267 err = a->comp.signal_u32_write(counter, a->parent, data); 268 break; 269 case COUNTER_SCOPE_COUNT: 270 if (a->comp.type == COUNTER_COMP_SYNAPSE_ACTION) 271 err = a->comp.action_write(counter, count, synapse, 272 data); 273 else 274 err = a->comp.count_u32_write(counter, count, data); 275 break; 276 default: 277 return -EINVAL; 278 } 279 if (err < 0) 280 return err; 281 282 return len; 283} 284 285static ssize_t counter_comp_u64_show(struct device *dev, 286 struct device_attribute *attr, char *buf) 287{ 288 const struct counter_attribute *const a = to_counter_attribute(attr); 289 struct counter_device *const counter = counter_from_dev(dev); 290 int err; 291 u64 data = 0; 292 293 switch (a->scope) { 294 case COUNTER_SCOPE_DEVICE: 295 err = a->comp.device_u64_read(counter, &data); 296 break; 297 case COUNTER_SCOPE_SIGNAL: 298 err = a->comp.signal_u64_read(counter, a->parent, &data); 299 break; 300 case COUNTER_SCOPE_COUNT: 301 err = a->comp.count_u64_read(counter, a->parent, &data); 302 break; 303 default: 304 return -EINVAL; 305 } 306 if (err < 0) 307 return err; 308 309 return sysfs_emit(buf, "%llu\n", (unsigned long long)data); 310} 311 312static ssize_t counter_comp_u64_store(struct device *dev, 313 struct device_attribute *attr, 314 const char *buf, size_t len) 315{ 316 const struct counter_attribute *const a = to_counter_attribute(attr); 317 struct counter_device *const counter = counter_from_dev(dev); 318 int err; 319 u64 data = 0; 320 321 err = kstrtou64(buf, 0, &data); 322 if (err < 0) 323 return err; 324 325 switch (a->scope) { 326 case COUNTER_SCOPE_DEVICE: 327 err = a->comp.device_u64_write(counter, data); 328 break; 329 case COUNTER_SCOPE_SIGNAL: 330 err = a->comp.signal_u64_write(counter, a->parent, data); 331 break; 332 case COUNTER_SCOPE_COUNT: 333 err = a->comp.count_u64_write(counter, a->parent, data); 334 break; 335 default: 336 return -EINVAL; 337 } 338 if (err < 0) 339 return err; 340 341 return len; 342} 343 344static ssize_t enums_available_show(const u32 *const enums, 345 const size_t num_enums, 346 const char *const strs[], char *buf) 347{ 348 size_t len = 0; 349 size_t index; 350 351 for (index = 0; index < num_enums; index++) 352 len += sysfs_emit_at(buf, len, "%s\n", strs[enums[index]]); 353 354 return len; 355} 356 357static ssize_t strs_available_show(const struct counter_available *const avail, 358 char *buf) 359{ 360 size_t len = 0; 361 size_t index; 362 363 for (index = 0; index < avail->num_items; index++) 364 len += sysfs_emit_at(buf, len, "%s\n", avail->strs[index]); 365 366 return len; 367} 368 369static ssize_t counter_comp_available_show(struct device *dev, 370 struct device_attribute *attr, 371 char *buf) 372{ 373 const struct counter_attribute *const a = to_counter_attribute(attr); 374 const struct counter_count *const count = a->parent; 375 const struct counter_synapse *const synapse = a->comp.priv; 376 const struct counter_available *const avail = a->comp.priv; 377 378 switch (a->comp.type) { 379 case COUNTER_COMP_FUNCTION: 380 return enums_available_show(count->functions_list, 381 count->num_functions, 382 counter_function_str, buf); 383 case COUNTER_COMP_SYNAPSE_ACTION: 384 return enums_available_show(synapse->actions_list, 385 synapse->num_actions, 386 counter_synapse_action_str, buf); 387 case COUNTER_COMP_ENUM: 388 return strs_available_show(avail, buf); 389 case COUNTER_COMP_COUNT_MODE: 390 return enums_available_show(avail->enums, avail->num_items, 391 counter_count_mode_str, buf); 392 default: 393 return -EINVAL; 394 } 395} 396 397static int counter_avail_attr_create(struct device *const dev, 398 struct counter_attribute_group *const group, 399 const struct counter_comp *const comp, void *const parent) 400{ 401 struct counter_attribute *counter_attr; 402 struct device_attribute *dev_attr; 403 404 counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL); 405 if (!counter_attr) 406 return -ENOMEM; 407 408 /* Configure Counter attribute */ 409 counter_attr->comp.type = comp->type; 410 counter_attr->comp.priv = comp->priv; 411 counter_attr->parent = parent; 412 413 /* Initialize sysfs attribute */ 414 dev_attr = &counter_attr->dev_attr; 415 sysfs_attr_init(&dev_attr->attr); 416 417 /* Configure device attribute */ 418 dev_attr->attr.name = devm_kasprintf(dev, GFP_KERNEL, "%s_available", 419 comp->name); 420 if (!dev_attr->attr.name) 421 return -ENOMEM; 422 dev_attr->attr.mode = 0444; 423 dev_attr->show = counter_comp_available_show; 424 425 /* Store list node */ 426 list_add(&counter_attr->l, &group->attr_list); 427 group->num_attr++; 428 429 return 0; 430} 431 432static int counter_attr_create(struct device *const dev, 433 struct counter_attribute_group *const group, 434 const struct counter_comp *const comp, 435 const enum counter_scope scope, 436 void *const parent) 437{ 438 struct counter_attribute *counter_attr; 439 struct device_attribute *dev_attr; 440 441 counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL); 442 if (!counter_attr) 443 return -ENOMEM; 444 445 /* Configure Counter attribute */ 446 counter_attr->comp = *comp; 447 counter_attr->scope = scope; 448 counter_attr->parent = parent; 449 450 /* Configure device attribute */ 451 dev_attr = &counter_attr->dev_attr; 452 sysfs_attr_init(&dev_attr->attr); 453 dev_attr->attr.name = comp->name; 454 switch (comp->type) { 455 case COUNTER_COMP_U8: 456 case COUNTER_COMP_BOOL: 457 if (comp->device_u8_read) { 458 dev_attr->attr.mode |= 0444; 459 dev_attr->show = counter_comp_u8_show; 460 } 461 if (comp->device_u8_write) { 462 dev_attr->attr.mode |= 0200; 463 dev_attr->store = counter_comp_u8_store; 464 } 465 break; 466 case COUNTER_COMP_SIGNAL_LEVEL: 467 case COUNTER_COMP_FUNCTION: 468 case COUNTER_COMP_SYNAPSE_ACTION: 469 case COUNTER_COMP_ENUM: 470 case COUNTER_COMP_COUNT_DIRECTION: 471 case COUNTER_COMP_COUNT_MODE: 472 if (comp->device_u32_read) { 473 dev_attr->attr.mode |= 0444; 474 dev_attr->show = counter_comp_u32_show; 475 } 476 if (comp->device_u32_write) { 477 dev_attr->attr.mode |= 0200; 478 dev_attr->store = counter_comp_u32_store; 479 } 480 break; 481 case COUNTER_COMP_U64: 482 if (comp->device_u64_read) { 483 dev_attr->attr.mode |= 0444; 484 dev_attr->show = counter_comp_u64_show; 485 } 486 if (comp->device_u64_write) { 487 dev_attr->attr.mode |= 0200; 488 dev_attr->store = counter_comp_u64_store; 489 } 490 break; 491 default: 492 return -EINVAL; 493 } 494 495 /* Store list node */ 496 list_add(&counter_attr->l, &group->attr_list); 497 group->num_attr++; 498 499 /* Create "*_available" attribute if needed */ 500 switch (comp->type) { 501 case COUNTER_COMP_FUNCTION: 502 case COUNTER_COMP_SYNAPSE_ACTION: 503 case COUNTER_COMP_ENUM: 504 case COUNTER_COMP_COUNT_MODE: 505 return counter_avail_attr_create(dev, group, comp, parent); 506 default: 507 return 0; 508 } 509} 510 511static ssize_t counter_comp_name_show(struct device *dev, 512 struct device_attribute *attr, char *buf) 513{ 514 return sysfs_emit(buf, "%s\n", to_counter_attribute(attr)->comp.name); 515} 516 517static int counter_name_attr_create(struct device *const dev, 518 struct counter_attribute_group *const group, 519 const char *const name) 520{ 521 struct counter_attribute *counter_attr; 522 523 counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL); 524 if (!counter_attr) 525 return -ENOMEM; 526 527 /* Configure Counter attribute */ 528 counter_attr->comp.name = name; 529 530 /* Configure device attribute */ 531 sysfs_attr_init(&counter_attr->dev_attr.attr); 532 counter_attr->dev_attr.attr.name = "name"; 533 counter_attr->dev_attr.attr.mode = 0444; 534 counter_attr->dev_attr.show = counter_comp_name_show; 535 536 /* Store list node */ 537 list_add(&counter_attr->l, &group->attr_list); 538 group->num_attr++; 539 540 return 0; 541} 542 543static ssize_t counter_comp_id_show(struct device *dev, 544 struct device_attribute *attr, char *buf) 545{ 546 const size_t id = (size_t)to_counter_attribute(attr)->comp.priv; 547 548 return sysfs_emit(buf, "%zu\n", id); 549} 550 551static int counter_comp_id_attr_create(struct device *const dev, 552 struct counter_attribute_group *const group, 553 const char *name, const size_t id) 554{ 555 struct counter_attribute *counter_attr; 556 557 /* Allocate Counter attribute */ 558 counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL); 559 if (!counter_attr) 560 return -ENOMEM; 561 562 /* Generate component ID name */ 563 name = devm_kasprintf(dev, GFP_KERNEL, "%s_component_id", name); 564 if (!name) 565 return -ENOMEM; 566 567 /* Configure Counter attribute */ 568 counter_attr->comp.priv = (void *)id; 569 570 /* Configure device attribute */ 571 sysfs_attr_init(&counter_attr->dev_attr.attr); 572 counter_attr->dev_attr.attr.name = name; 573 counter_attr->dev_attr.attr.mode = 0444; 574 counter_attr->dev_attr.show = counter_comp_id_show; 575 576 /* Store list node */ 577 list_add(&counter_attr->l, &group->attr_list); 578 group->num_attr++; 579 580 return 0; 581} 582 583static struct counter_comp counter_signal_comp = { 584 .type = COUNTER_COMP_SIGNAL_LEVEL, 585 .name = "signal", 586}; 587 588static int counter_signal_attrs_create(struct counter_device *const counter, 589 struct counter_attribute_group *const cattr_group, 590 struct counter_signal *const signal) 591{ 592 const enum counter_scope scope = COUNTER_SCOPE_SIGNAL; 593 struct device *const dev = &counter->dev; 594 int err; 595 struct counter_comp comp; 596 size_t i; 597 struct counter_comp *ext; 598 599 /* Create main Signal attribute */ 600 comp = counter_signal_comp; 601 comp.signal_u32_read = counter->ops->signal_read; 602 err = counter_attr_create(dev, cattr_group, &comp, scope, signal); 603 if (err < 0) 604 return err; 605 606 /* Create Signal name attribute */ 607 err = counter_name_attr_create(dev, cattr_group, signal->name); 608 if (err < 0) 609 return err; 610 611 /* Create an attribute for each extension */ 612 for (i = 0; i < signal->num_ext; i++) { 613 ext = &signal->ext[i]; 614 615 err = counter_attr_create(dev, cattr_group, ext, scope, signal); 616 if (err < 0) 617 return err; 618 619 err = counter_comp_id_attr_create(dev, cattr_group, ext->name, 620 i); 621 if (err < 0) 622 return err; 623 } 624 625 return 0; 626} 627 628static int counter_sysfs_signals_add(struct counter_device *const counter, 629 struct counter_attribute_group *const groups) 630{ 631 size_t i; 632 int err; 633 634 /* Add each Signal */ 635 for (i = 0; i < counter->num_signals; i++) { 636 /* Generate Signal attribute directory name */ 637 groups[i].name = devm_kasprintf(&counter->dev, GFP_KERNEL, 638 "signal%zu", i); 639 if (!groups[i].name) 640 return -ENOMEM; 641 642 /* Create all attributes associated with Signal */ 643 err = counter_signal_attrs_create(counter, groups + i, 644 counter->signals + i); 645 if (err < 0) 646 return err; 647 } 648 649 return 0; 650} 651 652static int counter_sysfs_synapses_add(struct counter_device *const counter, 653 struct counter_attribute_group *const group, 654 struct counter_count *const count) 655{ 656 size_t i; 657 658 /* Add each Synapse */ 659 for (i = 0; i < count->num_synapses; i++) { 660 struct device *const dev = &counter->dev; 661 struct counter_synapse *synapse; 662 size_t id; 663 struct counter_comp comp; 664 int err; 665 666 synapse = count->synapses + i; 667 668 /* Generate Synapse action name */ 669 id = synapse->signal - counter->signals; 670 comp.name = devm_kasprintf(dev, GFP_KERNEL, "signal%zu_action", 671 id); 672 if (!comp.name) 673 return -ENOMEM; 674 675 /* Create action attribute */ 676 comp.type = COUNTER_COMP_SYNAPSE_ACTION; 677 comp.action_read = counter->ops->action_read; 678 comp.action_write = counter->ops->action_write; 679 comp.priv = synapse; 680 err = counter_attr_create(dev, group, &comp, 681 COUNTER_SCOPE_COUNT, count); 682 if (err < 0) 683 return err; 684 685 /* Create Synapse component ID attribute */ 686 err = counter_comp_id_attr_create(dev, group, comp.name, i); 687 if (err < 0) 688 return err; 689 } 690 691 return 0; 692} 693 694static struct counter_comp counter_count_comp = 695 COUNTER_COMP_COUNT_U64("count", NULL, NULL); 696 697static struct counter_comp counter_function_comp = { 698 .type = COUNTER_COMP_FUNCTION, 699 .name = "function", 700}; 701 702static int counter_count_attrs_create(struct counter_device *const counter, 703 struct counter_attribute_group *const cattr_group, 704 struct counter_count *const count) 705{ 706 const enum counter_scope scope = COUNTER_SCOPE_COUNT; 707 struct device *const dev = &counter->dev; 708 int err; 709 struct counter_comp comp; 710 size_t i; 711 struct counter_comp *ext; 712 713 /* Create main Count attribute */ 714 comp = counter_count_comp; 715 comp.count_u64_read = counter->ops->count_read; 716 comp.count_u64_write = counter->ops->count_write; 717 err = counter_attr_create(dev, cattr_group, &comp, scope, count); 718 if (err < 0) 719 return err; 720 721 /* Create Count name attribute */ 722 err = counter_name_attr_create(dev, cattr_group, count->name); 723 if (err < 0) 724 return err; 725 726 /* Create Count function attribute */ 727 comp = counter_function_comp; 728 comp.count_u32_read = counter->ops->function_read; 729 comp.count_u32_write = counter->ops->function_write; 730 err = counter_attr_create(dev, cattr_group, &comp, scope, count); 731 if (err < 0) 732 return err; 733 734 /* Create an attribute for each extension */ 735 for (i = 0; i < count->num_ext; i++) { 736 ext = &count->ext[i]; 737 738 err = counter_attr_create(dev, cattr_group, ext, scope, count); 739 if (err < 0) 740 return err; 741 742 err = counter_comp_id_attr_create(dev, cattr_group, ext->name, 743 i); 744 if (err < 0) 745 return err; 746 } 747 748 return 0; 749} 750 751static int counter_sysfs_counts_add(struct counter_device *const counter, 752 struct counter_attribute_group *const groups) 753{ 754 size_t i; 755 struct counter_count *count; 756 int err; 757 758 /* Add each Count */ 759 for (i = 0; i < counter->num_counts; i++) { 760 count = counter->counts + i; 761 762 /* Generate Count attribute directory name */ 763 groups[i].name = devm_kasprintf(&counter->dev, GFP_KERNEL, 764 "count%zu", i); 765 if (!groups[i].name) 766 return -ENOMEM; 767 768 /* Add sysfs attributes of the Synapses */ 769 err = counter_sysfs_synapses_add(counter, groups + i, count); 770 if (err < 0) 771 return err; 772 773 /* Create all attributes associated with Count */ 774 err = counter_count_attrs_create(counter, groups + i, count); 775 if (err < 0) 776 return err; 777 } 778 779 return 0; 780} 781 782static int counter_num_signals_read(struct counter_device *counter, u8 *val) 783{ 784 *val = counter->num_signals; 785 return 0; 786} 787 788static int counter_num_counts_read(struct counter_device *counter, u8 *val) 789{ 790 *val = counter->num_counts; 791 return 0; 792} 793 794static int counter_events_queue_size_read(struct counter_device *counter, 795 u64 *val) 796{ 797 *val = kfifo_size(&counter->events); 798 return 0; 799} 800 801static int counter_events_queue_size_write(struct counter_device *counter, 802 u64 val) 803{ 804 DECLARE_KFIFO_PTR(events, struct counter_event); 805 int err; 806 unsigned long flags; 807 808 /* Allocate new events queue */ 809 err = kfifo_alloc(&events, val, GFP_KERNEL); 810 if (err) 811 return err; 812 813 /* Swap in new events queue */ 814 mutex_lock(&counter->events_out_lock); 815 spin_lock_irqsave(&counter->events_in_lock, flags); 816 kfifo_free(&counter->events); 817 counter->events.kfifo = events.kfifo; 818 spin_unlock_irqrestore(&counter->events_in_lock, flags); 819 mutex_unlock(&counter->events_out_lock); 820 821 return 0; 822} 823 824static struct counter_comp counter_num_signals_comp = 825 COUNTER_COMP_DEVICE_U8("num_signals", counter_num_signals_read, NULL); 826 827static struct counter_comp counter_num_counts_comp = 828 COUNTER_COMP_DEVICE_U8("num_counts", counter_num_counts_read, NULL); 829 830static struct counter_comp counter_events_queue_size_comp = 831 COUNTER_COMP_DEVICE_U64("events_queue_size", 832 counter_events_queue_size_read, 833 counter_events_queue_size_write); 834 835static int counter_sysfs_attr_add(struct counter_device *const counter, 836 struct counter_attribute_group *cattr_group) 837{ 838 const enum counter_scope scope = COUNTER_SCOPE_DEVICE; 839 struct device *const dev = &counter->dev; 840 int err; 841 size_t i; 842 struct counter_comp *ext; 843 844 /* Add Signals sysfs attributes */ 845 err = counter_sysfs_signals_add(counter, cattr_group); 846 if (err < 0) 847 return err; 848 cattr_group += counter->num_signals; 849 850 /* Add Counts sysfs attributes */ 851 err = counter_sysfs_counts_add(counter, cattr_group); 852 if (err < 0) 853 return err; 854 cattr_group += counter->num_counts; 855 856 /* Create name attribute */ 857 err = counter_name_attr_create(dev, cattr_group, counter->name); 858 if (err < 0) 859 return err; 860 861 /* Create num_signals attribute */ 862 err = counter_attr_create(dev, cattr_group, &counter_num_signals_comp, 863 scope, NULL); 864 if (err < 0) 865 return err; 866 867 /* Create num_counts attribute */ 868 err = counter_attr_create(dev, cattr_group, &counter_num_counts_comp, 869 scope, NULL); 870 if (err < 0) 871 return err; 872 873 /* Create events_queue_size attribute */ 874 err = counter_attr_create(dev, cattr_group, 875 &counter_events_queue_size_comp, scope, NULL); 876 if (err < 0) 877 return err; 878 879 /* Create an attribute for each extension */ 880 for (i = 0; i < counter->num_ext; i++) { 881 ext = &counter->ext[i]; 882 883 err = counter_attr_create(dev, cattr_group, ext, scope, NULL); 884 if (err < 0) 885 return err; 886 887 err = counter_comp_id_attr_create(dev, cattr_group, ext->name, 888 i); 889 if (err < 0) 890 return err; 891 } 892 893 return 0; 894} 895 896/** 897 * counter_sysfs_add - Adds Counter sysfs attributes to the device structure 898 * @counter: Pointer to the Counter device structure 899 * 900 * Counter sysfs attributes are created and added to the respective device 901 * structure for later registration to the system. Resource-managed memory 902 * allocation is performed by this function, and this memory should be freed 903 * when no longer needed (automatically by a device_unregister call, or 904 * manually by a devres_release_all call). 905 */ 906int counter_sysfs_add(struct counter_device *const counter) 907{ 908 struct device *const dev = &counter->dev; 909 const size_t num_groups = counter->num_signals + counter->num_counts + 1; 910 struct counter_attribute_group *cattr_groups; 911 size_t i, j; 912 int err; 913 struct attribute_group *groups; 914 struct counter_attribute *p; 915 916 /* Allocate space for attribute groups (signals, counts, and ext) */ 917 cattr_groups = devm_kcalloc(dev, num_groups, sizeof(*cattr_groups), 918 GFP_KERNEL); 919 if (!cattr_groups) 920 return -ENOMEM; 921 922 /* Initialize attribute lists */ 923 for (i = 0; i < num_groups; i++) 924 INIT_LIST_HEAD(&cattr_groups[i].attr_list); 925 926 /* Add Counter device sysfs attributes */ 927 err = counter_sysfs_attr_add(counter, cattr_groups); 928 if (err < 0) 929 return err; 930 931 /* Allocate attribute group pointers for association with device */ 932 dev->groups = devm_kcalloc(dev, num_groups + 1, sizeof(*dev->groups), 933 GFP_KERNEL); 934 if (!dev->groups) 935 return -ENOMEM; 936 937 /* Allocate space for attribute groups */ 938 groups = devm_kcalloc(dev, num_groups, sizeof(*groups), GFP_KERNEL); 939 if (!groups) 940 return -ENOMEM; 941 942 /* Prepare each group of attributes for association */ 943 for (i = 0; i < num_groups; i++) { 944 groups[i].name = cattr_groups[i].name; 945 946 /* Allocate space for attribute pointers */ 947 groups[i].attrs = devm_kcalloc(dev, 948 cattr_groups[i].num_attr + 1, 949 sizeof(*groups[i].attrs), 950 GFP_KERNEL); 951 if (!groups[i].attrs) 952 return -ENOMEM; 953 954 /* Add attribute pointers to attribute group */ 955 j = 0; 956 list_for_each_entry(p, &cattr_groups[i].attr_list, l) 957 groups[i].attrs[j++] = &p->dev_attr.attr; 958 959 /* Associate attribute group */ 960 dev->groups[i] = &groups[i]; 961 } 962 963 return 0; 964}