linux/drivers/edac/debugfs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2#include "edac_module.h"
   3
   4static struct dentry *edac_debugfs;
   5
   6static ssize_t edac_fake_inject_write(struct file *file,
   7                                      const char __user *data,
   8                                      size_t count, loff_t *ppos)
   9{
  10        struct device *dev = file->private_data;
  11        struct mem_ctl_info *mci = to_mci(dev);
  12        static enum hw_event_mc_err_type type;
  13        u16 errcount = mci->fake_inject_count;
  14
  15        if (!errcount)
  16                errcount = 1;
  17
  18        type = mci->fake_inject_ue ? HW_EVENT_ERR_UNCORRECTED
  19                                   : HW_EVENT_ERR_CORRECTED;
  20
  21        printk(KERN_DEBUG
  22               "Generating %d %s fake error%s to %d.%d.%d to test core handling. NOTE: this won't test the driver-specific decoding logic.\n",
  23                errcount,
  24                (type == HW_EVENT_ERR_UNCORRECTED) ? "UE" : "CE",
  25                errcount > 1 ? "s" : "",
  26                mci->fake_inject_layer[0],
  27                mci->fake_inject_layer[1],
  28                mci->fake_inject_layer[2]
  29               );
  30        edac_mc_handle_error(type, mci, errcount, 0, 0, 0,
  31                             mci->fake_inject_layer[0],
  32                             mci->fake_inject_layer[1],
  33                             mci->fake_inject_layer[2],
  34                             "FAKE ERROR", "for EDAC testing only");
  35
  36        return count;
  37}
  38
  39static const struct file_operations debug_fake_inject_fops = {
  40        .open = simple_open,
  41        .write = edac_fake_inject_write,
  42        .llseek = generic_file_llseek,
  43};
  44
  45void __init edac_debugfs_init(void)
  46{
  47        edac_debugfs = debugfs_create_dir("edac", NULL);
  48}
  49
  50void edac_debugfs_exit(void)
  51{
  52        debugfs_remove_recursive(edac_debugfs);
  53}
  54
  55void edac_create_debugfs_nodes(struct mem_ctl_info *mci)
  56{
  57        struct dentry *parent;
  58        char name[80];
  59        int i;
  60
  61        parent = debugfs_create_dir(mci->dev.kobj.name, edac_debugfs);
  62
  63        for (i = 0; i < mci->n_layers; i++) {
  64                sprintf(name, "fake_inject_%s",
  65                             edac_layer_name[mci->layers[i].type]);
  66                debugfs_create_u8(name, S_IRUGO | S_IWUSR, parent,
  67                                  &mci->fake_inject_layer[i]);
  68        }
  69
  70        debugfs_create_bool("fake_inject_ue", S_IRUGO | S_IWUSR, parent,
  71                            &mci->fake_inject_ue);
  72
  73        debugfs_create_u16("fake_inject_count", S_IRUGO | S_IWUSR, parent,
  74                           &mci->fake_inject_count);
  75
  76        debugfs_create_file("fake_inject", S_IWUSR, parent, &mci->dev,
  77                            &debug_fake_inject_fops);
  78
  79        mci->debugfs = parent;
  80}
  81
  82/* Create a toplevel dir under EDAC's debugfs hierarchy */
  83struct dentry *edac_debugfs_create_dir(const char *dirname)
  84{
  85        if (!edac_debugfs)
  86                return NULL;
  87
  88        return debugfs_create_dir(dirname, edac_debugfs);
  89}
  90EXPORT_SYMBOL_GPL(edac_debugfs_create_dir);
  91
  92/* Create a toplevel dir under EDAC's debugfs hierarchy with parent @parent */
  93struct dentry *
  94edac_debugfs_create_dir_at(const char *dirname, struct dentry *parent)
  95{
  96        return debugfs_create_dir(dirname, parent);
  97}
  98EXPORT_SYMBOL_GPL(edac_debugfs_create_dir_at);
  99
 100/*
 101 * Create a file under EDAC's hierarchy or a sub-hierarchy:
 102 *
 103 * @name: file name
 104 * @mode: file permissions
 105 * @parent: parent dentry. If NULL, it becomes the toplevel EDAC dir
 106 * @data: private data of caller
 107 * @fops: file operations of this file
 108 */
 109struct dentry *
 110edac_debugfs_create_file(const char *name, umode_t mode, struct dentry *parent,
 111                         void *data, const struct file_operations *fops)
 112{
 113        if (!parent)
 114                parent = edac_debugfs;
 115
 116        return debugfs_create_file(name, mode, parent, data, fops);
 117}
 118EXPORT_SYMBOL_GPL(edac_debugfs_create_file);
 119
 120/* Wrapper for debugfs_create_x8() */
 121void edac_debugfs_create_x8(const char *name, umode_t mode,
 122                            struct dentry *parent, u8 *value)
 123{
 124        if (!parent)
 125                parent = edac_debugfs;
 126
 127        debugfs_create_x8(name, mode, parent, value);
 128}
 129EXPORT_SYMBOL_GPL(edac_debugfs_create_x8);
 130
 131/* Wrapper for debugfs_create_x16() */
 132void edac_debugfs_create_x16(const char *name, umode_t mode,
 133                             struct dentry *parent, u16 *value)
 134{
 135        if (!parent)
 136                parent = edac_debugfs;
 137
 138        debugfs_create_x16(name, mode, parent, value);
 139}
 140EXPORT_SYMBOL_GPL(edac_debugfs_create_x16);
 141
 142/* Wrapper for debugfs_create_x32() */
 143void edac_debugfs_create_x32(const char *name, umode_t mode,
 144                             struct dentry *parent, u32 *value)
 145{
 146        if (!parent)
 147                parent = edac_debugfs;
 148
 149        debugfs_create_x32(name, mode, parent, value);
 150}
 151EXPORT_SYMBOL_GPL(edac_debugfs_create_x32);
 152