aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/apei/einj.c72
1 files changed, 67 insertions, 5 deletions
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);