diff options
| -rw-r--r-- | drivers/acpi/apei/apei-base.c | 11 | ||||
| -rw-r--r-- | drivers/acpi/apei/apei-internal.h | 3 | ||||
| -rw-r--r-- | drivers/acpi/apei/einj.c | 24 |
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 | ||
| 424 | int 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 | } | ||
| 433 | EXPORT_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 | ||
| 97 | void apei_resources_fini(struct apei_resources *resources); | 97 | void apei_resources_fini(struct apei_resources *resources); |
| 98 | int apei_resources_add(struct apei_resources *resources, | ||
| 99 | unsigned long start, unsigned long size, | ||
| 100 | bool iomem); | ||
| 98 | int apei_resources_sub(struct apei_resources *resources1, | 101 | int apei_resources_sub(struct apei_resources *resources1, |
| 99 | struct apei_resources *resources2); | 102 | struct apei_resources *resources2); |
| 100 | int apei_resources_request(struct apei_resources *resources, | 103 | int 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 */ |
| 198 | static int __einj_error_trigger(u64 trigger_paddr) | 198 | static 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); |
