aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2012-03-21 16:06:53 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-06-11 12:23:42 -0400
commit199747106934c4dc9cf90d37538f989e29420833 (patch)
tree53c7f6b7c0c7fb65efd0694205f9ecfafd57bfc4
parentd90c008963ef638cb7ab7d5eb76362b3c2d379bc (diff)
edac: add a new per-dimm API and make the old per-virtual-rank API obsolete
The old EDAC API is broken. It only works fine for systems manufatured before 2005 and for AMD 64. The reason is that it forces all memory controller drivers to discover rank info. Also, it doesn't allow grouping the several ranks into a DIMM. So, what almost all modern drivers do is to create a fake virtual-rank information, and use it to cheat the EDAC core to accept the driver. While this works if the user has enough time to discover what DIMM slot corresponds to each "virtual-rank" information, it prevents EDAC usage for users with less available time. It also makes life hard for vendors that may want to provide a table with their motherboards to the userspace tool (edac-utils) as each driver has its own logic for the virtual mapping. So, the old API should be removed, in favor of a more flexible API that allows newer drivers to not lie to the EDAC core. Reviewed-by: Aristeu Rozanski <arozansk@redhat.com> Cc: Doug Thompson <norsk5@yahoo.com> Cc: Borislav Petkov <borislav.petkov@amd.com> Cc: Randy Dunlap <rdunlap@xenotime.net> Cc: Josh Boyer <jwboyer@redhat.com> Cc: Hui Wang <jason77.wang@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/edac/Kconfig8
-rw-r--r--drivers/edac/edac_mc_sysfs.c165
2 files changed, 172 insertions, 1 deletions
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index fdffa1beca17..3b3f84ff351f 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -31,6 +31,14 @@ if EDAC
31 31
32comment "Reporting subsystems" 32comment "Reporting subsystems"
33 33
34config EDAC_LEGACY_SYSFS
35 bool "EDAC legacy sysfs"
36 default y
37 help
38 Enable the compatibility sysfs nodes.
39 Use 'Y' if your edac utilities aren't ported to work with the newer
40 structures.
41
34config EDAC_DEBUG 42config EDAC_DEBUG
35 bool "Debugging" 43 bool "Debugging"
36 help 44 help
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index 7002c9cab999..86da1767f86e 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -130,6 +130,7 @@ static const char *edac_caps[] = {
130 [EDAC_S16ECD16ED] = "S16ECD16ED" 130 [EDAC_S16ECD16ED] = "S16ECD16ED"
131}; 131};
132 132
133#ifdef CONFIG_EDAC_LEGACY_SYSFS
133/* 134/*
134 * EDAC sysfs CSROW data structures and methods 135 * EDAC sysfs CSROW data structures and methods
135 */ 136 */
@@ -443,6 +444,159 @@ static void edac_delete_csrow_objects(struct mem_ctl_info *mci)
443 device_del(&mci->csrows[i].dev); 444 device_del(&mci->csrows[i].dev);
444 } 445 }
445} 446}
447#endif
448
449/*
450 * Per-dimm (or per-rank) devices
451 */
452
453#define to_dimm(k) container_of(k, struct dimm_info, dev)
454
455/* show/store functions for DIMM Label attributes */
456static ssize_t dimmdev_location_show(struct device *dev,
457 struct device_attribute *mattr, char *data)
458{
459 struct dimm_info *dimm = to_dimm(dev);
460 struct mem_ctl_info *mci = dimm->mci;
461 int i;
462 char *p = data;
463
464 for (i = 0; i < mci->n_layers; i++) {
465 p += sprintf(p, "%s %d ",
466 edac_layer_name[mci->layers[i].type],
467 dimm->location[i]);
468 }
469
470 return p - data;
471}
472
473static ssize_t dimmdev_label_show(struct device *dev,
474 struct device_attribute *mattr, char *data)
475{
476 struct dimm_info *dimm = to_dimm(dev);
477
478 /* if field has not been initialized, there is nothing to send */
479 if (!dimm->label[0])
480 return 0;
481
482 return snprintf(data, EDAC_MC_LABEL_LEN, "%s\n", dimm->label);
483}
484
485static ssize_t dimmdev_label_store(struct device *dev,
486 struct device_attribute *mattr,
487 const char *data,
488 size_t count)
489{
490 struct dimm_info *dimm = to_dimm(dev);
491
492 ssize_t max_size = 0;
493
494 max_size = min((ssize_t) count, (ssize_t) EDAC_MC_LABEL_LEN - 1);
495 strncpy(dimm->label, data, max_size);
496 dimm->label[max_size] = '\0';
497
498 return max_size;
499}
500
501static ssize_t dimmdev_size_show(struct device *dev,
502 struct device_attribute *mattr, char *data)
503{
504 struct dimm_info *dimm = to_dimm(dev);
505
506 return sprintf(data, "%u\n", PAGES_TO_MiB(dimm->nr_pages));
507}
508
509static ssize_t dimmdev_mem_type_show(struct device *dev,
510 struct device_attribute *mattr, char *data)
511{
512 struct dimm_info *dimm = to_dimm(dev);
513
514 return sprintf(data, "%s\n", mem_types[dimm->mtype]);
515}
516
517static ssize_t dimmdev_dev_type_show(struct device *dev,
518 struct device_attribute *mattr, char *data)
519{
520 struct dimm_info *dimm = to_dimm(dev);
521
522 return sprintf(data, "%s\n", dev_types[dimm->dtype]);
523}
524
525static ssize_t dimmdev_edac_mode_show(struct device *dev,
526 struct device_attribute *mattr,
527 char *data)
528{
529 struct dimm_info *dimm = to_dimm(dev);
530
531 return sprintf(data, "%s\n", edac_caps[dimm->edac_mode]);
532}
533
534/* dimm/rank attribute files */
535static DEVICE_ATTR(dimm_label, S_IRUGO | S_IWUSR,
536 dimmdev_label_show, dimmdev_label_store);
537static DEVICE_ATTR(dimm_location, S_IRUGO, dimmdev_location_show, NULL);
538static DEVICE_ATTR(size, S_IRUGO, dimmdev_size_show, NULL);
539static DEVICE_ATTR(dimm_mem_type, S_IRUGO, dimmdev_mem_type_show, NULL);
540static DEVICE_ATTR(dimm_dev_type, S_IRUGO, dimmdev_dev_type_show, NULL);
541static DEVICE_ATTR(dimm_edac_mode, S_IRUGO, dimmdev_edac_mode_show, NULL);
542
543/* attributes of the dimm<id>/rank<id> object */
544static struct attribute *dimm_attrs[] = {
545 &dev_attr_dimm_label.attr,
546 &dev_attr_dimm_location.attr,
547 &dev_attr_size.attr,
548 &dev_attr_dimm_mem_type.attr,
549 &dev_attr_dimm_dev_type.attr,
550 &dev_attr_dimm_edac_mode.attr,
551 NULL,
552};
553
554static struct attribute_group dimm_attr_grp = {
555 .attrs = dimm_attrs,
556};
557
558static const struct attribute_group *dimm_attr_groups[] = {
559 &dimm_attr_grp,
560 NULL
561};
562
563static void dimm_attr_release(struct device *device)
564{
565 debugf1("Releasing dimm device %s\n", dev_name(device));
566}
567
568static struct device_type dimm_attr_type = {
569 .groups = dimm_attr_groups,
570 .release = dimm_attr_release,
571};
572
573/* Create a DIMM object under specifed memory controller device */
574static int edac_create_dimm_object(struct mem_ctl_info *mci,
575 struct dimm_info *dimm,
576 int index)
577{
578 int err;
579 dimm->mci = mci;
580
581 dimm->dev.type = &dimm_attr_type;
582 dimm->dev.bus = &mci->bus;
583 device_initialize(&dimm->dev);
584
585 dimm->dev.parent = &mci->dev;
586 if (mci->mem_is_per_rank)
587 dev_set_name(&dimm->dev, "rank%d", index);
588 else
589 dev_set_name(&dimm->dev, "dimm%d", index);
590 dev_set_drvdata(&dimm->dev, dimm);
591 pm_runtime_forbid(&mci->dev);
592
593 err = device_add(&dimm->dev);
594
595 debugf0("%s(): creating rank/dimm device %s\n", __func__,
596 dev_name(&dimm->dev));
597
598 return err;
599}
446 600
447/* 601/*
448 * Memory controller device 602 * Memory controller device
@@ -660,7 +814,6 @@ static struct device_type mci_attr_type = {
660 .release = mci_attr_release, 814 .release = mci_attr_release,
661}; 815};
662 816
663
664/* 817/*
665 * Create a new Memory Controller kobject instance, 818 * Create a new Memory Controller kobject instance,
666 * mc<id> under the 'mc' directory 819 * mc<id> under the 'mc' directory
@@ -725,11 +878,19 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
725 printk(KERN_CONT "\n"); 878 printk(KERN_CONT "\n");
726 } 879 }
727#endif 880#endif
881 err = edac_create_dimm_object(mci, dimm, i);
882 if (err) {
883 debugf1("%s() failure: create dimm %d obj\n",
884 __func__, i);
885 goto fail;
886 }
728 } 887 }
729 888
889#ifdef CONFIG_EDAC_LEGACY_SYSFS
730 err = edac_create_csrow_objects(mci); 890 err = edac_create_csrow_objects(mci);
731 if (err < 0) 891 if (err < 0)
732 goto fail; 892 goto fail;
893#endif
733 894
734 return 0; 895 return 0;
735 896
@@ -757,7 +918,9 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
757 918
758 debugf0("%s()\n", __func__); 919 debugf0("%s()\n", __func__);
759 920
921#ifdef CONFIG_EDAC_LEGACY_SYSFS
760 edac_delete_csrow_objects(mci); 922 edac_delete_csrow_objects(mci);
923#endif
761 924
762 for (i = 0; i < mci->tot_dimms; i++) { 925 for (i = 0; i < mci->tot_dimms; i++) {
763 struct dimm_info *dimm = &mci->dimms[i]; 926 struct dimm_info *dimm = &mci->dimms[i];