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