Skip to content

Commit

Permalink
EDAC, mce_amd_inj: Modify flags attribute to use string arguments
Browse files Browse the repository at this point in the history
Use strings such as "hw" or "sw" to indicate the type of error injection
to be performed.

Current flags attribute derives the meanings of values that can be
programmed into it from asm/mce.h. Moving to defined strings for the
attribute allows this module to be self-sufficient and removes the
dependency. Also, we can introduce new flags as and when needed without
having to worry about conflicting with the flags already defined in
asm/mce.h.

Also, modify do_inject() to use the newly defined injection_type enum to
figure out the injection mechanism we need to use

Suggested-by: Borislav Petkov <[email protected]>
Signed-off-by: Aravind Gopalakrishnan <[email protected]>
Cc: linux-edac <[email protected]>
Cc: [email protected]
Cc: x86-ml <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
[ Use strstrip() return value. ]
Signed-off-by: Borislav Petkov <[email protected]>
  • Loading branch information
Aravind Gopalakrishnan authored and suryasaimadhu committed Jun 3, 2015
1 parent 685d46d commit 0451d14
Showing 1 changed file with 71 additions and 10 deletions.
81 changes: 71 additions & 10 deletions drivers/edac/mce_amd_inj.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#include <linux/device.h>
#include <linux/module.h>
#include <linux/cpu.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include <asm/mce.h>

#include "mce_amd.h"
Expand All @@ -27,6 +29,23 @@ static struct dentry *dfs_inj;

static u8 n_banks;

#define MAX_FLAG_OPT_SIZE 3

enum injection_type {
SW_INJ = 0, /* SW injection, simply decode the error */
HW_INJ, /* Trigger a #MC */
N_INJ_TYPES,
};

static const char * const flags_options[] = {
[SW_INJ] = "sw",
[HW_INJ] = "hw",
NULL
};

/* Set default injection to SW_INJ */
enum injection_type inj_type = SW_INJ;

#define MCE_INJECT_SET(reg) \
static int inj_##reg##_set(void *data, u64 val) \
{ \
Expand Down Expand Up @@ -81,24 +100,66 @@ static int toggle_hw_mce_inject(unsigned int cpu, bool enable)
return err;
}

static int flags_get(void *data, u64 *val)
static int __set_inj(const char *buf)
{
struct mce *m = (struct mce *)data;
int i;

*val = m->inject_flags;
for (i = 0; i < N_INJ_TYPES; i++) {
if (!strncmp(flags_options[i], buf, strlen(flags_options[i]))) {
inj_type = i;
return 0;
}
}
return -EINVAL;
}

return 0;
static ssize_t flags_read(struct file *filp, char __user *ubuf,
size_t cnt, loff_t *ppos)
{
char buf[MAX_FLAG_OPT_SIZE];
int n;

n = sprintf(buf, "%s\n", flags_options[inj_type]);

return simple_read_from_buffer(ubuf, cnt, ppos, buf, n);
}

static int flags_set(void *data, u64 val)
static ssize_t flags_write(struct file *filp, const char __user *ubuf,
size_t cnt, loff_t *ppos)
{
struct mce *m = (struct mce *)data;
char buf[MAX_FLAG_OPT_SIZE], *__buf;
int err;
size_t ret;

m->inject_flags = (u8)val;
return 0;
if (cnt > MAX_FLAG_OPT_SIZE)
cnt = MAX_FLAG_OPT_SIZE;

ret = cnt;

if (copy_from_user(&buf, ubuf, cnt))
return -EFAULT;

buf[cnt - 1] = 0;

/* strip whitespace */
__buf = strstrip(buf);

err = __set_inj(__buf);
if (err) {
pr_err("%s: Invalid flags value: %s\n", __func__, __buf);
return err;
}

*ppos += ret;

return ret;
}

DEFINE_SIMPLE_ATTRIBUTE(flags_fops, flags_get, flags_set, "%llu\n");
static const struct file_operations flags_fops = {
.read = flags_read,
.write = flags_write,
.llseek = generic_file_llseek,
};

/*
* On which CPU to inject?
Expand Down Expand Up @@ -130,7 +191,7 @@ static void do_inject(void)
unsigned int cpu = i_mce.extcpu;
u8 b = i_mce.bank;

if (!(i_mce.inject_flags & MCJ_EXCEPTION)) {
if (inj_type == SW_INJ) {
amd_decode_mce(NULL, 0, &i_mce);
return;
}
Expand Down

0 comments on commit 0451d14

Please sign in to comment.