1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/ctype.h>
14#include <linux/module.h>
15#include <linux/slab.h>
16#include <linux/edac.h>
17
18#include "edac_core.h"
19#include "edac_module.h"
20
21#define EDAC_DEVICE_SYMLINK "device"
22
23#define to_edacdev(k) container_of(k, struct edac_device_ctl_info, kobj)
24#define to_edacdev_attr(a) container_of(a, struct edacdev_attribute, attr)
25
26
27
28
29
30
31
32static ssize_t edac_device_ctl_log_ue_show(struct edac_device_ctl_info
33 *ctl_info, char *data)
34{
35 return sprintf(data, "%u\n", ctl_info->log_ue);
36}
37
38static ssize_t edac_device_ctl_log_ue_store(struct edac_device_ctl_info
39 *ctl_info, const char *data,
40 size_t count)
41{
42
43 ctl_info->log_ue = (simple_strtoul(data, NULL, 0) != 0);
44
45 return count;
46}
47
48
49static ssize_t edac_device_ctl_log_ce_show(struct edac_device_ctl_info
50 *ctl_info, char *data)
51{
52 return sprintf(data, "%u\n", ctl_info->log_ce);
53}
54
55static ssize_t edac_device_ctl_log_ce_store(struct edac_device_ctl_info
56 *ctl_info, const char *data,
57 size_t count)
58{
59
60 ctl_info->log_ce = (simple_strtoul(data, NULL, 0) != 0);
61
62 return count;
63}
64
65
66static ssize_t edac_device_ctl_panic_on_ue_show(struct edac_device_ctl_info
67 *ctl_info, char *data)
68{
69 return sprintf(data, "%u\n", ctl_info->panic_on_ue);
70}
71
72static ssize_t edac_device_ctl_panic_on_ue_store(struct edac_device_ctl_info
73 *ctl_info, const char *data,
74 size_t count)
75{
76
77 ctl_info->panic_on_ue = (simple_strtoul(data, NULL, 0) != 0);
78
79 return count;
80}
81
82
83static ssize_t edac_device_ctl_poll_msec_show(struct edac_device_ctl_info
84 *ctl_info, char *data)
85{
86 return sprintf(data, "%u\n", ctl_info->poll_msec);
87}
88
89static ssize_t edac_device_ctl_poll_msec_store(struct edac_device_ctl_info
90 *ctl_info, const char *data,
91 size_t count)
92{
93 unsigned long value;
94
95
96
97
98
99
100 value = simple_strtoul(data, NULL, 0);
101 edac_device_reset_delay_period(ctl_info, value);
102
103 return count;
104}
105
106
107struct ctl_info_attribute {
108 struct attribute attr;
109 ssize_t(*show) (struct edac_device_ctl_info *, char *);
110 ssize_t(*store) (struct edac_device_ctl_info *, const char *, size_t);
111};
112
113#define to_ctl_info(k) container_of(k, struct edac_device_ctl_info, kobj)
114#define to_ctl_info_attr(a) container_of(a,struct ctl_info_attribute,attr)
115
116
117static ssize_t edac_dev_ctl_info_show(struct kobject *kobj,
118 struct attribute *attr, char *buffer)
119{
120 struct edac_device_ctl_info *edac_dev = to_ctl_info(kobj);
121 struct ctl_info_attribute *ctl_info_attr = to_ctl_info_attr(attr);
122
123 if (ctl_info_attr->show)
124 return ctl_info_attr->show(edac_dev, buffer);
125 return -EIO;
126}
127
128
129static ssize_t edac_dev_ctl_info_store(struct kobject *kobj,
130 struct attribute *attr,
131 const char *buffer, size_t count)
132{
133 struct edac_device_ctl_info *edac_dev = to_ctl_info(kobj);
134 struct ctl_info_attribute *ctl_info_attr = to_ctl_info_attr(attr);
135
136 if (ctl_info_attr->store)
137 return ctl_info_attr->store(edac_dev, buffer, count);
138 return -EIO;
139}
140
141
142static const struct sysfs_ops device_ctl_info_ops = {
143 .show = edac_dev_ctl_info_show,
144 .store = edac_dev_ctl_info_store
145};
146
147#define CTL_INFO_ATTR(_name,_mode,_show,_store) \
148static struct ctl_info_attribute attr_ctl_info_##_name = { \
149 .attr = {.name = __stringify(_name), .mode = _mode }, \
150 .show = _show, \
151 .store = _store, \
152};
153
154
155CTL_INFO_ATTR(log_ue, S_IRUGO | S_IWUSR,
156 edac_device_ctl_log_ue_show, edac_device_ctl_log_ue_store);
157CTL_INFO_ATTR(log_ce, S_IRUGO | S_IWUSR,
158 edac_device_ctl_log_ce_show, edac_device_ctl_log_ce_store);
159CTL_INFO_ATTR(panic_on_ue, S_IRUGO | S_IWUSR,
160 edac_device_ctl_panic_on_ue_show,
161 edac_device_ctl_panic_on_ue_store);
162CTL_INFO_ATTR(poll_msec, S_IRUGO | S_IWUSR,
163 edac_device_ctl_poll_msec_show, edac_device_ctl_poll_msec_store);
164
165
166static struct ctl_info_attribute *device_ctrl_attr[] = {
167 &attr_ctl_info_panic_on_ue,
168 &attr_ctl_info_log_ue,
169 &attr_ctl_info_log_ce,
170 &attr_ctl_info_poll_msec,
171 NULL,
172};
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201static void edac_device_ctrl_master_release(struct kobject *kobj)
202{
203 struct edac_device_ctl_info *edac_dev = to_edacdev(kobj);
204
205 edac_dbg(4, "control index=%d\n", edac_dev->dev_idx);
206
207
208 module_put(edac_dev->owner);
209
210
211
212
213 kfree(edac_dev);
214}
215
216
217static struct kobj_type ktype_device_ctrl = {
218 .release = edac_device_ctrl_master_release,
219 .sysfs_ops = &device_ctl_info_ops,
220 .default_attrs = (struct attribute **)device_ctrl_attr,
221};
222
223
224
225
226
227
228
229
230
231int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
232{
233 struct bus_type *edac_subsys;
234 int err;
235
236 edac_dbg(1, "\n");
237
238
239 edac_subsys = edac_get_sysfs_subsys();
240 if (edac_subsys == NULL) {
241 edac_dbg(1, "no edac_subsys error\n");
242 err = -ENODEV;
243 goto err_out;
244 }
245
246
247 edac_dev->edac_subsys = edac_subsys;
248
249
250 memset(&edac_dev->kobj, 0, sizeof(struct kobject));
251
252
253
254
255 edac_dev->owner = THIS_MODULE;
256
257 if (!try_module_get(edac_dev->owner)) {
258 err = -ENODEV;
259 goto err_mod_get;
260 }
261
262
263 err = kobject_init_and_add(&edac_dev->kobj, &ktype_device_ctrl,
264 &edac_subsys->dev_root->kobj,
265 "%s", edac_dev->name);
266 if (err) {
267 edac_dbg(1, "Failed to register '.../edac/%s'\n",
268 edac_dev->name);
269 goto err_kobj_reg;
270 }
271 kobject_uevent(&edac_dev->kobj, KOBJ_ADD);
272
273
274
275
276
277 edac_dbg(4, "Registered '.../edac/%s' kobject\n", edac_dev->name);
278
279 return 0;
280
281
282err_kobj_reg:
283 module_put(edac_dev->owner);
284
285err_mod_get:
286 edac_put_sysfs_subsys();
287
288err_out:
289 return err;
290}
291
292
293
294
295
296void edac_device_unregister_sysfs_main_kobj(struct edac_device_ctl_info *dev)
297{
298 edac_dbg(0, "\n");
299 edac_dbg(4, "name of kobject is: %s\n", kobject_name(&dev->kobj));
300
301
302
303
304
305
306
307
308 kobject_put(&dev->kobj);
309 edac_put_sysfs_subsys();
310}
311
312
313
314
315
316
317static ssize_t instance_ue_count_show(struct edac_device_instance *instance,
318 char *data)
319{
320 return sprintf(data, "%u\n", instance->counters.ue_count);
321}
322
323static ssize_t instance_ce_count_show(struct edac_device_instance *instance,
324 char *data)
325{
326 return sprintf(data, "%u\n", instance->counters.ce_count);
327}
328
329#define to_instance(k) container_of(k, struct edac_device_instance, kobj)
330#define to_instance_attr(a) container_of(a,struct instance_attribute,attr)
331
332
333static void edac_device_ctrl_instance_release(struct kobject *kobj)
334{
335 struct edac_device_instance *instance;
336
337 edac_dbg(1, "\n");
338
339
340
341
342 instance = to_instance(kobj);
343 kobject_put(&instance->ctl->kobj);
344}
345
346
347struct instance_attribute {
348 struct attribute attr;
349 ssize_t(*show) (struct edac_device_instance *, char *);
350 ssize_t(*store) (struct edac_device_instance *, const char *, size_t);
351};
352
353
354static ssize_t edac_dev_instance_show(struct kobject *kobj,
355 struct attribute *attr, char *buffer)
356{
357 struct edac_device_instance *instance = to_instance(kobj);
358 struct instance_attribute *instance_attr = to_instance_attr(attr);
359
360 if (instance_attr->show)
361 return instance_attr->show(instance, buffer);
362 return -EIO;
363}
364
365
366static ssize_t edac_dev_instance_store(struct kobject *kobj,
367 struct attribute *attr,
368 const char *buffer, size_t count)
369{
370 struct edac_device_instance *instance = to_instance(kobj);
371 struct instance_attribute *instance_attr = to_instance_attr(attr);
372
373 if (instance_attr->store)
374 return instance_attr->store(instance, buffer, count);
375 return -EIO;
376}
377
378
379static const struct sysfs_ops device_instance_ops = {
380 .show = edac_dev_instance_show,
381 .store = edac_dev_instance_store
382};
383
384#define INSTANCE_ATTR(_name,_mode,_show,_store) \
385static struct instance_attribute attr_instance_##_name = { \
386 .attr = {.name = __stringify(_name), .mode = _mode }, \
387 .show = _show, \
388 .store = _store, \
389};
390
391
392
393
394
395
396INSTANCE_ATTR(ce_count, S_IRUGO, instance_ce_count_show, NULL);
397INSTANCE_ATTR(ue_count, S_IRUGO, instance_ue_count_show, NULL);
398
399
400static struct instance_attribute *device_instance_attr[] = {
401 &attr_instance_ce_count,
402 &attr_instance_ue_count,
403 NULL,
404};
405
406
407static struct kobj_type ktype_instance_ctrl = {
408 .release = edac_device_ctrl_instance_release,
409 .sysfs_ops = &device_instance_ops,
410 .default_attrs = (struct attribute **)device_instance_attr,
411};
412
413
414
415#define to_block(k) container_of(k, struct edac_device_block, kobj)
416#define to_block_attr(a) \
417 container_of(a, struct edac_dev_sysfs_block_attribute, attr)
418
419
420
421
422static ssize_t block_ue_count_show(struct kobject *kobj,
423 struct attribute *attr, char *data)
424{
425 struct edac_device_block *block = to_block(kobj);
426
427 return sprintf(data, "%u\n", block->counters.ue_count);
428}
429
430static ssize_t block_ce_count_show(struct kobject *kobj,
431 struct attribute *attr, char *data)
432{
433 struct edac_device_block *block = to_block(kobj);
434
435 return sprintf(data, "%u\n", block->counters.ce_count);
436}
437
438
439static void edac_device_ctrl_block_release(struct kobject *kobj)
440{
441 struct edac_device_block *block;
442
443 edac_dbg(1, "\n");
444
445
446 block = to_block(kobj);
447
448
449
450
451 kobject_put(&block->instance->ctl->kobj);
452}
453
454
455
456static ssize_t edac_dev_block_show(struct kobject *kobj,
457 struct attribute *attr, char *buffer)
458{
459 struct edac_dev_sysfs_block_attribute *block_attr =
460 to_block_attr(attr);
461
462 if (block_attr->show)
463 return block_attr->show(kobj, attr, buffer);
464 return -EIO;
465}
466
467
468static ssize_t edac_dev_block_store(struct kobject *kobj,
469 struct attribute *attr,
470 const char *buffer, size_t count)
471{
472 struct edac_dev_sysfs_block_attribute *block_attr;
473
474 block_attr = to_block_attr(attr);
475
476 if (block_attr->store)
477 return block_attr->store(kobj, attr, buffer, count);
478 return -EIO;
479}
480
481
482static const struct sysfs_ops device_block_ops = {
483 .show = edac_dev_block_show,
484 .store = edac_dev_block_store
485};
486
487#define BLOCK_ATTR(_name,_mode,_show,_store) \
488static struct edac_dev_sysfs_block_attribute attr_block_##_name = { \
489 .attr = {.name = __stringify(_name), .mode = _mode }, \
490 .show = _show, \
491 .store = _store, \
492};
493
494BLOCK_ATTR(ce_count, S_IRUGO, block_ce_count_show, NULL);
495BLOCK_ATTR(ue_count, S_IRUGO, block_ue_count_show, NULL);
496
497
498static struct edac_dev_sysfs_block_attribute *device_block_attr[] = {
499 &attr_block_ce_count,
500 &attr_block_ue_count,
501 NULL,
502};
503
504
505static struct kobj_type ktype_block_ctrl = {
506 .release = edac_device_ctrl_block_release,
507 .sysfs_ops = &device_block_ops,
508 .default_attrs = (struct attribute **)device_block_attr,
509};
510
511
512
513
514
515
516static int edac_device_create_block(struct edac_device_ctl_info *edac_dev,
517 struct edac_device_instance *instance,
518 struct edac_device_block *block)
519{
520 int i;
521 int err;
522 struct edac_dev_sysfs_block_attribute *sysfs_attrib;
523 struct kobject *main_kobj;
524
525 edac_dbg(4, "Instance '%s' inst_p=%p block '%s' block_p=%p\n",
526 instance->name, instance, block->name, block);
527 edac_dbg(4, "block kobj=%p block kobj->parent=%p\n",
528 &block->kobj, &block->kobj.parent);
529
530
531 memset(&block->kobj, 0, sizeof(struct kobject));
532
533
534
535
536 main_kobj = kobject_get(&edac_dev->kobj);
537 if (!main_kobj) {
538 err = -ENODEV;
539 goto err_out;
540 }
541
542
543 err = kobject_init_and_add(&block->kobj, &ktype_block_ctrl,
544 &instance->kobj,
545 "%s", block->name);
546 if (err) {
547 edac_dbg(1, "Failed to register instance '%s'\n", block->name);
548 kobject_put(main_kobj);
549 err = -ENODEV;
550 goto err_out;
551 }
552
553
554
555
556 sysfs_attrib = block->block_attributes;
557 if (sysfs_attrib && block->nr_attribs) {
558 for (i = 0; i < block->nr_attribs; i++, sysfs_attrib++) {
559
560 edac_dbg(4, "creating block attrib='%s' attrib->%p to kobj=%p\n",
561 sysfs_attrib->attr.name,
562 sysfs_attrib, &block->kobj);
563
564
565 err = sysfs_create_file(&block->kobj,
566 &sysfs_attrib->attr);
567 if (err)
568 goto err_on_attrib;
569 }
570 }
571 kobject_uevent(&block->kobj, KOBJ_ADD);
572
573 return 0;
574
575
576err_on_attrib:
577 kobject_put(&block->kobj);
578
579err_out:
580 return err;
581}
582
583
584
585
586static void edac_device_delete_block(struct edac_device_ctl_info *edac_dev,
587 struct edac_device_block *block)
588{
589 struct edac_dev_sysfs_block_attribute *sysfs_attrib;
590 int i;
591
592
593
594
595 sysfs_attrib = block->block_attributes;
596 if (sysfs_attrib && block->nr_attribs) {
597 for (i = 0; i < block->nr_attribs; i++, sysfs_attrib++) {
598
599
600 sysfs_remove_file(&block->kobj,
601 (struct attribute *) sysfs_attrib);
602 }
603 }
604
605
606
607
608 kobject_put(&block->kobj);
609}
610
611
612
613
614
615
616
617static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev,
618 int idx)
619{
620 int i, j;
621 int err;
622 struct edac_device_instance *instance;
623 struct kobject *main_kobj;
624
625 instance = &edac_dev->instances[idx];
626
627
628 memset(&instance->kobj, 0, sizeof(struct kobject));
629
630 instance->ctl = edac_dev;
631
632
633
634
635 main_kobj = kobject_get(&edac_dev->kobj);
636 if (!main_kobj) {
637 err = -ENODEV;
638 goto err_out;
639 }
640
641
642 err = kobject_init_and_add(&instance->kobj, &ktype_instance_ctrl,
643 &edac_dev->kobj, "%s", instance->name);
644 if (err != 0) {
645 edac_dbg(2, "Failed to register instance '%s'\n",
646 instance->name);
647 kobject_put(main_kobj);
648 goto err_out;
649 }
650
651 edac_dbg(4, "now register '%d' blocks for instance %d\n",
652 instance->nr_blocks, idx);
653
654
655 for (i = 0; i < instance->nr_blocks; i++) {
656 err = edac_device_create_block(edac_dev, instance,
657 &instance->blocks[i]);
658 if (err) {
659
660 for (j = 0; j < i; j++)
661 edac_device_delete_block(edac_dev,
662 &instance->blocks[j]);
663 goto err_release_instance_kobj;
664 }
665 }
666 kobject_uevent(&instance->kobj, KOBJ_ADD);
667
668 edac_dbg(4, "Registered instance %d '%s' kobject\n",
669 idx, instance->name);
670
671 return 0;
672
673
674err_release_instance_kobj:
675 kobject_put(&instance->kobj);
676
677err_out:
678 return err;
679}
680
681
682
683
684
685static void edac_device_delete_instance(struct edac_device_ctl_info *edac_dev,
686 int idx)
687{
688 struct edac_device_instance *instance;
689 int i;
690
691 instance = &edac_dev->instances[idx];
692
693
694 for (i = 0; i < instance->nr_blocks; i++)
695 edac_device_delete_block(edac_dev, &instance->blocks[i]);
696
697
698
699
700 kobject_put(&instance->kobj);
701}
702
703
704
705
706
707
708static int edac_device_create_instances(struct edac_device_ctl_info *edac_dev)
709{
710 int i, j;
711 int err;
712
713 edac_dbg(0, "\n");
714
715
716 for (i = 0; i < edac_dev->nr_instances; i++) {
717 err = edac_device_create_instance(edac_dev, i);
718 if (err) {
719
720 for (j = 0; j < i; j++)
721 edac_device_delete_instance(edac_dev, j);
722 return err;
723 }
724 }
725
726 return 0;
727}
728
729
730
731
732
733static void edac_device_delete_instances(struct edac_device_ctl_info *edac_dev)
734{
735 int i;
736
737
738 for (i = 0; i < edac_dev->nr_instances; i++)
739 edac_device_delete_instance(edac_dev, i);
740}
741
742
743
744
745
746
747
748static int edac_device_add_main_sysfs_attributes(
749 struct edac_device_ctl_info *edac_dev)
750{
751 struct edac_dev_sysfs_attribute *sysfs_attrib;
752 int err = 0;
753
754 sysfs_attrib = edac_dev->sysfs_attributes;
755 if (sysfs_attrib) {
756
757
758
759 while (sysfs_attrib->attr.name != NULL) {
760 err = sysfs_create_file(&edac_dev->kobj,
761 (struct attribute*) sysfs_attrib);
762 if (err)
763 goto err_out;
764
765 sysfs_attrib++;
766 }
767 }
768
769err_out:
770 return err;
771}
772
773
774
775
776
777static void edac_device_remove_main_sysfs_attributes(
778 struct edac_device_ctl_info *edac_dev)
779{
780 struct edac_dev_sysfs_attribute *sysfs_attrib;
781
782
783
784
785
786 sysfs_attrib = edac_dev->sysfs_attributes;
787 if (sysfs_attrib) {
788 while (sysfs_attrib->attr.name != NULL) {
789 sysfs_remove_file(&edac_dev->kobj,
790 (struct attribute *) sysfs_attrib);
791 sysfs_attrib++;
792 }
793 }
794}
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev)
811{
812 int err;
813 struct kobject *edac_kobj = &edac_dev->kobj;
814
815 edac_dbg(0, "idx=%d\n", edac_dev->dev_idx);
816
817
818 err = edac_device_add_main_sysfs_attributes(edac_dev);
819 if (err) {
820 edac_dbg(0, "failed to add sysfs attribs\n");
821 goto err_out;
822 }
823
824
825
826
827 err = sysfs_create_link(edac_kobj,
828 &edac_dev->dev->kobj, EDAC_DEVICE_SYMLINK);
829 if (err) {
830 edac_dbg(0, "sysfs_create_link() returned err= %d\n", err);
831 goto err_remove_main_attribs;
832 }
833
834
835
836
837
838 err = edac_device_create_instances(edac_dev);
839 if (err) {
840 edac_dbg(0, "edac_device_create_instances() returned err= %d\n",
841 err);
842 goto err_remove_link;
843 }
844
845
846 edac_dbg(4, "create-instances done, idx=%d\n", edac_dev->dev_idx);
847
848 return 0;
849
850
851err_remove_link:
852
853 sysfs_remove_link(&edac_dev->kobj, EDAC_DEVICE_SYMLINK);
854
855err_remove_main_attribs:
856 edac_device_remove_main_sysfs_attributes(edac_dev);
857
858err_out:
859 return err;
860}
861
862
863
864
865
866
867void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev)
868{
869 edac_dbg(0, "\n");
870
871
872 edac_device_remove_main_sysfs_attributes(edac_dev);
873
874
875 sysfs_remove_link(&edac_dev->kobj, EDAC_DEVICE_SYMLINK);
876
877
878 edac_device_delete_instances(edac_dev);
879}
880