Skip to content

Commit 90711f7

Browse files
aeglrafaeljw
authored andcommitted
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>
1 parent 691a0f0 commit 90711f7

1 file changed

Lines changed: 97 additions & 0 deletions

File tree

drivers/acpi/apei/einj-core.c

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ static char vendor_dev[64];
111111
static u32 max_nr_components;
112112
static u32 available_error_type;
113113
static u32 available_error_type_v2;
114+
static struct syndrome_array *syndrome_data;
114115

115116
/*
116117
* Some BIOSes allow parameters to the SET_ERROR_TYPE entries in the
@@ -712,6 +713,7 @@ static u64 error_param3;
712713
static u64 error_param4;
713714
static struct dentry *einj_debug_dir;
714715
static char einj_buf[32];
716+
static bool einj_v2_enabled;
715717
static struct { u32 mask; const char *str; } const einj_error_type_string[] = {
716718
{ BIT(0), "Processor Correctable" },
717719
{ BIT(1), "Processor Uncorrectable non-fatal" },
@@ -848,6 +850,98 @@ static int einj_check_table(struct acpi_table_einj *einj_tab)
848850
return 0;
849851
}
850852

853+
static ssize_t u128_read(struct file *f, char __user *buf, size_t count, loff_t *off)
854+
{
855+
char output[2 * COMPONENT_LEN + 1];
856+
u8 *data = f->f_inode->i_private;
857+
int i;
858+
859+
if (*off >= sizeof(output))
860+
return 0;
861+
862+
for (i = 0; i < COMPONENT_LEN; i++)
863+
sprintf(output + 2 * i, "%.02x", data[COMPONENT_LEN - i - 1]);
864+
output[2 * COMPONENT_LEN] = '\n';
865+
866+
return simple_read_from_buffer(buf, count, off, output, sizeof(output));
867+
}
868+
869+
static ssize_t u128_write(struct file *f, const char __user *buf, size_t count, loff_t *off)
870+
{
871+
char input[2 + 2 * COMPONENT_LEN + 2];
872+
u8 *save = f->f_inode->i_private;
873+
u8 tmp[COMPONENT_LEN];
874+
char byte[3] = {};
875+
char *s, *e;
876+
size_t c;
877+
long val;
878+
int i;
879+
880+
/* Require that user supply whole input line in one write(2) syscall */
881+
if (*off)
882+
return -EINVAL;
883+
884+
c = simple_write_to_buffer(input, sizeof(input), off, buf, count);
885+
if (c < 0)
886+
return c;
887+
888+
if (c < 1 || input[c - 1] != '\n')
889+
return -EINVAL;
890+
891+
/* Empty line means invalidate this entry */
892+
if (c == 1) {
893+
memset(save, 0xff, COMPONENT_LEN);
894+
return c;
895+
}
896+
897+
if (input[0] == '0' && (input[1] == 'x' || input[1] == 'X'))
898+
s = input + 2;
899+
else
900+
s = input;
901+
e = input + c - 1;
902+
903+
for (i = 0; i < COMPONENT_LEN; i++) {
904+
byte[1] = *--e;
905+
byte[0] = e > s ? *--e : '0';
906+
if (kstrtol(byte, 16, &val))
907+
return -EINVAL;
908+
tmp[i] = val;
909+
if (e <= s)
910+
break;
911+
}
912+
while (++i < COMPONENT_LEN)
913+
tmp[i] = 0;
914+
915+
memcpy(save, tmp, COMPONENT_LEN);
916+
917+
return c;
918+
}
919+
920+
static const struct file_operations u128_fops = {
921+
.read = u128_read,
922+
.write = u128_write,
923+
};
924+
925+
static bool setup_einjv2_component_files(void)
926+
{
927+
char name[32];
928+
929+
syndrome_data = kcalloc(max_nr_components, sizeof(syndrome_data[0]), GFP_KERNEL);
930+
if (!syndrome_data)
931+
return false;
932+
933+
for (int i = 0; i < max_nr_components; i++) {
934+
sprintf(name, "component_id%d", i);
935+
debugfs_create_file(name, 0600, einj_debug_dir,
936+
&syndrome_data[i].comp_id, &u128_fops);
937+
sprintf(name, "component_syndrome%d", i);
938+
debugfs_create_file(name, 0600, einj_debug_dir,
939+
&syndrome_data[i].comp_synd, &u128_fops);
940+
}
941+
942+
return true;
943+
}
944+
851945
static int __init einj_probe(struct faux_device *fdev)
852946
{
853947
int rc;
@@ -919,6 +1013,8 @@ static int __init einj_probe(struct faux_device *fdev)
9191013
&error_param4);
9201014
debugfs_create_x32("notrigger", S_IRUSR | S_IWUSR,
9211015
einj_debug_dir, &notrigger);
1016+
if (available_error_type & ACPI65_EINJV2_SUPP)
1017+
einj_v2_enabled = setup_einjv2_component_files();
9221018
}
9231019

9241020
if (vendor_dev[0]) {
@@ -967,6 +1063,7 @@ static void __exit einj_remove(struct faux_device *fdev)
9671063
apei_resources_release(&einj_resources);
9681064
apei_resources_fini(&einj_resources);
9691065
debugfs_remove_recursive(einj_debug_dir);
1066+
kfree(syndrome_data);
9701067
acpi_put_table((struct acpi_table_header *)einj_tab);
9711068
}
9721069

0 commit comments

Comments
 (0)