Commit 452a6bf955ee1842361742833e40e046287308f4
1 parent
8ad6c78a69
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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>
Showing 2 changed files with 94 additions and 0 deletions Side-by-side Diff
drivers/edac/edac_mc_sysfs.c
... | ... | @@ -17,6 +17,7 @@ |
17 | 17 | #include <linux/edac.h> |
18 | 18 | #include <linux/bug.h> |
19 | 19 | #include <linux/pm_runtime.h> |
20 | +#include <linux/uaccess.h> | |
20 | 21 | |
21 | 22 | #include "edac_core.h" |
22 | 23 | #include "edac_module.h" |
... | ... | @@ -783,6 +784,47 @@ |
783 | 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 | 828 | /* default Control file */ |
787 | 829 | DEVICE_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store); |
788 | 830 | |
... | ... | @@ -833,6 +875,45 @@ |
833 | 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 | 918 | * Create a new Memory Controller kobject instance, |
838 | 919 | * mc<id> under the 'mc' directory |
... | ... | @@ -911,6 +992,9 @@ |
911 | 992 | goto fail; |
912 | 993 | #endif |
913 | 994 | |
995 | +#ifdef CONFIG_EDAC_DEBUG | |
996 | + edac_create_debug_nodes(mci); | |
997 | +#endif | |
914 | 998 | return 0; |
915 | 999 | |
916 | 1000 | fail: |
... | ... | @@ -937,6 +1021,9 @@ |
937 | 1021 | |
938 | 1022 | debugf0("%s()\n", __func__); |
939 | 1023 | |
1024 | +#ifdef CONFIG_EDAC_DEBUG | |
1025 | + debugfs_remove(mci->debugfs); | |
1026 | +#endif | |
940 | 1027 | #ifdef CONFIG_EDAC_LEGACY_SYSFS |
941 | 1028 | edac_delete_csrow_objects(mci); |
942 | 1029 | #endif |
include/linux/edac.h
... | ... | @@ -17,6 +17,7 @@ |
17 | 17 | #include <linux/kobject.h> |
18 | 18 | #include <linux/completion.h> |
19 | 19 | #include <linux/workqueue.h> |
20 | +#include <linux/debugfs.h> | |
20 | 21 | |
21 | 22 | struct device; |
22 | 23 | |
... | ... | @@ -634,6 +635,12 @@ |
634 | 635 | |
635 | 636 | /* the internal state of this controller instance */ |
636 | 637 | int op_state; |
638 | + | |
639 | +#ifdef CONFIG_EDAC_DEBUG | |
640 | + struct dentry *debugfs; | |
641 | + u8 fake_inject_layer[EDAC_MAX_LAYERS]; | |
642 | + u32 fake_inject_ue; | |
643 | +#endif | |
637 | 644 | }; |
638 | 645 | |
639 | 646 | #endif |