aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHuang Ying <ying.huang@intel.com>2010-05-18 02:35:24 -0400
committerLen Brown <len.brown@intel.com>2010-05-19 22:42:08 -0400
commit6e320ec1d98f9eb93d5b2a5d70e2f40dce923f1b (patch)
tree352a2b82433040611f68bf4782eca2e0db28eb15
parent15b0beaa332b3923cce2ed109e0fb141ec1425d9 (diff)
ACPI, APEI, EINJ injection parameters support
Some hardware error injection needs parameters, for example, it is useful to specify memory address and memory address mask for memory errors. Some BIOSes allow parameters to be specified via an unpublished extension. This patch adds support to it. The parameters will be ignored on machines without necessary BIOS support. Signed-off-by: Huang Ying <ying.huang@intel.com> Signed-off-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r--Documentation/acpi/apei/einj.txt10
-rw-r--r--drivers/acpi/apei/einj.c72
2 files changed, 77 insertions, 5 deletions
diff --git a/Documentation/acpi/apei/einj.txt b/Documentation/acpi/apei/einj.txt
index 838b7f0d5e11..dfab71848dc8 100644
--- a/Documentation/acpi/apei/einj.txt
+++ b/Documentation/acpi/apei/einj.txt
@@ -45,5 +45,15 @@ directory apei/einj. The following files are provided.
45 injection. Before this, please specify all necessary error 45 injection. Before this, please specify all necessary error
46 parameters. 46 parameters.
47 47
48- param1
49 This file is used to set the first error parameter value. Effect of
50 parameter depends on error_type specified. For memory error, this is
51 physical memory address.
52
53- param2
54 This file is used to set the second error parameter value. Effect of
55 parameter depends on error_type specified. For memory error, this is
56 physical memory address mask.
57
48For more information about EINJ, please refer to ACPI specification 58For more information about EINJ, please refer to ACPI specification
49version 4.0, section 17.5. 59version 4.0, section 17.5.
diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c
index 4ccebd8f930a..465c885938ee 100644
--- a/drivers/acpi/apei/einj.c
+++ b/drivers/acpi/apei/einj.c
@@ -7,7 +7,7 @@
7 * For more information about EINJ, please refer to ACPI Specification 7 * For more information about EINJ, please refer to ACPI Specification
8 * version 4.0, section 17.5. 8 * version 4.0, section 17.5.
9 * 9 *
10 * Copyright 2009 Intel Corp. 10 * Copyright 2009-2010 Intel Corp.
11 * Author: Huang Ying <ying.huang@intel.com> 11 * Author: Huang Ying <ying.huang@intel.com>
12 * 12 *
13 * This program is free software; you can redistribute it and/or 13 * This program is free software; you can redistribute it and/or
@@ -42,6 +42,20 @@
42/* Firmware should respond within 1 miliseconds */ 42/* Firmware should respond within 1 miliseconds */
43#define FIRMWARE_TIMEOUT (1 * NSEC_PER_MSEC) 43#define FIRMWARE_TIMEOUT (1 * NSEC_PER_MSEC)
44 44
45/*
46 * Some BIOSes allow parameters to the SET_ERROR_TYPE entries in the
47 * EINJ table through an unpublished extension. Use with caution as
48 * most will ignore the parameter and make their own choice of address
49 * for error injection.
50 */
51struct einj_parameter {
52 u64 type;
53 u64 reserved1;
54 u64 reserved2;
55 u64 param1;
56 u64 param2;
57};
58
45#define EINJ_OP_BUSY 0x1 59#define EINJ_OP_BUSY 0x1
46#define EINJ_STATUS_SUCCESS 0x0 60#define EINJ_STATUS_SUCCESS 0x0
47#define EINJ_STATUS_FAIL 0x1 61#define EINJ_STATUS_FAIL 0x1
@@ -85,6 +99,8 @@ static struct apei_exec_ins_type einj_ins_type[] = {
85 */ 99 */
86static DEFINE_MUTEX(einj_mutex); 100static DEFINE_MUTEX(einj_mutex);
87 101
102static struct einj_parameter *einj_param;
103
88static void einj_exec_ctx_init(struct apei_exec_context *ctx) 104static void einj_exec_ctx_init(struct apei_exec_context *ctx)
89{ 105{
90 apei_exec_ctx_init(ctx, einj_ins_type, ARRAY_SIZE(einj_ins_type), 106 apei_exec_ctx_init(ctx, einj_ins_type, ARRAY_SIZE(einj_ins_type),
@@ -130,6 +146,26 @@ static int einj_timedout(u64 *t)
130 return 0; 146 return 0;
131} 147}
132 148
149static u64 einj_get_parameter_address(void)
150{
151 int i;
152 u64 paddr = 0;
153 struct acpi_whea_header *entry;
154
155 entry = EINJ_TAB_ENTRY(einj_tab);
156 for (i = 0; i < einj_tab->entries; i++) {
157 if (entry->action == ACPI_EINJ_SET_ERROR_TYPE &&
158 entry->instruction == ACPI_EINJ_WRITE_REGISTER &&
159 entry->register_region.space_id ==
160 ACPI_ADR_SPACE_SYSTEM_MEMORY)
161 memcpy(&paddr, &entry->register_region.address,
162 sizeof(paddr));
163 entry++;
164 }
165
166 return paddr;
167}
168
133/* do sanity check to trigger table */ 169/* do sanity check to trigger table */
134static int einj_check_trigger_header(struct acpi_einj_trigger *trigger_tab) 170static int einj_check_trigger_header(struct acpi_einj_trigger *trigger_tab)
135{ 171{
@@ -233,7 +269,7 @@ out:
233 return rc; 269 return rc;
234} 270}
235 271
236static int __einj_error_inject(u32 type) 272static int __einj_error_inject(u32 type, u64 param1, u64 param2)
237{ 273{
238 struct apei_exec_context ctx; 274 struct apei_exec_context ctx;
239 u64 val, trigger_paddr, timeout = FIRMWARE_TIMEOUT; 275 u64 val, trigger_paddr, timeout = FIRMWARE_TIMEOUT;
@@ -248,6 +284,10 @@ static int __einj_error_inject(u32 type)
248 rc = apei_exec_run(&ctx, ACPI_EINJ_SET_ERROR_TYPE); 284 rc = apei_exec_run(&ctx, ACPI_EINJ_SET_ERROR_TYPE);
249 if (rc) 285 if (rc)
250 return rc; 286 return rc;
287 if (einj_param) {
288 writeq(param1, &einj_param->param1);
289 writeq(param2, &einj_param->param2);
290 }
251 rc = apei_exec_run(&ctx, ACPI_EINJ_EXECUTE_OPERATION); 291 rc = apei_exec_run(&ctx, ACPI_EINJ_EXECUTE_OPERATION);
252 if (rc) 292 if (rc)
253 return rc; 293 return rc;
@@ -281,18 +321,20 @@ static int __einj_error_inject(u32 type)
281} 321}
282 322
283/* Inject the specified hardware error */ 323/* Inject the specified hardware error */
284static int einj_error_inject(u32 type) 324static int einj_error_inject(u32 type, u64 param1, u64 param2)
285{ 325{
286 int rc; 326 int rc;
287 327
288 mutex_lock(&einj_mutex); 328 mutex_lock(&einj_mutex);
289 rc = __einj_error_inject(type); 329 rc = __einj_error_inject(type, param1, param2);
290 mutex_unlock(&einj_mutex); 330 mutex_unlock(&einj_mutex);
291 331
292 return rc; 332 return rc;
293} 333}
294 334
295static u32 error_type; 335static u32 error_type;
336static u64 error_param1;
337static u64 error_param2;
296static struct dentry *einj_debug_dir; 338static struct dentry *einj_debug_dir;
297 339
298static int available_error_type_show(struct seq_file *m, void *v) 340static int available_error_type_show(struct seq_file *m, void *v)
@@ -376,7 +418,7 @@ static int error_inject_set(void *data, u64 val)
376 if (!error_type) 418 if (!error_type)
377 return -EINVAL; 419 return -EINVAL;
378 420
379 return einj_error_inject(error_type); 421 return einj_error_inject(error_type, error_param1, error_param2);
380} 422}
381 423
382DEFINE_SIMPLE_ATTRIBUTE(error_inject_fops, NULL, 424DEFINE_SIMPLE_ATTRIBUTE(error_inject_fops, NULL,
@@ -399,6 +441,7 @@ static int einj_check_table(struct acpi_table_einj *einj_tab)
399static int __init einj_init(void) 441static int __init einj_init(void)
400{ 442{
401 int rc; 443 int rc;
444 u64 param_paddr;
402 acpi_status status; 445 acpi_status status;
403 struct dentry *fentry; 446 struct dentry *fentry;
404 struct apei_exec_context ctx; 447 struct apei_exec_context ctx;
@@ -436,6 +479,14 @@ static int __init einj_init(void)
436 einj_debug_dir, NULL, &error_type_fops); 479 einj_debug_dir, NULL, &error_type_fops);
437 if (!fentry) 480 if (!fentry)
438 goto err_cleanup; 481 goto err_cleanup;
482 fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR,
483 einj_debug_dir, &error_param1);
484 if (!fentry)
485 goto err_cleanup;
486 fentry = debugfs_create_x64("param2", S_IRUSR | S_IWUSR,
487 einj_debug_dir, &error_param2);
488 if (!fentry)
489 goto err_cleanup;
439 fentry = debugfs_create_file("error_inject", S_IWUSR, 490 fentry = debugfs_create_file("error_inject", S_IWUSR,
440 einj_debug_dir, NULL, &error_inject_fops); 491 einj_debug_dir, NULL, &error_inject_fops);
441 if (!fentry) 492 if (!fentry)
@@ -452,11 +503,20 @@ static int __init einj_init(void)
452 rc = apei_exec_pre_map_gars(&ctx); 503 rc = apei_exec_pre_map_gars(&ctx);
453 if (rc) 504 if (rc)
454 goto err_release; 505 goto err_release;
506 param_paddr = einj_get_parameter_address();
507 if (param_paddr) {
508 einj_param = ioremap(param_paddr, sizeof(*einj_param));
509 rc = -ENOMEM;
510 if (!einj_param)
511 goto err_unmap;
512 }
455 513
456 pr_info(EINJ_PFX "Error INJection is initialized.\n"); 514 pr_info(EINJ_PFX "Error INJection is initialized.\n");
457 515
458 return 0; 516 return 0;
459 517
518err_unmap:
519 apei_exec_post_unmap_gars(&ctx);
460err_release: 520err_release:
461 apei_resources_release(&einj_resources); 521 apei_resources_release(&einj_resources);
462err_fini: 522err_fini:
@@ -471,6 +531,8 @@ static void __exit einj_exit(void)
471{ 531{
472 struct apei_exec_context ctx; 532 struct apei_exec_context ctx;
473 533
534 if (einj_param)
535 iounmap(einj_param);
474 einj_exec_ctx_init(&ctx); 536 einj_exec_ctx_init(&ctx);
475 apei_exec_post_unmap_gars(&ctx); 537 apei_exec_post_unmap_gars(&ctx);
476 apei_resources_release(&einj_resources); 538 apei_resources_release(&einj_resources);