diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-03-26 08:35:11 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-06-11 12:23:43 -0400 |
commit | 452a6bf955ee1842361742833e40e046287308f4 (patch) | |
tree | 2e4fb61fbbf32f17d80d9fce27a985361e6fc9af /drivers/edac/edac_mc_sysfs.c | |
parent | 8ad6c78a69ac5c74e8f4e8c78cdb86772face433 (diff) |
edac: Add debufs nodes to allow doing fake error inject
Sometimes, it is useful to have a mechanism that generates fake
errors, in order to test the EDAC core code, and the userspace
tools.
Provide such mechanism by adding a few debugfs nodes.
Reviewed-by: Aristeu Rozanski <arozansk@redhat.com>
Cc: Doug Thompson <norsk5@yahoo.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/edac/edac_mc_sysfs.c')
-rw-r--r-- | drivers/edac/edac_mc_sysfs.c | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 87fb396bc550..daa418b61525 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/edac.h> | 17 | #include <linux/edac.h> |
18 | #include <linux/bug.h> | 18 | #include <linux/bug.h> |
19 | #include <linux/pm_runtime.h> | 19 | #include <linux/pm_runtime.h> |
20 | #include <linux/uaccess.h> | ||
20 | 21 | ||
21 | #include "edac_core.h" | 22 | #include "edac_core.h" |
22 | #include "edac_module.h" | 23 | #include "edac_module.h" |
@@ -783,6 +784,47 @@ static ssize_t mci_max_location_show(struct device *dev, | |||
783 | return p - data; | 784 | return p - data; |
784 | } | 785 | } |
785 | 786 | ||
787 | #ifdef CONFIG_EDAC_DEBUG | ||
788 | static ssize_t edac_fake_inject_write(struct file *file, | ||
789 | const char __user *data, | ||
790 | size_t count, loff_t *ppos) | ||
791 | { | ||
792 | struct device *dev = file->private_data; | ||
793 | struct mem_ctl_info *mci = to_mci(dev); | ||
794 | static enum hw_event_mc_err_type type; | ||
795 | |||
796 | type = mci->fake_inject_ue ? HW_EVENT_ERR_UNCORRECTED | ||
797 | : HW_EVENT_ERR_CORRECTED; | ||
798 | |||
799 | printk(KERN_DEBUG | ||
800 | "Generating a %s fake error to %d.%d.%d to test core handling. NOTE: this won't test the driver-specific decoding logic.\n", | ||
801 | (type == HW_EVENT_ERR_UNCORRECTED) ? "UE" : "CE", | ||
802 | mci->fake_inject_layer[0], | ||
803 | mci->fake_inject_layer[1], | ||
804 | mci->fake_inject_layer[2] | ||
805 | ); | ||
806 | edac_mc_handle_error(type, mci, 0, 0, 0, | ||
807 | mci->fake_inject_layer[0], | ||
808 | mci->fake_inject_layer[1], | ||
809 | mci->fake_inject_layer[2], | ||
810 | "FAKE ERROR", "for EDAC testing only", NULL); | ||
811 | |||
812 | return count; | ||
813 | } | ||
814 | |||
815 | static int debugfs_open(struct inode *inode, struct file *file) | ||
816 | { | ||
817 | file->private_data = inode->i_private; | ||
818 | return 0; | ||
819 | } | ||
820 | |||
821 | static const struct file_operations debug_fake_inject_fops = { | ||
822 | .open = debugfs_open, | ||
823 | .write = edac_fake_inject_write, | ||
824 | .llseek = generic_file_llseek, | ||
825 | }; | ||
826 | #endif | ||
827 | |||
786 | /* default Control file */ | 828 | /* default Control file */ |
787 | DEVICE_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store); | 829 | DEVICE_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store); |
788 | 830 | ||
@@ -833,6 +875,45 @@ static struct device_type mci_attr_type = { | |||
833 | .release = mci_attr_release, | 875 | .release = mci_attr_release, |
834 | }; | 876 | }; |
835 | 877 | ||
878 | #ifdef CONFIG_EDAC_DEBUG | ||
879 | int edac_create_debug_nodes(struct mem_ctl_info *mci) | ||
880 | { | ||
881 | struct dentry *d, *parent; | ||
882 | char name[80]; | ||
883 | int i; | ||
884 | |||
885 | d = debugfs_create_dir(mci->dev.kobj.name, mci->debugfs); | ||
886 | if (!d) | ||
887 | return -ENOMEM; | ||
888 | parent = d; | ||
889 | |||
890 | for (i = 0; i < mci->n_layers; i++) { | ||
891 | sprintf(name, "fake_inject_%s", | ||
892 | edac_layer_name[mci->layers[i].type]); | ||
893 | d = debugfs_create_u8(name, S_IRUGO | S_IWUSR, parent, | ||
894 | &mci->fake_inject_layer[i]); | ||
895 | if (!d) | ||
896 | goto nomem; | ||
897 | } | ||
898 | |||
899 | d = debugfs_create_bool("fake_inject_ue", S_IRUGO | S_IWUSR, parent, | ||
900 | &mci->fake_inject_ue); | ||
901 | if (!d) | ||
902 | goto nomem; | ||
903 | |||
904 | d = debugfs_create_file("fake_inject", S_IWUSR, parent, | ||
905 | &mci->dev, | ||
906 | &debug_fake_inject_fops); | ||
907 | if (!d) | ||
908 | goto nomem; | ||
909 | |||
910 | return 0; | ||
911 | nomem: | ||
912 | debugfs_remove(mci->debugfs); | ||
913 | return -ENOMEM; | ||
914 | } | ||
915 | #endif | ||
916 | |||
836 | /* | 917 | /* |
837 | * Create a new Memory Controller kobject instance, | 918 | * Create a new Memory Controller kobject instance, |
838 | * mc<id> under the 'mc' directory | 919 | * mc<id> under the 'mc' directory |
@@ -911,6 +992,9 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) | |||
911 | goto fail; | 992 | goto fail; |
912 | #endif | 993 | #endif |
913 | 994 | ||
995 | #ifdef CONFIG_EDAC_DEBUG | ||
996 | edac_create_debug_nodes(mci); | ||
997 | #endif | ||
914 | return 0; | 998 | return 0; |
915 | 999 | ||
916 | fail: | 1000 | fail: |
@@ -937,6 +1021,9 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) | |||
937 | 1021 | ||
938 | debugf0("%s()\n", __func__); | 1022 | debugf0("%s()\n", __func__); |
939 | 1023 | ||
1024 | #ifdef CONFIG_EDAC_DEBUG | ||
1025 | debugfs_remove(mci->debugfs); | ||
1026 | #endif | ||
940 | #ifdef CONFIG_EDAC_LEGACY_SYSFS | 1027 | #ifdef CONFIG_EDAC_LEGACY_SYSFS |
941 | edac_delete_csrow_objects(mci); | 1028 | edac_delete_csrow_objects(mci); |
942 | #endif | 1029 | #endif |