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 static 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 */ 35 struct 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 */ 53 struct counter_attribute_group { 54 const char *name; 55 struct list_head attr_list; 56 size_t num_attr; 57 }; 58 59 static 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 70 static const char *const counter_signal_value_str[] = { 71 [COUNTER_SIGNAL_LEVEL_LOW] = "low", 72 [COUNTER_SIGNAL_LEVEL_HIGH] = "high" 73 }; 74 75 static 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 82 static const char *const counter_count_direction_str[] = { 83 [COUNTER_COUNT_DIRECTION_FORWARD] = "forward", 84 [COUNTER_COUNT_DIRECTION_BACKWARD] = "backward" 85 }; 86 87 static 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 [COUNTER_COUNT_MODE_INTERRUPT_ON_TERMINAL_COUNT] = "interrupt on terminal count", 93 [COUNTER_COUNT_MODE_HARDWARE_RETRIGGERABLE_ONESHOT] = "hardware retriggerable one-shot", 94 [COUNTER_COUNT_MODE_RATE_GENERATOR] = "rate generator", 95 [COUNTER_COUNT_MODE_SQUARE_WAVE_MODE] = "square wave mode", 96 [COUNTER_COUNT_MODE_SOFTWARE_TRIGGERED_STROBE] = "software triggered strobe", 97 [COUNTER_COUNT_MODE_HARDWARE_TRIGGERED_STROBE] = "hardware triggered strobe", 98 }; 99 100 static const char *const counter_signal_polarity_str[] = { 101 [COUNTER_SIGNAL_POLARITY_POSITIVE] = "positive", 102 [COUNTER_SIGNAL_POLARITY_NEGATIVE] = "negative" 103 }; 104 105 static ssize_t counter_comp_u8_show(struct device *dev, 106 struct device_attribute *attr, char *buf) 107 { 108 const struct counter_attribute *const a = to_counter_attribute(attr); 109 struct counter_device *const counter = counter_from_dev(dev); 110 int err; 111 u8 data = 0; 112 113 switch (a->scope) { 114 case COUNTER_SCOPE_DEVICE: 115 err = a->comp.device_u8_read(counter, &data); 116 break; 117 case COUNTER_SCOPE_SIGNAL: 118 err = a->comp.signal_u8_read(counter, a->parent, &data); 119 break; 120 case COUNTER_SCOPE_COUNT: 121 err = a->comp.count_u8_read(counter, a->parent, &data); 122 break; 123 default: 124 return -EINVAL; 125 } 126 if (err < 0) 127 return err; 128 129 if (a->comp.type == COUNTER_COMP_BOOL) 130 /* data should already be boolean but ensure just to be safe */ 131 data = !!data; 132 133 return sysfs_emit(buf, "%u\n", (unsigned int)data); 134 } 135 136 static ssize_t counter_comp_u8_store(struct device *dev, 137 struct device_attribute *attr, 138 const char *buf, size_t len) 139 { 140 const struct counter_attribute *const a = to_counter_attribute(attr); 141 struct counter_device *const counter = counter_from_dev(dev); 142 int err; 143 bool bool_data = 0; 144 u8 data = 0; 145 146 if (a->comp.type == COUNTER_COMP_BOOL) { 147 err = kstrtobool(buf, &bool_data); 148 data = bool_data; 149 } else 150 err = kstrtou8(buf, 0, &data); 151 if (err < 0) 152 return err; 153 154 switch (a->scope) { 155 case COUNTER_SCOPE_DEVICE: 156 err = a->comp.device_u8_write(counter, data); 157 break; 158 case COUNTER_SCOPE_SIGNAL: 159 err = a->comp.signal_u8_write(counter, a->parent, data); 160 break; 161 case COUNTER_SCOPE_COUNT: 162 err = a->comp.count_u8_write(counter, a->parent, data); 163 break; 164 default: 165 return -EINVAL; 166 } 167 if (err < 0) 168 return err; 169 170 return len; 171 } 172 173 static ssize_t counter_comp_u32_show(struct device *dev, 174 struct device_attribute *attr, char *buf) 175 { 176 const struct counter_attribute *const a = to_counter_attribute(attr); 177 struct counter_device *const counter = counter_from_dev(dev); 178 const struct counter_available *const avail = a->comp.priv; 179 int err; 180 u32 data = 0; 181 182 switch (a->scope) { 183 case COUNTER_SCOPE_DEVICE: 184 err = a->comp.device_u32_read(counter, &data); 185 break; 186 case COUNTER_SCOPE_SIGNAL: 187 err = a->comp.signal_u32_read(counter, a->parent, &data); 188 break; 189 case COUNTER_SCOPE_COUNT: 190 if (a->comp.type == COUNTER_COMP_SYNAPSE_ACTION) 191 err = a->comp.action_read(counter, a->parent, 192 a->comp.priv, &data); 193 else 194 err = a->comp.count_u32_read(counter, a->parent, &data); 195 break; 196 default: 197 return -EINVAL; 198 } 199 if (err < 0) 200 return err; 201 202 switch (a->comp.type) { 203 case COUNTER_COMP_FUNCTION: 204 return sysfs_emit(buf, "%s\n", counter_function_str[data]); 205 case COUNTER_COMP_SIGNAL_LEVEL: 206 return sysfs_emit(buf, "%s\n", counter_signal_value_str[data]); 207 case COUNTER_COMP_SYNAPSE_ACTION: 208 return sysfs_emit(buf, "%s\n", counter_synapse_action_str[data]); 209 case COUNTER_COMP_ENUM: 210 return sysfs_emit(buf, "%s\n", avail->strs[data]); 211 case COUNTER_COMP_COUNT_DIRECTION: 212 return sysfs_emit(buf, "%s\n", counter_count_direction_str[data]); 213 case COUNTER_COMP_COUNT_MODE: 214 return sysfs_emit(buf, "%s\n", counter_count_mode_str[data]); 215 case COUNTER_COMP_SIGNAL_POLARITY: 216 return sysfs_emit(buf, "%s\n", counter_signal_polarity_str[data]); 217 default: 218 return sysfs_emit(buf, "%u\n", (unsigned int)data); 219 } 220 } 221 222 static int counter_find_enum(u32 *const enum_item, const u32 *const enums, 223 const size_t num_enums, const char *const buf, 224 const char *const string_array[]) 225 { 226 size_t index; 227 228 for (index = 0; index < num_enums; index++) { 229 *enum_item = enums[index]; 230 if (sysfs_streq(buf, string_array[*enum_item])) 231 return 0; 232 } 233 234 return -EINVAL; 235 } 236 237 static ssize_t counter_comp_u32_store(struct device *dev, 238 struct device_attribute *attr, 239 const char *buf, size_t len) 240 { 241 const struct counter_attribute *const a = to_counter_attribute(attr); 242 struct counter_device *const counter = counter_from_dev(dev); 243 struct counter_count *const count = a->parent; 244 struct counter_synapse *const synapse = a->comp.priv; 245 const struct counter_available *const avail = a->comp.priv; 246 int err; 247 u32 data = 0; 248 249 switch (a->comp.type) { 250 case COUNTER_COMP_FUNCTION: 251 err = counter_find_enum(&data, count->functions_list, 252 count->num_functions, buf, 253 counter_function_str); 254 break; 255 case COUNTER_COMP_SYNAPSE_ACTION: 256 err = counter_find_enum(&data, synapse->actions_list, 257 synapse->num_actions, buf, 258 counter_synapse_action_str); 259 break; 260 case COUNTER_COMP_ENUM: 261 err = __sysfs_match_string(avail->strs, avail->num_items, buf); 262 data = err; 263 break; 264 case COUNTER_COMP_COUNT_MODE: 265 err = counter_find_enum(&data, avail->enums, avail->num_items, 266 buf, counter_count_mode_str); 267 break; 268 case COUNTER_COMP_SIGNAL_POLARITY: 269 err = counter_find_enum(&data, avail->enums, avail->num_items, 270 buf, counter_signal_polarity_str); 271 break; 272 default: 273 err = kstrtou32(buf, 0, &data); 274 break; 275 } 276 if (err < 0) 277 return err; 278 279 switch (a->scope) { 280 case COUNTER_SCOPE_DEVICE: 281 err = a->comp.device_u32_write(counter, data); 282 break; 283 case COUNTER_SCOPE_SIGNAL: 284 err = a->comp.signal_u32_write(counter, a->parent, data); 285 break; 286 case COUNTER_SCOPE_COUNT: 287 if (a->comp.type == COUNTER_COMP_SYNAPSE_ACTION) 288 err = a->comp.action_write(counter, count, synapse, 289 data); 290 else 291 err = a->comp.count_u32_write(counter, count, data); 292 break; 293 default: 294 return -EINVAL; 295 } 296 if (err < 0) 297 return err; 298 299 return len; 300 } 301 302 static ssize_t counter_comp_u64_show(struct device *dev, 303 struct device_attribute *attr, char *buf) 304 { 305 const struct counter_attribute *const a = to_counter_attribute(attr); 306 struct counter_device *const counter = counter_from_dev(dev); 307 int err; 308 u64 data = 0; 309 310 switch (a->scope) { 311 case COUNTER_SCOPE_DEVICE: 312 err = a->comp.device_u64_read(counter, &data); 313 break; 314 case COUNTER_SCOPE_SIGNAL: 315 err = a->comp.signal_u64_read(counter, a->parent, &data); 316 break; 317 case COUNTER_SCOPE_COUNT: 318 err = a->comp.count_u64_read(counter, a->parent, &data); 319 break; 320 default: 321 return -EINVAL; 322 } 323 if (err < 0) 324 return err; 325 326 return sysfs_emit(buf, "%llu\n", (unsigned long long)data); 327 } 328 329 static ssize_t counter_comp_u64_store(struct device *dev, 330 struct device_attribute *attr, 331 const char *buf, size_t len) 332 { 333 const struct counter_attribute *const a = to_counter_attribute(attr); 334 struct counter_device *const counter = counter_from_dev(dev); 335 int err; 336 u64 data = 0; 337 338 err = kstrtou64(buf, 0, &data); 339 if (err < 0) 340 return err; 341 342 switch (a->scope) { 343 case COUNTER_SCOPE_DEVICE: 344 err = a->comp.device_u64_write(counter, data); 345 break; 346 case COUNTER_SCOPE_SIGNAL: 347 err = a->comp.signal_u64_write(counter, a->parent, data); 348 break; 349 case COUNTER_SCOPE_COUNT: 350 err = a->comp.count_u64_write(counter, a->parent, data); 351 break; 352 default: 353 return -EINVAL; 354 } 355 if (err < 0) 356 return err; 357 358 return len; 359 } 360 361 static ssize_t counter_comp_array_u32_show(struct device *dev, 362 struct device_attribute *attr, 363 char *buf) 364 { 365 const struct counter_attribute *const a = to_counter_attribute(attr); 366 struct counter_device *const counter = counter_from_dev(dev); 367 const struct counter_array *const element = a->comp.priv; 368 int err; 369 u32 data = 0; 370 371 if (a->scope != COUNTER_SCOPE_SIGNAL || 372 element->type != COUNTER_COMP_SIGNAL_POLARITY) 373 return -EINVAL; 374 375 err = a->comp.signal_array_u32_read(counter, a->parent, element->idx, 376 &data); 377 if (err < 0) 378 return err; 379 380 return sysfs_emit(buf, "%s\n", counter_signal_polarity_str[data]); 381 } 382 383 static ssize_t counter_comp_array_u32_store(struct device *dev, 384 struct device_attribute *attr, 385 const char *buf, size_t len) 386 { 387 const struct counter_attribute *const a = to_counter_attribute(attr); 388 struct counter_device *const counter = counter_from_dev(dev); 389 const struct counter_array *const element = a->comp.priv; 390 int err; 391 u32 data = 0; 392 393 if (element->type != COUNTER_COMP_SIGNAL_POLARITY || 394 a->scope != COUNTER_SCOPE_SIGNAL) 395 return -EINVAL; 396 397 err = counter_find_enum(&data, element->avail->enums, 398 element->avail->num_items, buf, 399 counter_signal_polarity_str); 400 if (err < 0) 401 return err; 402 403 err = a->comp.signal_array_u32_write(counter, a->parent, element->idx, 404 data); 405 if (err < 0) 406 return err; 407 408 return len; 409 } 410 411 static ssize_t counter_comp_array_u64_show(struct device *dev, 412 struct device_attribute *attr, 413 char *buf) 414 { 415 const struct counter_attribute *const a = to_counter_attribute(attr); 416 struct counter_device *const counter = counter_from_dev(dev); 417 const struct counter_array *const element = a->comp.priv; 418 int err; 419 u64 data = 0; 420 421 switch (a->scope) { 422 case COUNTER_SCOPE_DEVICE: 423 err = a->comp.device_array_u64_read(counter, element->idx, 424 &data); 425 break; 426 case COUNTER_SCOPE_SIGNAL: 427 err = a->comp.signal_array_u64_read(counter, a->parent, 428 element->idx, &data); 429 break; 430 case COUNTER_SCOPE_COUNT: 431 err = a->comp.count_array_u64_read(counter, a->parent, 432 element->idx, &data); 433 break; 434 default: 435 return -EINVAL; 436 } 437 if (err < 0) 438 return err; 439 440 return sysfs_emit(buf, "%llu\n", (unsigned long long)data); 441 } 442 443 static ssize_t counter_comp_array_u64_store(struct device *dev, 444 struct device_attribute *attr, 445 const char *buf, size_t len) 446 { 447 const struct counter_attribute *const a = to_counter_attribute(attr); 448 struct counter_device *const counter = counter_from_dev(dev); 449 const struct counter_array *const element = a->comp.priv; 450 int err; 451 u64 data = 0; 452 453 err = kstrtou64(buf, 0, &data); 454 if (err < 0) 455 return err; 456 457 switch (a->scope) { 458 case COUNTER_SCOPE_DEVICE: 459 err = a->comp.device_array_u64_write(counter, element->idx, 460 data); 461 break; 462 case COUNTER_SCOPE_SIGNAL: 463 err = a->comp.signal_array_u64_write(counter, a->parent, 464 element->idx, data); 465 break; 466 case COUNTER_SCOPE_COUNT: 467 err = a->comp.count_array_u64_write(counter, a->parent, 468 element->idx, data); 469 break; 470 default: 471 return -EINVAL; 472 } 473 if (err < 0) 474 return err; 475 476 return len; 477 } 478 479 static ssize_t enums_available_show(const u32 *const enums, 480 const size_t num_enums, 481 const char *const strs[], char *buf) 482 { 483 size_t len = 0; 484 size_t index; 485 486 for (index = 0; index < num_enums; index++) 487 len += sysfs_emit_at(buf, len, "%s\n", strs[enums[index]]); 488 489 return len; 490 } 491 492 static ssize_t strs_available_show(const struct counter_available *const avail, 493 char *buf) 494 { 495 size_t len = 0; 496 size_t index; 497 498 for (index = 0; index < avail->num_items; index++) 499 len += sysfs_emit_at(buf, len, "%s\n", avail->strs[index]); 500 501 return len; 502 } 503 504 static ssize_t counter_comp_available_show(struct device *dev, 505 struct device_attribute *attr, 506 char *buf) 507 { 508 const struct counter_attribute *const a = to_counter_attribute(attr); 509 const struct counter_count *const count = a->parent; 510 const struct counter_synapse *const synapse = a->comp.priv; 511 const struct counter_available *const avail = a->comp.priv; 512 513 switch (a->comp.type) { 514 case COUNTER_COMP_FUNCTION: 515 return enums_available_show(count->functions_list, 516 count->num_functions, 517 counter_function_str, buf); 518 case COUNTER_COMP_SYNAPSE_ACTION: 519 return enums_available_show(synapse->actions_list, 520 synapse->num_actions, 521 counter_synapse_action_str, buf); 522 case COUNTER_COMP_ENUM: 523 return strs_available_show(avail, buf); 524 case COUNTER_COMP_COUNT_MODE: 525 return enums_available_show(avail->enums, avail->num_items, 526 counter_count_mode_str, buf); 527 default: 528 return -EINVAL; 529 } 530 } 531 532 static int counter_avail_attr_create(struct device *const dev, 533 struct counter_attribute_group *const group, 534 const struct counter_comp *const comp, void *const parent) 535 { 536 struct counter_attribute *counter_attr; 537 struct device_attribute *dev_attr; 538 539 counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL); 540 if (!counter_attr) 541 return -ENOMEM; 542 543 /* Configure Counter attribute */ 544 counter_attr->comp.type = comp->type; 545 counter_attr->comp.priv = comp->priv; 546 counter_attr->parent = parent; 547 548 /* Initialize sysfs attribute */ 549 dev_attr = &counter_attr->dev_attr; 550 sysfs_attr_init(&dev_attr->attr); 551 552 /* Configure device attribute */ 553 dev_attr->attr.name = devm_kasprintf(dev, GFP_KERNEL, "%s_available", 554 comp->name); 555 if (!dev_attr->attr.name) 556 return -ENOMEM; 557 dev_attr->attr.mode = 0444; 558 dev_attr->show = counter_comp_available_show; 559 560 /* Store list node */ 561 list_add(&counter_attr->l, &group->attr_list); 562 group->num_attr++; 563 564 return 0; 565 } 566 567 static int counter_attr_create(struct device *const dev, 568 struct counter_attribute_group *const group, 569 const struct counter_comp *const comp, 570 const enum counter_scope scope, 571 void *const parent) 572 { 573 const struct counter_array *const array = comp->priv; 574 struct counter_attribute *counter_attr; 575 struct device_attribute *dev_attr; 576 577 counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL); 578 if (!counter_attr) 579 return -ENOMEM; 580 581 /* Configure Counter attribute */ 582 counter_attr->comp = *comp; 583 counter_attr->scope = scope; 584 counter_attr->parent = parent; 585 586 /* Configure device attribute */ 587 dev_attr = &counter_attr->dev_attr; 588 sysfs_attr_init(&dev_attr->attr); 589 dev_attr->attr.name = comp->name; 590 switch (comp->type) { 591 case COUNTER_COMP_U8: 592 case COUNTER_COMP_BOOL: 593 if (comp->device_u8_read) { 594 dev_attr->attr.mode |= 0444; 595 dev_attr->show = counter_comp_u8_show; 596 } 597 if (comp->device_u8_write) { 598 dev_attr->attr.mode |= 0200; 599 dev_attr->store = counter_comp_u8_store; 600 } 601 break; 602 case COUNTER_COMP_SIGNAL_LEVEL: 603 case COUNTER_COMP_FUNCTION: 604 case COUNTER_COMP_SYNAPSE_ACTION: 605 case COUNTER_COMP_ENUM: 606 case COUNTER_COMP_COUNT_DIRECTION: 607 case COUNTER_COMP_COUNT_MODE: 608 case COUNTER_COMP_SIGNAL_POLARITY: 609 if (comp->device_u32_read) { 610 dev_attr->attr.mode |= 0444; 611 dev_attr->show = counter_comp_u32_show; 612 } 613 if (comp->device_u32_write) { 614 dev_attr->attr.mode |= 0200; 615 dev_attr->store = counter_comp_u32_store; 616 } 617 break; 618 case COUNTER_COMP_U64: 619 if (comp->device_u64_read) { 620 dev_attr->attr.mode |= 0444; 621 dev_attr->show = counter_comp_u64_show; 622 } 623 if (comp->device_u64_write) { 624 dev_attr->attr.mode |= 0200; 625 dev_attr->store = counter_comp_u64_store; 626 } 627 break; 628 case COUNTER_COMP_ARRAY: 629 switch (array->type) { 630 case COUNTER_COMP_SIGNAL_POLARITY: 631 if (comp->signal_array_u32_read) { 632 dev_attr->attr.mode |= 0444; 633 dev_attr->show = counter_comp_array_u32_show; 634 } 635 if (comp->signal_array_u32_write) { 636 dev_attr->attr.mode |= 0200; 637 dev_attr->store = counter_comp_array_u32_store; 638 } 639 break; 640 case COUNTER_COMP_U64: 641 if (comp->device_array_u64_read) { 642 dev_attr->attr.mode |= 0444; 643 dev_attr->show = counter_comp_array_u64_show; 644 } 645 if (comp->device_array_u64_write) { 646 dev_attr->attr.mode |= 0200; 647 dev_attr->store = counter_comp_array_u64_store; 648 } 649 break; 650 default: 651 return -EINVAL; 652 } 653 break; 654 default: 655 return -EINVAL; 656 } 657 658 /* Store list node */ 659 list_add(&counter_attr->l, &group->attr_list); 660 group->num_attr++; 661 662 /* Create "*_available" attribute if needed */ 663 switch (comp->type) { 664 case COUNTER_COMP_FUNCTION: 665 case COUNTER_COMP_SYNAPSE_ACTION: 666 case COUNTER_COMP_ENUM: 667 case COUNTER_COMP_COUNT_MODE: 668 return counter_avail_attr_create(dev, group, comp, parent); 669 default: 670 return 0; 671 } 672 } 673 674 static ssize_t counter_comp_name_show(struct device *dev, 675 struct device_attribute *attr, char *buf) 676 { 677 return sysfs_emit(buf, "%s\n", to_counter_attribute(attr)->comp.name); 678 } 679 680 static int counter_name_attr_create(struct device *const dev, 681 struct counter_attribute_group *const group, 682 const char *const name) 683 { 684 struct counter_attribute *counter_attr; 685 686 counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL); 687 if (!counter_attr) 688 return -ENOMEM; 689 690 /* Configure Counter attribute */ 691 counter_attr->comp.name = name; 692 693 /* Configure device attribute */ 694 sysfs_attr_init(&counter_attr->dev_attr.attr); 695 counter_attr->dev_attr.attr.name = "name"; 696 counter_attr->dev_attr.attr.mode = 0444; 697 counter_attr->dev_attr.show = counter_comp_name_show; 698 699 /* Store list node */ 700 list_add(&counter_attr->l, &group->attr_list); 701 group->num_attr++; 702 703 return 0; 704 } 705 706 static ssize_t counter_comp_id_show(struct device *dev, 707 struct device_attribute *attr, char *buf) 708 { 709 const size_t id = (size_t)to_counter_attribute(attr)->comp.priv; 710 711 return sysfs_emit(buf, "%zu\n", id); 712 } 713 714 static int counter_comp_id_attr_create(struct device *const dev, 715 struct counter_attribute_group *const group, 716 const char *name, const size_t id) 717 { 718 struct counter_attribute *counter_attr; 719 720 /* Allocate Counter attribute */ 721 counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL); 722 if (!counter_attr) 723 return -ENOMEM; 724 725 /* Generate component ID name */ 726 name = devm_kasprintf(dev, GFP_KERNEL, "%s_component_id", name); 727 if (!name) 728 return -ENOMEM; 729 730 /* Configure Counter attribute */ 731 counter_attr->comp.priv = (void *)id; 732 733 /* Configure device attribute */ 734 sysfs_attr_init(&counter_attr->dev_attr.attr); 735 counter_attr->dev_attr.attr.name = name; 736 counter_attr->dev_attr.attr.mode = 0444; 737 counter_attr->dev_attr.show = counter_comp_id_show; 738 739 /* Store list node */ 740 list_add(&counter_attr->l, &group->attr_list); 741 group->num_attr++; 742 743 return 0; 744 } 745 746 static int counter_ext_attrs_create(struct device *const dev, 747 struct counter_attribute_group *const group, 748 const struct counter_comp *const ext, 749 const enum counter_scope scope, 750 void *const parent, const size_t id) 751 { 752 int err; 753 754 /* Create main extension attribute */ 755 err = counter_attr_create(dev, group, ext, scope, parent); 756 if (err < 0) 757 return err; 758 759 /* Create extension id attribute */ 760 return counter_comp_id_attr_create(dev, group, ext->name, id); 761 } 762 763 static int counter_array_attrs_create(struct device *const dev, 764 struct counter_attribute_group *const group, 765 const struct counter_comp *const comp, 766 const enum counter_scope scope, 767 void *const parent, const size_t id) 768 { 769 const struct counter_array *const array = comp->priv; 770 struct counter_comp ext = *comp; 771 struct counter_array *element; 772 size_t idx; 773 int err; 774 775 /* Create an attribute for each array element */ 776 for (idx = 0; idx < array->length; idx++) { 777 /* Generate array element attribute name */ 778 ext.name = devm_kasprintf(dev, GFP_KERNEL, "%s%zu", comp->name, 779 idx); 780 if (!ext.name) 781 return -ENOMEM; 782 783 /* Allocate and configure array element */ 784 element = devm_kzalloc(dev, sizeof(*element), GFP_KERNEL); 785 if (!element) 786 return -ENOMEM; 787 element->type = array->type; 788 element->avail = array->avail; 789 element->idx = idx; 790 ext.priv = element; 791 792 /* Create all attributes associated with the array element */ 793 err = counter_ext_attrs_create(dev, group, &ext, scope, parent, 794 id + idx); 795 if (err < 0) 796 return err; 797 } 798 799 return 0; 800 } 801 802 static int counter_sysfs_exts_add(struct device *const dev, 803 struct counter_attribute_group *const group, 804 const struct counter_comp *const exts, 805 const size_t num_ext, 806 const enum counter_scope scope, 807 void *const parent) 808 { 809 size_t i; 810 const struct counter_comp *ext; 811 int err; 812 size_t id = 0; 813 const struct counter_array *array; 814 815 /* Create attributes for each extension */ 816 for (i = 0; i < num_ext; i++) { 817 ext = &exts[i]; 818 if (ext->type == COUNTER_COMP_ARRAY) { 819 err = counter_array_attrs_create(dev, group, ext, scope, 820 parent, id); 821 array = ext->priv; 822 id += array->length; 823 } else { 824 err = counter_ext_attrs_create(dev, group, ext, scope, 825 parent, id); 826 id++; 827 } 828 if (err < 0) 829 return err; 830 } 831 832 return 0; 833 } 834 835 static struct counter_comp counter_signal_comp = { 836 .type = COUNTER_COMP_SIGNAL_LEVEL, 837 .name = "signal", 838 }; 839 840 static int counter_signal_attrs_create(struct counter_device *const counter, 841 struct counter_attribute_group *const cattr_group, 842 struct counter_signal *const signal) 843 { 844 const enum counter_scope scope = COUNTER_SCOPE_SIGNAL; 845 struct device *const dev = &counter->dev; 846 int err; 847 struct counter_comp comp; 848 849 /* Create main Signal attribute */ 850 comp = counter_signal_comp; 851 comp.signal_u32_read = counter->ops->signal_read; 852 err = counter_attr_create(dev, cattr_group, &comp, scope, signal); 853 if (err < 0) 854 return err; 855 856 /* Create Signal name attribute */ 857 err = counter_name_attr_create(dev, cattr_group, signal->name); 858 if (err < 0) 859 return err; 860 861 /* Add Signal extensions */ 862 return counter_sysfs_exts_add(dev, cattr_group, signal->ext, 863 signal->num_ext, scope, signal); 864 } 865 866 static int counter_sysfs_signals_add(struct counter_device *const counter, 867 struct counter_attribute_group *const groups) 868 { 869 size_t i; 870 int err; 871 872 /* Add each Signal */ 873 for (i = 0; i < counter->num_signals; i++) { 874 /* Generate Signal attribute directory name */ 875 groups[i].name = devm_kasprintf(&counter->dev, GFP_KERNEL, 876 "signal%zu", i); 877 if (!groups[i].name) 878 return -ENOMEM; 879 880 /* Create all attributes associated with Signal */ 881 err = counter_signal_attrs_create(counter, groups + i, 882 counter->signals + i); 883 if (err < 0) 884 return err; 885 } 886 887 return 0; 888 } 889 890 static int counter_sysfs_synapses_add(struct counter_device *const counter, 891 struct counter_attribute_group *const group, 892 struct counter_count *const count) 893 { 894 size_t i; 895 896 /* Add each Synapse */ 897 for (i = 0; i < count->num_synapses; i++) { 898 struct device *const dev = &counter->dev; 899 struct counter_synapse *synapse; 900 size_t id; 901 struct counter_comp comp; 902 int err; 903 904 synapse = count->synapses + i; 905 906 /* Generate Synapse action name */ 907 id = synapse->signal - counter->signals; 908 comp.name = devm_kasprintf(dev, GFP_KERNEL, "signal%zu_action", 909 id); 910 if (!comp.name) 911 return -ENOMEM; 912 913 /* Create action attribute */ 914 comp.type = COUNTER_COMP_SYNAPSE_ACTION; 915 comp.action_read = counter->ops->action_read; 916 comp.action_write = counter->ops->action_write; 917 comp.priv = synapse; 918 err = counter_attr_create(dev, group, &comp, 919 COUNTER_SCOPE_COUNT, count); 920 if (err < 0) 921 return err; 922 923 /* Create Synapse component ID attribute */ 924 err = counter_comp_id_attr_create(dev, group, comp.name, i); 925 if (err < 0) 926 return err; 927 } 928 929 return 0; 930 } 931 932 static struct counter_comp counter_count_comp = 933 COUNTER_COMP_COUNT_U64("count", NULL, NULL); 934 935 static struct counter_comp counter_function_comp = { 936 .type = COUNTER_COMP_FUNCTION, 937 .name = "function", 938 }; 939 940 static int counter_count_attrs_create(struct counter_device *const counter, 941 struct counter_attribute_group *const cattr_group, 942 struct counter_count *const count) 943 { 944 const enum counter_scope scope = COUNTER_SCOPE_COUNT; 945 struct device *const dev = &counter->dev; 946 int err; 947 struct counter_comp comp; 948 949 /* Create main Count attribute */ 950 comp = counter_count_comp; 951 comp.count_u64_read = counter->ops->count_read; 952 comp.count_u64_write = counter->ops->count_write; 953 err = counter_attr_create(dev, cattr_group, &comp, scope, count); 954 if (err < 0) 955 return err; 956 957 /* Create Count name attribute */ 958 err = counter_name_attr_create(dev, cattr_group, count->name); 959 if (err < 0) 960 return err; 961 962 /* Create Count function attribute */ 963 comp = counter_function_comp; 964 comp.count_u32_read = counter->ops->function_read; 965 comp.count_u32_write = counter->ops->function_write; 966 err = counter_attr_create(dev, cattr_group, &comp, scope, count); 967 if (err < 0) 968 return err; 969 970 /* Add Count extensions */ 971 return counter_sysfs_exts_add(dev, cattr_group, count->ext, 972 count->num_ext, scope, count); 973 } 974 975 static int counter_sysfs_counts_add(struct counter_device *const counter, 976 struct counter_attribute_group *const groups) 977 { 978 size_t i; 979 struct counter_count *count; 980 int err; 981 982 /* Add each Count */ 983 for (i = 0; i < counter->num_counts; i++) { 984 count = counter->counts + i; 985 986 /* Generate Count attribute directory name */ 987 groups[i].name = devm_kasprintf(&counter->dev, GFP_KERNEL, 988 "count%zu", i); 989 if (!groups[i].name) 990 return -ENOMEM; 991 992 /* Add sysfs attributes of the Synapses */ 993 err = counter_sysfs_synapses_add(counter, groups + i, count); 994 if (err < 0) 995 return err; 996 997 /* Create all attributes associated with Count */ 998 err = counter_count_attrs_create(counter, groups + i, count); 999 if (err < 0) 1000 return err; 1001 } 1002 1003 return 0; 1004 } 1005 1006 static int counter_num_signals_read(struct counter_device *counter, u8 *val) 1007 { 1008 *val = counter->num_signals; 1009 return 0; 1010 } 1011 1012 static int counter_num_counts_read(struct counter_device *counter, u8 *val) 1013 { 1014 *val = counter->num_counts; 1015 return 0; 1016 } 1017 1018 static int counter_events_queue_size_read(struct counter_device *counter, 1019 u64 *val) 1020 { 1021 *val = kfifo_size(&counter->events); 1022 return 0; 1023 } 1024 1025 static int counter_events_queue_size_write(struct counter_device *counter, 1026 u64 val) 1027 { 1028 DECLARE_KFIFO_PTR(events, struct counter_event); 1029 int err; 1030 unsigned long flags; 1031 1032 /* Allocate new events queue */ 1033 err = kfifo_alloc(&events, val, GFP_KERNEL); 1034 if (err) 1035 return err; 1036 1037 /* Swap in new events queue */ 1038 mutex_lock(&counter->events_out_lock); 1039 spin_lock_irqsave(&counter->events_in_lock, flags); 1040 kfifo_free(&counter->events); 1041 counter->events.kfifo = events.kfifo; 1042 spin_unlock_irqrestore(&counter->events_in_lock, flags); 1043 mutex_unlock(&counter->events_out_lock); 1044 1045 return 0; 1046 } 1047 1048 static struct counter_comp counter_num_signals_comp = 1049 COUNTER_COMP_DEVICE_U8("num_signals", counter_num_signals_read, NULL); 1050 1051 static struct counter_comp counter_num_counts_comp = 1052 COUNTER_COMP_DEVICE_U8("num_counts", counter_num_counts_read, NULL); 1053 1054 static struct counter_comp counter_events_queue_size_comp = 1055 COUNTER_COMP_DEVICE_U64("events_queue_size", 1056 counter_events_queue_size_read, 1057 counter_events_queue_size_write); 1058 1059 static int counter_sysfs_attr_add(struct counter_device *const counter, 1060 struct counter_attribute_group *cattr_group) 1061 { 1062 const enum counter_scope scope = COUNTER_SCOPE_DEVICE; 1063 struct device *const dev = &counter->dev; 1064 int err; 1065 1066 /* Add Signals sysfs attributes */ 1067 err = counter_sysfs_signals_add(counter, cattr_group); 1068 if (err < 0) 1069 return err; 1070 cattr_group += counter->num_signals; 1071 1072 /* Add Counts sysfs attributes */ 1073 err = counter_sysfs_counts_add(counter, cattr_group); 1074 if (err < 0) 1075 return err; 1076 cattr_group += counter->num_counts; 1077 1078 /* Create name attribute */ 1079 err = counter_name_attr_create(dev, cattr_group, counter->name); 1080 if (err < 0) 1081 return err; 1082 1083 /* Create num_signals attribute */ 1084 err = counter_attr_create(dev, cattr_group, &counter_num_signals_comp, 1085 scope, NULL); 1086 if (err < 0) 1087 return err; 1088 1089 /* Create num_counts attribute */ 1090 err = counter_attr_create(dev, cattr_group, &counter_num_counts_comp, 1091 scope, NULL); 1092 if (err < 0) 1093 return err; 1094 1095 /* Create events_queue_size attribute */ 1096 err = counter_attr_create(dev, cattr_group, 1097 &counter_events_queue_size_comp, scope, NULL); 1098 if (err < 0) 1099 return err; 1100 1101 /* Add device extensions */ 1102 return counter_sysfs_exts_add(dev, cattr_group, counter->ext, 1103 counter->num_ext, scope, NULL); 1104 1105 return 0; 1106 } 1107 1108 /** 1109 * counter_sysfs_add - Adds Counter sysfs attributes to the device structure 1110 * @counter: Pointer to the Counter device structure 1111 * 1112 * Counter sysfs attributes are created and added to the respective device 1113 * structure for later registration to the system. Resource-managed memory 1114 * allocation is performed by this function, and this memory should be freed 1115 * when no longer needed (automatically by a device_unregister call, or 1116 * manually by a devres_release_all call). 1117 */ 1118 int counter_sysfs_add(struct counter_device *const counter) 1119 { 1120 struct device *const dev = &counter->dev; 1121 const size_t num_groups = counter->num_signals + counter->num_counts + 1; 1122 struct counter_attribute_group *cattr_groups; 1123 size_t i, j; 1124 int err; 1125 struct attribute_group *groups; 1126 struct counter_attribute *p; 1127 1128 /* Allocate space for attribute groups (signals, counts, and ext) */ 1129 cattr_groups = devm_kcalloc(dev, num_groups, sizeof(*cattr_groups), 1130 GFP_KERNEL); 1131 if (!cattr_groups) 1132 return -ENOMEM; 1133 1134 /* Initialize attribute lists */ 1135 for (i = 0; i < num_groups; i++) 1136 INIT_LIST_HEAD(&cattr_groups[i].attr_list); 1137 1138 /* Add Counter device sysfs attributes */ 1139 err = counter_sysfs_attr_add(counter, cattr_groups); 1140 if (err < 0) 1141 return err; 1142 1143 /* Allocate attribute group pointers for association with device */ 1144 dev->groups = devm_kcalloc(dev, num_groups + 1, sizeof(*dev->groups), 1145 GFP_KERNEL); 1146 if (!dev->groups) 1147 return -ENOMEM; 1148 1149 /* Allocate space for attribute groups */ 1150 groups = devm_kcalloc(dev, num_groups, sizeof(*groups), GFP_KERNEL); 1151 if (!groups) 1152 return -ENOMEM; 1153 1154 /* Prepare each group of attributes for association */ 1155 for (i = 0; i < num_groups; i++) { 1156 groups[i].name = cattr_groups[i].name; 1157 1158 /* Allocate space for attribute pointers */ 1159 groups[i].attrs = devm_kcalloc(dev, 1160 cattr_groups[i].num_attr + 1, 1161 sizeof(*groups[i].attrs), 1162 GFP_KERNEL); 1163 if (!groups[i].attrs) 1164 return -ENOMEM; 1165 1166 /* Add attribute pointers to attribute group */ 1167 j = 0; 1168 list_for_each_entry(p, &cattr_groups[i].attr_list, l) 1169 groups[i].attrs[j++] = &p->dev_attr.attr; 1170 1171 /* Associate attribute group */ 1172 dev->groups[i] = &groups[i]; 1173 } 1174 1175 return 0; 1176 } 1177