mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-18 12:30:31 +00:00
ACPI: APEI: EINJ: Create debugfs files to enter device id and syndrome
EINJv2 allows users to inject multiple errors at the same time by specifying the device id and syndrome bits for each error in a flex array. Create files in the einj debugfs directory to enter data for each device id and syndrome value. Note that the specification says these are 128-bit little-endian values. Linux doesn't have a handy helper to manage objects of this type. Signed-off-by: Tony Luck <tony.luck@intel.com> Reviewed-by: Ira Weiny <ira.weiny@intel.com> Signed-off-by: Zaid Alali <zaidal@os.amperecomputing.com> Link: https://patch.msgid.link/20250617193026.637510-6-zaidal@os.amperecomputing.com Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
parent
691a0f0a55
commit
90711f7bdf
1 changed files with 97 additions and 0 deletions
|
@ -111,6 +111,7 @@ static char vendor_dev[64];
|
|||
static u32 max_nr_components;
|
||||
static u32 available_error_type;
|
||||
static u32 available_error_type_v2;
|
||||
static struct syndrome_array *syndrome_data;
|
||||
|
||||
/*
|
||||
* Some BIOSes allow parameters to the SET_ERROR_TYPE entries in the
|
||||
|
@ -712,6 +713,7 @@ static u64 error_param3;
|
|||
static u64 error_param4;
|
||||
static struct dentry *einj_debug_dir;
|
||||
static char einj_buf[32];
|
||||
static bool einj_v2_enabled;
|
||||
static struct { u32 mask; const char *str; } const einj_error_type_string[] = {
|
||||
{ BIT(0), "Processor Correctable" },
|
||||
{ BIT(1), "Processor Uncorrectable non-fatal" },
|
||||
|
@ -848,6 +850,98 @@ static int einj_check_table(struct acpi_table_einj *einj_tab)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t u128_read(struct file *f, char __user *buf, size_t count, loff_t *off)
|
||||
{
|
||||
char output[2 * COMPONENT_LEN + 1];
|
||||
u8 *data = f->f_inode->i_private;
|
||||
int i;
|
||||
|
||||
if (*off >= sizeof(output))
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < COMPONENT_LEN; i++)
|
||||
sprintf(output + 2 * i, "%.02x", data[COMPONENT_LEN - i - 1]);
|
||||
output[2 * COMPONENT_LEN] = '\n';
|
||||
|
||||
return simple_read_from_buffer(buf, count, off, output, sizeof(output));
|
||||
}
|
||||
|
||||
static ssize_t u128_write(struct file *f, const char __user *buf, size_t count, loff_t *off)
|
||||
{
|
||||
char input[2 + 2 * COMPONENT_LEN + 2];
|
||||
u8 *save = f->f_inode->i_private;
|
||||
u8 tmp[COMPONENT_LEN];
|
||||
char byte[3] = {};
|
||||
char *s, *e;
|
||||
size_t c;
|
||||
long val;
|
||||
int i;
|
||||
|
||||
/* Require that user supply whole input line in one write(2) syscall */
|
||||
if (*off)
|
||||
return -EINVAL;
|
||||
|
||||
c = simple_write_to_buffer(input, sizeof(input), off, buf, count);
|
||||
if (c < 0)
|
||||
return c;
|
||||
|
||||
if (c < 1 || input[c - 1] != '\n')
|
||||
return -EINVAL;
|
||||
|
||||
/* Empty line means invalidate this entry */
|
||||
if (c == 1) {
|
||||
memset(save, 0xff, COMPONENT_LEN);
|
||||
return c;
|
||||
}
|
||||
|
||||
if (input[0] == '0' && (input[1] == 'x' || input[1] == 'X'))
|
||||
s = input + 2;
|
||||
else
|
||||
s = input;
|
||||
e = input + c - 1;
|
||||
|
||||
for (i = 0; i < COMPONENT_LEN; i++) {
|
||||
byte[1] = *--e;
|
||||
byte[0] = e > s ? *--e : '0';
|
||||
if (kstrtol(byte, 16, &val))
|
||||
return -EINVAL;
|
||||
tmp[i] = val;
|
||||
if (e <= s)
|
||||
break;
|
||||
}
|
||||
while (++i < COMPONENT_LEN)
|
||||
tmp[i] = 0;
|
||||
|
||||
memcpy(save, tmp, COMPONENT_LEN);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static const struct file_operations u128_fops = {
|
||||
.read = u128_read,
|
||||
.write = u128_write,
|
||||
};
|
||||
|
||||
static bool setup_einjv2_component_files(void)
|
||||
{
|
||||
char name[32];
|
||||
|
||||
syndrome_data = kcalloc(max_nr_components, sizeof(syndrome_data[0]), GFP_KERNEL);
|
||||
if (!syndrome_data)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < max_nr_components; i++) {
|
||||
sprintf(name, "component_id%d", i);
|
||||
debugfs_create_file(name, 0600, einj_debug_dir,
|
||||
&syndrome_data[i].comp_id, &u128_fops);
|
||||
sprintf(name, "component_syndrome%d", i);
|
||||
debugfs_create_file(name, 0600, einj_debug_dir,
|
||||
&syndrome_data[i].comp_synd, &u128_fops);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int __init einj_probe(struct faux_device *fdev)
|
||||
{
|
||||
int rc;
|
||||
|
@ -919,6 +1013,8 @@ static int __init einj_probe(struct faux_device *fdev)
|
|||
&error_param4);
|
||||
debugfs_create_x32("notrigger", S_IRUSR | S_IWUSR,
|
||||
einj_debug_dir, ¬rigger);
|
||||
if (available_error_type & ACPI65_EINJV2_SUPP)
|
||||
einj_v2_enabled = setup_einjv2_component_files();
|
||||
}
|
||||
|
||||
if (vendor_dev[0]) {
|
||||
|
@ -967,6 +1063,7 @@ static void __exit einj_remove(struct faux_device *fdev)
|
|||
apei_resources_release(&einj_resources);
|
||||
apei_resources_fini(&einj_resources);
|
||||
debugfs_remove_recursive(einj_debug_dir);
|
||||
kfree(syndrome_data);
|
||||
acpi_put_table((struct acpi_table_header *)einj_tab);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue