Message ID | 20250506213814.2365788-6-zaidal@os.amperecomputing.com |
---|---|
State | New |
Headers | show |
Series | Enable EINJv2 Support | expand |
On Tue, May 6, 2025 at 11:38 PM Zaid Alali <zaidal@os.amperecomputing.com> wrote: > > Enable the driver to show all supported error injections for EINJ > and EINJv2 at the same time. EINJv2 capabilities can be discovered > by checking the return value of get_error_type, where bit 30 set > indicates EINJv2 support. > > Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> > Signed-off-by: Zaid Alali <zaidal@os.amperecomputing.com> While the tag provided by Jonathan is appreciated, patches [5-9/9] need to be reviewed by one of the reviewers listed in the APEI entry in MAINTAINERS. > --- > drivers/acpi/apei/apei-internal.h | 2 +- > drivers/acpi/apei/einj-core.c | 75 +++++++++++++++++++++++++------ > drivers/acpi/apei/einj-cxl.c | 2 +- > 3 files changed, 63 insertions(+), 16 deletions(-) > > diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h > index cd2766c69d78..77c10a7a7a9f 100644 > --- a/drivers/acpi/apei/apei-internal.h > +++ b/drivers/acpi/apei/apei-internal.h > @@ -131,7 +131,7 @@ static inline u32 cper_estatus_len(struct acpi_hest_generic_status *estatus) > > int apei_osc_setup(void); > > -int einj_get_available_error_type(u32 *type); > +int einj_get_available_error_type(u32 *type, int einj_action); > int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, u64 param3, > u64 param4); > int einj_cxl_rch_error_inject(u32 type, u32 flags, u64 param1, u64 param2, > diff --git a/drivers/acpi/apei/einj-core.c b/drivers/acpi/apei/einj-core.c > index ada1d7026af5..ee26df0398fc 100644 > --- a/drivers/acpi/apei/einj-core.c > +++ b/drivers/acpi/apei/einj-core.c > @@ -33,6 +33,7 @@ > #define SLEEP_UNIT_MAX 5000 /* 5ms */ > /* Firmware should respond within 1 seconds */ > #define FIRMWARE_TIMEOUT (1 * USEC_PER_SEC) > +#define ACPI65_EINJV2_SUPP BIT(30) > #define ACPI5_VENDOR_BIT BIT(31) > #define MEM_ERROR_MASK (ACPI_EINJ_MEMORY_CORRECTABLE | \ > ACPI_EINJ_MEMORY_UNCORRECTABLE | \ > @@ -84,6 +85,7 @@ static struct debugfs_blob_wrapper vendor_errors; > static char vendor_dev[64]; > > static u32 available_error_type; > +static u32 available_error_type_v2; > > /* > * Some BIOSes allow parameters to the SET_ERROR_TYPE entries in the > @@ -159,13 +161,13 @@ static void einj_exec_ctx_init(struct apei_exec_context *ctx) > EINJ_TAB_ENTRY(einj_tab), einj_tab->entries); > } > > -static int __einj_get_available_error_type(u32 *type) > +static int __einj_get_available_error_type(u32 *type, int einj_action) > { > struct apei_exec_context ctx; > int rc; > > einj_exec_ctx_init(&ctx); > - rc = apei_exec_run(&ctx, ACPI_EINJ_GET_ERROR_TYPE); > + rc = apei_exec_run(&ctx, einj_action); > if (rc) > return rc; > *type = apei_exec_ctx_get_output(&ctx); > @@ -174,17 +176,34 @@ static int __einj_get_available_error_type(u32 *type) > } > > /* Get error injection capabilities of the platform */ > -int einj_get_available_error_type(u32 *type) > +int einj_get_available_error_type(u32 *type, int einj_action) > { > int rc; > > mutex_lock(&einj_mutex); > - rc = __einj_get_available_error_type(type); > + rc = __einj_get_available_error_type(type, einj_action); > mutex_unlock(&einj_mutex); > > return rc; > } > > +static int einj_get_available_error_types(u32 *type1, u32 *type2) > +{ > + int rc; > + > + rc = einj_get_available_error_type(type1, ACPI_EINJ_GET_ERROR_TYPE); > + if (rc) > + return rc; > + if (*type1 & ACPI65_EINJV2_SUPP) { > + rc = einj_get_available_error_type(type2, > + ACPI_EINJV2_GET_ERROR_TYPE); > + if (rc) > + return rc; > + } > + > + return 0; > +} > + > static int einj_timedout(u64 *t) > { > if ((s64)*t < SLEEP_UNIT_MIN) { > @@ -646,6 +665,7 @@ static u64 error_param2; > static u64 error_param3; > static u64 error_param4; > static struct dentry *einj_debug_dir; > +static char einj_buf[32]; > static struct { u32 mask; const char *str; } const einj_error_type_string[] = { > { BIT(0), "Processor Correctable" }, > { BIT(1), "Processor Uncorrectable non-fatal" }, > @@ -662,6 +682,12 @@ static struct { u32 mask; const char *str; } const einj_error_type_string[] = { > { BIT(31), "Vendor Defined Error Types" }, > }; > > +static struct { u32 mask; const char *str; } const einjv2_error_type_string[] = { > + { BIT(0), "EINJV2 Processor Error" }, > + { BIT(1), "EINJV2 Memory Error" }, > + { BIT(2), "EINJV2 PCI Express Error" }, > +}; > + > static int available_error_type_show(struct seq_file *m, void *v) > { > > @@ -669,17 +695,22 @@ static int available_error_type_show(struct seq_file *m, void *v) > if (available_error_type & einj_error_type_string[pos].mask) > seq_printf(m, "0x%08x\t%s\n", einj_error_type_string[pos].mask, > einj_error_type_string[pos].str); > - > + if (available_error_type & ACPI65_EINJV2_SUPP) { > + for (int pos = 0; pos < ARRAY_SIZE(einjv2_error_type_string); pos++) { > + if (available_error_type_v2 & einjv2_error_type_string[pos].mask) > + seq_printf(m, "V2_0x%08x\t%s\n", einjv2_error_type_string[pos].mask, > + einjv2_error_type_string[pos].str); > + } > + } > return 0; > } > > DEFINE_SHOW_ATTRIBUTE(available_error_type); > > -static int error_type_get(void *data, u64 *val) > +static ssize_t error_type_get(struct file *file, char __user *buf, > + size_t count, loff_t *ppos) > { > - *val = error_type; > - > - return 0; > + return simple_read_from_buffer(buf, count, ppos, einj_buf, strlen(einj_buf)); > } > > bool einj_is_cxl_error_type(u64 type) > @@ -712,9 +743,23 @@ int einj_validate_error_type(u64 type) > return 0; > } > > -static int error_type_set(void *data, u64 val) > +static ssize_t error_type_set(struct file *file, const char __user *buf, > + size_t count, loff_t *ppos) > { > int rc; > + u64 val; > + > + memset(einj_buf, 0, sizeof(einj_buf)); > + if (copy_from_user(einj_buf, buf, count)) > + return -EFAULT; > + > + if (strncmp(einj_buf, "V2_", 3) == 0) { > + if (!sscanf(einj_buf, "V2_%llx", &val)) > + return -EINVAL; > + } else { > + if (!sscanf(einj_buf, "%llx", &val)) > + return -EINVAL; > + } > > rc = einj_validate_error_type(val); > if (rc) > @@ -722,11 +767,13 @@ static int error_type_set(void *data, u64 val) > > error_type = val; > > - return 0; > + return count; > } > > -DEFINE_DEBUGFS_ATTRIBUTE(error_type_fops, error_type_get, error_type_set, > - "0x%llx\n"); > +static const struct file_operations error_type_fops = { > + .read = error_type_get, > + .write = error_type_set, > +}; > > static int error_inject_set(void *data, u64 val) > { > @@ -783,7 +830,7 @@ static int __init einj_probe(struct platform_device *pdev) > goto err_put_table; > } > > - rc = einj_get_available_error_type(&available_error_type); > + rc = einj_get_available_error_types(&available_error_type, &available_error_type_v2); > if (rc) > return rc; > > diff --git a/drivers/acpi/apei/einj-cxl.c b/drivers/acpi/apei/einj-cxl.c > index 78da9ae543a2..e70a416ec925 100644 > --- a/drivers/acpi/apei/einj-cxl.c > +++ b/drivers/acpi/apei/einj-cxl.c > @@ -30,7 +30,7 @@ int einj_cxl_available_error_type_show(struct seq_file *m, void *v) > int cxl_err, rc; > u32 available_error_type = 0; > > - rc = einj_get_available_error_type(&available_error_type); > + rc = einj_get_available_error_type(&available_error_type, ACPI_EINJ_GET_ERROR_TYPE); > if (rc) > return rc; > > -- > 2.43.0 >
diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h index cd2766c69d78..77c10a7a7a9f 100644 --- a/drivers/acpi/apei/apei-internal.h +++ b/drivers/acpi/apei/apei-internal.h @@ -131,7 +131,7 @@ static inline u32 cper_estatus_len(struct acpi_hest_generic_status *estatus) int apei_osc_setup(void); -int einj_get_available_error_type(u32 *type); +int einj_get_available_error_type(u32 *type, int einj_action); int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, u64 param3, u64 param4); int einj_cxl_rch_error_inject(u32 type, u32 flags, u64 param1, u64 param2, diff --git a/drivers/acpi/apei/einj-core.c b/drivers/acpi/apei/einj-core.c index ada1d7026af5..ee26df0398fc 100644 --- a/drivers/acpi/apei/einj-core.c +++ b/drivers/acpi/apei/einj-core.c @@ -33,6 +33,7 @@ #define SLEEP_UNIT_MAX 5000 /* 5ms */ /* Firmware should respond within 1 seconds */ #define FIRMWARE_TIMEOUT (1 * USEC_PER_SEC) +#define ACPI65_EINJV2_SUPP BIT(30) #define ACPI5_VENDOR_BIT BIT(31) #define MEM_ERROR_MASK (ACPI_EINJ_MEMORY_CORRECTABLE | \ ACPI_EINJ_MEMORY_UNCORRECTABLE | \ @@ -84,6 +85,7 @@ static struct debugfs_blob_wrapper vendor_errors; static char vendor_dev[64]; static u32 available_error_type; +static u32 available_error_type_v2; /* * Some BIOSes allow parameters to the SET_ERROR_TYPE entries in the @@ -159,13 +161,13 @@ static void einj_exec_ctx_init(struct apei_exec_context *ctx) EINJ_TAB_ENTRY(einj_tab), einj_tab->entries); } -static int __einj_get_available_error_type(u32 *type) +static int __einj_get_available_error_type(u32 *type, int einj_action) { struct apei_exec_context ctx; int rc; einj_exec_ctx_init(&ctx); - rc = apei_exec_run(&ctx, ACPI_EINJ_GET_ERROR_TYPE); + rc = apei_exec_run(&ctx, einj_action); if (rc) return rc; *type = apei_exec_ctx_get_output(&ctx); @@ -174,17 +176,34 @@ static int __einj_get_available_error_type(u32 *type) } /* Get error injection capabilities of the platform */ -int einj_get_available_error_type(u32 *type) +int einj_get_available_error_type(u32 *type, int einj_action) { int rc; mutex_lock(&einj_mutex); - rc = __einj_get_available_error_type(type); + rc = __einj_get_available_error_type(type, einj_action); mutex_unlock(&einj_mutex); return rc; } +static int einj_get_available_error_types(u32 *type1, u32 *type2) +{ + int rc; + + rc = einj_get_available_error_type(type1, ACPI_EINJ_GET_ERROR_TYPE); + if (rc) + return rc; + if (*type1 & ACPI65_EINJV2_SUPP) { + rc = einj_get_available_error_type(type2, + ACPI_EINJV2_GET_ERROR_TYPE); + if (rc) + return rc; + } + + return 0; +} + static int einj_timedout(u64 *t) { if ((s64)*t < SLEEP_UNIT_MIN) { @@ -646,6 +665,7 @@ static u64 error_param2; static u64 error_param3; static u64 error_param4; static struct dentry *einj_debug_dir; +static char einj_buf[32]; static struct { u32 mask; const char *str; } const einj_error_type_string[] = { { BIT(0), "Processor Correctable" }, { BIT(1), "Processor Uncorrectable non-fatal" }, @@ -662,6 +682,12 @@ static struct { u32 mask; const char *str; } const einj_error_type_string[] = { { BIT(31), "Vendor Defined Error Types" }, }; +static struct { u32 mask; const char *str; } const einjv2_error_type_string[] = { + { BIT(0), "EINJV2 Processor Error" }, + { BIT(1), "EINJV2 Memory Error" }, + { BIT(2), "EINJV2 PCI Express Error" }, +}; + static int available_error_type_show(struct seq_file *m, void *v) { @@ -669,17 +695,22 @@ static int available_error_type_show(struct seq_file *m, void *v) if (available_error_type & einj_error_type_string[pos].mask) seq_printf(m, "0x%08x\t%s\n", einj_error_type_string[pos].mask, einj_error_type_string[pos].str); - + if (available_error_type & ACPI65_EINJV2_SUPP) { + for (int pos = 0; pos < ARRAY_SIZE(einjv2_error_type_string); pos++) { + if (available_error_type_v2 & einjv2_error_type_string[pos].mask) + seq_printf(m, "V2_0x%08x\t%s\n", einjv2_error_type_string[pos].mask, + einjv2_error_type_string[pos].str); + } + } return 0; } DEFINE_SHOW_ATTRIBUTE(available_error_type); -static int error_type_get(void *data, u64 *val) +static ssize_t error_type_get(struct file *file, char __user *buf, + size_t count, loff_t *ppos) { - *val = error_type; - - return 0; + return simple_read_from_buffer(buf, count, ppos, einj_buf, strlen(einj_buf)); } bool einj_is_cxl_error_type(u64 type) @@ -712,9 +743,23 @@ int einj_validate_error_type(u64 type) return 0; } -static int error_type_set(void *data, u64 val) +static ssize_t error_type_set(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) { int rc; + u64 val; + + memset(einj_buf, 0, sizeof(einj_buf)); + if (copy_from_user(einj_buf, buf, count)) + return -EFAULT; + + if (strncmp(einj_buf, "V2_", 3) == 0) { + if (!sscanf(einj_buf, "V2_%llx", &val)) + return -EINVAL; + } else { + if (!sscanf(einj_buf, "%llx", &val)) + return -EINVAL; + } rc = einj_validate_error_type(val); if (rc) @@ -722,11 +767,13 @@ static int error_type_set(void *data, u64 val) error_type = val; - return 0; + return count; } -DEFINE_DEBUGFS_ATTRIBUTE(error_type_fops, error_type_get, error_type_set, - "0x%llx\n"); +static const struct file_operations error_type_fops = { + .read = error_type_get, + .write = error_type_set, +}; static int error_inject_set(void *data, u64 val) { @@ -783,7 +830,7 @@ static int __init einj_probe(struct platform_device *pdev) goto err_put_table; } - rc = einj_get_available_error_type(&available_error_type); + rc = einj_get_available_error_types(&available_error_type, &available_error_type_v2); if (rc) return rc; diff --git a/drivers/acpi/apei/einj-cxl.c b/drivers/acpi/apei/einj-cxl.c index 78da9ae543a2..e70a416ec925 100644 --- a/drivers/acpi/apei/einj-cxl.c +++ b/drivers/acpi/apei/einj-cxl.c @@ -30,7 +30,7 @@ int einj_cxl_available_error_type_show(struct seq_file *m, void *v) int cxl_err, rc; u32 available_error_type = 0; - rc = einj_get_available_error_type(&available_error_type); + rc = einj_get_available_error_type(&available_error_type, ACPI_EINJ_GET_ERROR_TYPE); if (rc) return rc;