There are couple of reasons why such hack was applied: o lack of UEFI thus no firmware region is reserved to exchange info about error between firmware and OS o EINJ table should operate on registers but GPIO interrupts are availabled now
We set aside some pretend physical space (that is described the same in the tables) and fill in with some error info e.g. memory error. Then it should be triggered. The easiest way to trigger hardware error is to call AML method directly which in turn notify HED (hardware error device). Later on, HED call SCI handler, traverse all GHES list, match appropriate GHES and start to parse.
Signed-off-by: Tomasz Nowicki tomasz.nowicki@linaro.org --- drivers/acpi/apei/einj.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+)
diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index fb57d03..d51c8a6 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c @@ -645,10 +645,33 @@ DEFINE_SIMPLE_ATTRIBUTE(error_type_fops, error_type_get,
static int error_inject_set(void *data, u64 val) { +#if defined (CONFIG_ARM) || defined (CONFIG_ARM64) + /* + * Simulate error injection by calling AML control method directly. + * We need this hack because of lack in GPIO functionality. + */ + int status = ACPI_EINJ_SUCCESS; + + /* Reserve valu=1 for error trigger */ + if (val == 1) { + status = acpi_evaluate_object(NULL, "\_SB.TRIG", NULL, NULL); + if (status != ACPI_EINJ_SUCCESS) + pr_err("Failure during AML control method.\n"); + } + + /* Reserve valu=2 panic triggered by user */ + if (val == 2) { + panic_timeout = 5; + panic("Panic cosed by user ! Only for test purpose !"); + } + + return status; +#else if (!error_type) return -EINVAL;
return einj_error_inject(error_type, error_param1, error_param2); +#endif }
DEFINE_SIMPLE_ATTRIBUTE(error_inject_fops, NULL, @@ -700,6 +723,7 @@ static int __init einj_init(void) einj_debug_dir = debugfs_create_dir("einj", apei_get_debugfs_dir()); if (!einj_debug_dir) goto err_cleanup; +#if !defined (CONFIG_ARM) && !defined (CONFIG_ARM64) fentry = debugfs_create_file("available_error_type", S_IRUSR, einj_debug_dir, NULL, &available_error_type_fops); @@ -709,11 +733,13 @@ static int __init einj_init(void) einj_debug_dir, NULL, &error_type_fops); if (!fentry) goto err_cleanup; +#endif fentry = debugfs_create_file("error_inject", S_IWUSR, einj_debug_dir, NULL, &error_inject_fops); if (!fentry) goto err_cleanup;
+#if !defined (CONFIG_ARM) && !defined (CONFIG_ARM64) apei_resources_init(&einj_resources); einj_exec_ctx_init(&ctx); rc = apei_exec_collect_resources(&ctx, &einj_resources); @@ -756,6 +782,7 @@ static int __init einj_init(void) if (!fentry) goto err_unmap; } +#endif
pr_info(EINJ_PFX "Error INJection is initialized.\n");