aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHuang Ying <ying.huang@intel.com>2011-12-07 22:25:47 -0500
committerLen Brown <len.brown@intel.com>2012-01-17 03:54:38 -0500
commitfdea163d8c17ba08814142259a467ba3e899010d (patch)
treea512e00b3e569a2ce5d5456bcc8ef9a30020075f
parent76da3fb3575e39fb23b2c072997ccd1187a2ce9d (diff)
ACPI, APEI, EINJ, Fix resource conflict on some machine
Some APEI firmware implementation will access injected address specified in param1 to trigger the error when injecting memory error. This will cause resource conflict with RAM. On one of our testing machine, if injecting at memory address 0x10000000, the following error will be reported in dmesg: APEI: Can not request iomem region <0000000010000000-0000000010000008> for GARs. This patch removes the injecting memory address range from trigger table resources to avoid conflict. Signed-off-by: Huang Ying <ying.huang@intel.com> Tested-by: Tony Luck <tony.luck@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
-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 3492896b96f..f2c5062e2b3 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 f57050e7a5e..d778edd34fb 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 43eeb2e6e63..4fdc8a3b4f6 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);