aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/apei/apei-base.c11
-rw-r--r--drivers/acpi/apei/apei-internal.h3
-rw-r--r--drivers/acpi/apei/einj.c24
3 files changed, 36 insertions, 2 deletions
diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c
index 3492896b96f2..f2c5062e2b32 100644
--- a/drivers/acpi/apei/apei-base.c
+++ b/drivers/acpi/apei/apei-base.c
@@ -421,6 +421,17 @@ static int apei_resources_merge(struct apei_resources *resources1,
421 return 0; 421 return 0;
422} 422}
423 423
424int apei_resources_add(struct apei_resources *resources,
425 unsigned long start, unsigned long size,
426 bool iomem)
427{
428 if (iomem)
429 return apei_res_add(&resources->iomem, start, size);
430 else
431 return apei_res_add(&resources->ioport, start, size);
432}
433EXPORT_SYMBOL_GPL(apei_resources_add);
434
424/* 435/*
425 * EINJ has two groups of GARs (EINJ table entry and trigger table 436 * EINJ has two groups of GARs (EINJ table entry and trigger table
426 * entry), so common resources are subtracted from the trigger table 437 * entry), so common resources are subtracted from the trigger table
diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h
index f57050e7a5e7..d778edd34fba 100644
--- a/drivers/acpi/apei/apei-internal.h
+++ b/drivers/acpi/apei/apei-internal.h
@@ -95,6 +95,9 @@ static inline void apei_resources_init(struct apei_resources *resources)
95} 95}
96 96
97void apei_resources_fini(struct apei_resources *resources); 97void apei_resources_fini(struct apei_resources *resources);
98int apei_resources_add(struct apei_resources *resources,
99 unsigned long start, unsigned long size,
100 bool iomem);
98int apei_resources_sub(struct apei_resources *resources1, 101int apei_resources_sub(struct apei_resources *resources1,
99 struct apei_resources *resources2); 102 struct apei_resources *resources2);
100int apei_resources_request(struct apei_resources *resources, 103int apei_resources_request(struct apei_resources *resources,
diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c
index 43eeb2e6e635..4fdc8a3b4f6c 100644
--- a/drivers/acpi/apei/einj.c
+++ b/drivers/acpi/apei/einj.c
@@ -195,7 +195,8 @@ static int einj_check_trigger_header(struct acpi_einj_trigger *trigger_tab)
195} 195}
196 196
197/* Execute instructions in trigger error action table */ 197/* Execute instructions in trigger error action table */
198static int __einj_error_trigger(u64 trigger_paddr) 198static int __einj_error_trigger(u64 trigger_paddr, u32 type,
199 u64 param1, u64 param2)
199{ 200{
200 struct acpi_einj_trigger *trigger_tab = NULL; 201 struct acpi_einj_trigger *trigger_tab = NULL;
201 struct apei_exec_context trigger_ctx; 202 struct apei_exec_context trigger_ctx;
@@ -256,6 +257,25 @@ static int __einj_error_trigger(u64 trigger_paddr)
256 rc = apei_resources_sub(&trigger_resources, &einj_resources); 257 rc = apei_resources_sub(&trigger_resources, &einj_resources);
257 if (rc) 258 if (rc)
258 goto out_fini; 259 goto out_fini;
260 /*
261 * Some firmware will access target address specified in
262 * param1 to trigger the error when injecting memory error.
263 * This will cause resource conflict with regular memory. So
264 * remove it from trigger table resources.
265 */
266 if (param_extension && (type & 0x0038) && param2) {
267 struct apei_resources addr_resources;
268 apei_resources_init(&addr_resources);
269 rc = apei_resources_add(&addr_resources,
270 param1 & param2,
271 ~param2 + 1, true);
272 if (rc)
273 goto out_fini;
274 rc = apei_resources_sub(&trigger_resources, &addr_resources);
275 apei_resources_fini(&addr_resources);
276 if (rc)
277 goto out_fini;
278 }
259 rc = apei_resources_request(&trigger_resources, "APEI EINJ Trigger"); 279 rc = apei_resources_request(&trigger_resources, "APEI EINJ Trigger");
260 if (rc) 280 if (rc)
261 goto out_fini; 281 goto out_fini;
@@ -325,7 +345,7 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2)
325 if (rc) 345 if (rc)
326 return rc; 346 return rc;
327 trigger_paddr = apei_exec_ctx_get_output(&ctx); 347 trigger_paddr = apei_exec_ctx_get_output(&ctx);
328 rc = __einj_error_trigger(trigger_paddr); 348 rc = __einj_error_trigger(trigger_paddr, type, param1, param2);
329 if (rc) 349 if (rc)
330 return rc; 350 return rc;
331 rc = apei_exec_run_optional(&ctx, ACPI_EINJ_END_OPERATION); 351 rc = apei_exec_run_optional(&ctx, ACPI_EINJ_END_OPERATION);