Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.1-rc2 567 lines 15 kB view raw
1/* 2 * APEI Error INJection support 3 * 4 * EINJ provides a hardware error injection mechanism, this is useful 5 * for debugging and testing of other APEI and RAS features. 6 * 7 * For more information about EINJ, please refer to ACPI Specification 8 * version 4.0, section 17.5. 9 * 10 * Copyright 2009-2010 Intel Corp. 11 * Author: Huang Ying <ying.huang@intel.com> 12 * 13 * This program is free software; you can redistribute it and/or 14 * modify it under the terms of the GNU General Public License version 15 * 2 as published by the Free Software Foundation. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 * 22 * You should have received a copy of the GNU General Public License 23 * along with this program; if not, write to the Free Software 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 25 */ 26 27#include <linux/kernel.h> 28#include <linux/module.h> 29#include <linux/init.h> 30#include <linux/io.h> 31#include <linux/debugfs.h> 32#include <linux/seq_file.h> 33#include <linux/nmi.h> 34#include <linux/delay.h> 35#include <acpi/acpi.h> 36 37#include "apei-internal.h" 38 39#define EINJ_PFX "EINJ: " 40 41#define SPIN_UNIT 100 /* 100ns */ 42/* Firmware should respond within 1 milliseconds */ 43#define FIRMWARE_TIMEOUT (1 * NSEC_PER_MSEC) 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. This extension is used only if 50 * param_extension module parameter is specified. 51 */ 52struct einj_parameter { 53 u64 type; 54 u64 reserved1; 55 u64 reserved2; 56 u64 param1; 57 u64 param2; 58}; 59 60#define EINJ_OP_BUSY 0x1 61#define EINJ_STATUS_SUCCESS 0x0 62#define EINJ_STATUS_FAIL 0x1 63#define EINJ_STATUS_INVAL 0x2 64 65#define EINJ_TAB_ENTRY(tab) \ 66 ((struct acpi_whea_header *)((char *)(tab) + \ 67 sizeof(struct acpi_table_einj))) 68 69static bool param_extension; 70module_param(param_extension, bool, 0); 71 72static struct acpi_table_einj *einj_tab; 73 74static struct apei_resources einj_resources; 75 76static struct apei_exec_ins_type einj_ins_type[] = { 77 [ACPI_EINJ_READ_REGISTER] = { 78 .flags = APEI_EXEC_INS_ACCESS_REGISTER, 79 .run = apei_exec_read_register, 80 }, 81 [ACPI_EINJ_READ_REGISTER_VALUE] = { 82 .flags = APEI_EXEC_INS_ACCESS_REGISTER, 83 .run = apei_exec_read_register_value, 84 }, 85 [ACPI_EINJ_WRITE_REGISTER] = { 86 .flags = APEI_EXEC_INS_ACCESS_REGISTER, 87 .run = apei_exec_write_register, 88 }, 89 [ACPI_EINJ_WRITE_REGISTER_VALUE] = { 90 .flags = APEI_EXEC_INS_ACCESS_REGISTER, 91 .run = apei_exec_write_register_value, 92 }, 93 [ACPI_EINJ_NOOP] = { 94 .flags = 0, 95 .run = apei_exec_noop, 96 }, 97}; 98 99/* 100 * Prevent EINJ interpreter to run simultaneously, because the 101 * corresponding firmware implementation may not work properly when 102 * invoked simultaneously. 103 */ 104static DEFINE_MUTEX(einj_mutex); 105 106static struct einj_parameter *einj_param; 107 108#ifndef writeq 109static inline void writeq(__u64 val, volatile void __iomem *addr) 110{ 111 writel(val, addr); 112 writel(val >> 32, addr+4); 113} 114#endif 115 116static void einj_exec_ctx_init(struct apei_exec_context *ctx) 117{ 118 apei_exec_ctx_init(ctx, einj_ins_type, ARRAY_SIZE(einj_ins_type), 119 EINJ_TAB_ENTRY(einj_tab), einj_tab->entries); 120} 121 122static int __einj_get_available_error_type(u32 *type) 123{ 124 struct apei_exec_context ctx; 125 int rc; 126 127 einj_exec_ctx_init(&ctx); 128 rc = apei_exec_run(&ctx, ACPI_EINJ_GET_ERROR_TYPE); 129 if (rc) 130 return rc; 131 *type = apei_exec_ctx_get_output(&ctx); 132 133 return 0; 134} 135 136/* Get error injection capabilities of the platform */ 137static int einj_get_available_error_type(u32 *type) 138{ 139 int rc; 140 141 mutex_lock(&einj_mutex); 142 rc = __einj_get_available_error_type(type); 143 mutex_unlock(&einj_mutex); 144 145 return rc; 146} 147 148static int einj_timedout(u64 *t) 149{ 150 if ((s64)*t < SPIN_UNIT) { 151 pr_warning(FW_WARN EINJ_PFX 152 "Firmware does not respond in time\n"); 153 return 1; 154 } 155 *t -= SPIN_UNIT; 156 ndelay(SPIN_UNIT); 157 touch_nmi_watchdog(); 158 return 0; 159} 160 161static u64 einj_get_parameter_address(void) 162{ 163 int i; 164 u64 paddr = 0; 165 struct acpi_whea_header *entry; 166 167 entry = EINJ_TAB_ENTRY(einj_tab); 168 for (i = 0; i < einj_tab->entries; i++) { 169 if (entry->action == ACPI_EINJ_SET_ERROR_TYPE && 170 entry->instruction == ACPI_EINJ_WRITE_REGISTER && 171 entry->register_region.space_id == 172 ACPI_ADR_SPACE_SYSTEM_MEMORY) 173 memcpy(&paddr, &entry->register_region.address, 174 sizeof(paddr)); 175 entry++; 176 } 177 178 return paddr; 179} 180 181/* do sanity check to trigger table */ 182static int einj_check_trigger_header(struct acpi_einj_trigger *trigger_tab) 183{ 184 if (trigger_tab->header_size != sizeof(struct acpi_einj_trigger)) 185 return -EINVAL; 186 if (trigger_tab->table_size > PAGE_SIZE || 187 trigger_tab->table_size <= trigger_tab->header_size) 188 return -EINVAL; 189 if (trigger_tab->entry_count != 190 (trigger_tab->table_size - trigger_tab->header_size) / 191 sizeof(struct acpi_einj_entry)) 192 return -EINVAL; 193 194 return 0; 195} 196 197/* Execute instructions in trigger error action table */ 198static int __einj_error_trigger(u64 trigger_paddr) 199{ 200 struct acpi_einj_trigger *trigger_tab = NULL; 201 struct apei_exec_context trigger_ctx; 202 struct apei_resources trigger_resources; 203 struct acpi_whea_header *trigger_entry; 204 struct resource *r; 205 u32 table_size; 206 int rc = -EIO; 207 208 r = request_mem_region(trigger_paddr, sizeof(*trigger_tab), 209 "APEI EINJ Trigger Table"); 210 if (!r) { 211 pr_err(EINJ_PFX 212 "Can not request iomem region <%016llx-%016llx> for Trigger table.\n", 213 (unsigned long long)trigger_paddr, 214 (unsigned long long)trigger_paddr+sizeof(*trigger_tab)); 215 goto out; 216 } 217 trigger_tab = ioremap_cache(trigger_paddr, sizeof(*trigger_tab)); 218 if (!trigger_tab) { 219 pr_err(EINJ_PFX "Failed to map trigger table!\n"); 220 goto out_rel_header; 221 } 222 rc = einj_check_trigger_header(trigger_tab); 223 if (rc) { 224 pr_warning(FW_BUG EINJ_PFX 225 "The trigger error action table is invalid\n"); 226 goto out_rel_header; 227 } 228 rc = -EIO; 229 table_size = trigger_tab->table_size; 230 r = request_mem_region(trigger_paddr + sizeof(*trigger_tab), 231 table_size - sizeof(*trigger_tab), 232 "APEI EINJ Trigger Table"); 233 if (!r) { 234 pr_err(EINJ_PFX 235"Can not request iomem region <%016llx-%016llx> for Trigger Table Entry.\n", 236 (unsigned long long)trigger_paddr+sizeof(*trigger_tab), 237 (unsigned long long)trigger_paddr + table_size); 238 goto out_rel_header; 239 } 240 iounmap(trigger_tab); 241 trigger_tab = ioremap_cache(trigger_paddr, table_size); 242 if (!trigger_tab) { 243 pr_err(EINJ_PFX "Failed to map trigger table!\n"); 244 goto out_rel_entry; 245 } 246 trigger_entry = (struct acpi_whea_header *) 247 ((char *)trigger_tab + sizeof(struct acpi_einj_trigger)); 248 apei_resources_init(&trigger_resources); 249 apei_exec_ctx_init(&trigger_ctx, einj_ins_type, 250 ARRAY_SIZE(einj_ins_type), 251 trigger_entry, trigger_tab->entry_count); 252 rc = apei_exec_collect_resources(&trigger_ctx, &trigger_resources); 253 if (rc) 254 goto out_fini; 255 rc = apei_resources_sub(&trigger_resources, &einj_resources); 256 if (rc) 257 goto out_fini; 258 rc = apei_resources_request(&trigger_resources, "APEI EINJ Trigger"); 259 if (rc) 260 goto out_fini; 261 rc = apei_exec_pre_map_gars(&trigger_ctx); 262 if (rc) 263 goto out_release; 264 265 rc = apei_exec_run(&trigger_ctx, ACPI_EINJ_TRIGGER_ERROR); 266 267 apei_exec_post_unmap_gars(&trigger_ctx); 268out_release: 269 apei_resources_release(&trigger_resources); 270out_fini: 271 apei_resources_fini(&trigger_resources); 272out_rel_entry: 273 release_mem_region(trigger_paddr + sizeof(*trigger_tab), 274 table_size - sizeof(*trigger_tab)); 275out_rel_header: 276 release_mem_region(trigger_paddr, sizeof(*trigger_tab)); 277out: 278 if (trigger_tab) 279 iounmap(trigger_tab); 280 281 return rc; 282} 283 284static int __einj_error_inject(u32 type, u64 param1, u64 param2) 285{ 286 struct apei_exec_context ctx; 287 u64 val, trigger_paddr, timeout = FIRMWARE_TIMEOUT; 288 int rc; 289 290 einj_exec_ctx_init(&ctx); 291 292 rc = apei_exec_run_optional(&ctx, ACPI_EINJ_BEGIN_OPERATION); 293 if (rc) 294 return rc; 295 apei_exec_ctx_set_input(&ctx, type); 296 rc = apei_exec_run(&ctx, ACPI_EINJ_SET_ERROR_TYPE); 297 if (rc) 298 return rc; 299 if (einj_param) { 300 writeq(param1, &einj_param->param1); 301 writeq(param2, &einj_param->param2); 302 } 303 rc = apei_exec_run(&ctx, ACPI_EINJ_EXECUTE_OPERATION); 304 if (rc) 305 return rc; 306 for (;;) { 307 rc = apei_exec_run(&ctx, ACPI_EINJ_CHECK_BUSY_STATUS); 308 if (rc) 309 return rc; 310 val = apei_exec_ctx_get_output(&ctx); 311 if (!(val & EINJ_OP_BUSY)) 312 break; 313 if (einj_timedout(&timeout)) 314 return -EIO; 315 } 316 rc = apei_exec_run(&ctx, ACPI_EINJ_GET_COMMAND_STATUS); 317 if (rc) 318 return rc; 319 val = apei_exec_ctx_get_output(&ctx); 320 if (val != EINJ_STATUS_SUCCESS) 321 return -EBUSY; 322 323 rc = apei_exec_run(&ctx, ACPI_EINJ_GET_TRIGGER_TABLE); 324 if (rc) 325 return rc; 326 trigger_paddr = apei_exec_ctx_get_output(&ctx); 327 rc = __einj_error_trigger(trigger_paddr); 328 if (rc) 329 return rc; 330 rc = apei_exec_run_optional(&ctx, ACPI_EINJ_END_OPERATION); 331 332 return rc; 333} 334 335/* Inject the specified hardware error */ 336static int einj_error_inject(u32 type, u64 param1, u64 param2) 337{ 338 int rc; 339 340 mutex_lock(&einj_mutex); 341 rc = __einj_error_inject(type, param1, param2); 342 mutex_unlock(&einj_mutex); 343 344 return rc; 345} 346 347static u32 error_type; 348static u64 error_param1; 349static u64 error_param2; 350static struct dentry *einj_debug_dir; 351 352static int available_error_type_show(struct seq_file *m, void *v) 353{ 354 int rc; 355 u32 available_error_type = 0; 356 357 rc = einj_get_available_error_type(&available_error_type); 358 if (rc) 359 return rc; 360 if (available_error_type & 0x0001) 361 seq_printf(m, "0x00000001\tProcessor Correctable\n"); 362 if (available_error_type & 0x0002) 363 seq_printf(m, "0x00000002\tProcessor Uncorrectable non-fatal\n"); 364 if (available_error_type & 0x0004) 365 seq_printf(m, "0x00000004\tProcessor Uncorrectable fatal\n"); 366 if (available_error_type & 0x0008) 367 seq_printf(m, "0x00000008\tMemory Correctable\n"); 368 if (available_error_type & 0x0010) 369 seq_printf(m, "0x00000010\tMemory Uncorrectable non-fatal\n"); 370 if (available_error_type & 0x0020) 371 seq_printf(m, "0x00000020\tMemory Uncorrectable fatal\n"); 372 if (available_error_type & 0x0040) 373 seq_printf(m, "0x00000040\tPCI Express Correctable\n"); 374 if (available_error_type & 0x0080) 375 seq_printf(m, "0x00000080\tPCI Express Uncorrectable non-fatal\n"); 376 if (available_error_type & 0x0100) 377 seq_printf(m, "0x00000100\tPCI Express Uncorrectable fatal\n"); 378 if (available_error_type & 0x0200) 379 seq_printf(m, "0x00000200\tPlatform Correctable\n"); 380 if (available_error_type & 0x0400) 381 seq_printf(m, "0x00000400\tPlatform Uncorrectable non-fatal\n"); 382 if (available_error_type & 0x0800) 383 seq_printf(m, "0x00000800\tPlatform Uncorrectable fatal\n"); 384 385 return 0; 386} 387 388static int available_error_type_open(struct inode *inode, struct file *file) 389{ 390 return single_open(file, available_error_type_show, NULL); 391} 392 393static const struct file_operations available_error_type_fops = { 394 .open = available_error_type_open, 395 .read = seq_read, 396 .llseek = seq_lseek, 397 .release = single_release, 398}; 399 400static int error_type_get(void *data, u64 *val) 401{ 402 *val = error_type; 403 404 return 0; 405} 406 407static int error_type_set(void *data, u64 val) 408{ 409 int rc; 410 u32 available_error_type = 0; 411 412 /* Only one error type can be specified */ 413 if (val & (val - 1)) 414 return -EINVAL; 415 rc = einj_get_available_error_type(&available_error_type); 416 if (rc) 417 return rc; 418 if (!(val & available_error_type)) 419 return -EINVAL; 420 error_type = val; 421 422 return 0; 423} 424 425DEFINE_SIMPLE_ATTRIBUTE(error_type_fops, error_type_get, 426 error_type_set, "0x%llx\n"); 427 428static int error_inject_set(void *data, u64 val) 429{ 430 if (!error_type) 431 return -EINVAL; 432 433 return einj_error_inject(error_type, error_param1, error_param2); 434} 435 436DEFINE_SIMPLE_ATTRIBUTE(error_inject_fops, NULL, 437 error_inject_set, "%llu\n"); 438 439static int einj_check_table(struct acpi_table_einj *einj_tab) 440{ 441 if ((einj_tab->header_length != 442 (sizeof(struct acpi_table_einj) - sizeof(einj_tab->header))) 443 && (einj_tab->header_length != sizeof(struct acpi_table_einj))) 444 return -EINVAL; 445 if (einj_tab->header.length < sizeof(struct acpi_table_einj)) 446 return -EINVAL; 447 if (einj_tab->entries != 448 (einj_tab->header.length - sizeof(struct acpi_table_einj)) / 449 sizeof(struct acpi_einj_entry)) 450 return -EINVAL; 451 452 return 0; 453} 454 455static int __init einj_init(void) 456{ 457 int rc; 458 u64 param_paddr; 459 acpi_status status; 460 struct dentry *fentry; 461 struct apei_exec_context ctx; 462 463 if (acpi_disabled) 464 return -ENODEV; 465 466 status = acpi_get_table(ACPI_SIG_EINJ, 0, 467 (struct acpi_table_header **)&einj_tab); 468 if (status == AE_NOT_FOUND) { 469 pr_info(EINJ_PFX "Table is not found!\n"); 470 return -ENODEV; 471 } else if (ACPI_FAILURE(status)) { 472 const char *msg = acpi_format_exception(status); 473 pr_err(EINJ_PFX "Failed to get table, %s\n", msg); 474 return -EINVAL; 475 } 476 477 rc = einj_check_table(einj_tab); 478 if (rc) { 479 pr_warning(FW_BUG EINJ_PFX "EINJ table is invalid\n"); 480 return -EINVAL; 481 } 482 483 rc = -ENOMEM; 484 einj_debug_dir = debugfs_create_dir("einj", apei_get_debugfs_dir()); 485 if (!einj_debug_dir) 486 goto err_cleanup; 487 fentry = debugfs_create_file("available_error_type", S_IRUSR, 488 einj_debug_dir, NULL, 489 &available_error_type_fops); 490 if (!fentry) 491 goto err_cleanup; 492 fentry = debugfs_create_file("error_type", S_IRUSR | S_IWUSR, 493 einj_debug_dir, NULL, &error_type_fops); 494 if (!fentry) 495 goto err_cleanup; 496 fentry = debugfs_create_file("error_inject", S_IWUSR, 497 einj_debug_dir, NULL, &error_inject_fops); 498 if (!fentry) 499 goto err_cleanup; 500 501 apei_resources_init(&einj_resources); 502 einj_exec_ctx_init(&ctx); 503 rc = apei_exec_collect_resources(&ctx, &einj_resources); 504 if (rc) 505 goto err_fini; 506 rc = apei_resources_request(&einj_resources, "APEI EINJ"); 507 if (rc) 508 goto err_fini; 509 rc = apei_exec_pre_map_gars(&ctx); 510 if (rc) 511 goto err_release; 512 if (param_extension) { 513 param_paddr = einj_get_parameter_address(); 514 if (param_paddr) { 515 einj_param = ioremap(param_paddr, sizeof(*einj_param)); 516 rc = -ENOMEM; 517 if (!einj_param) 518 goto err_unmap; 519 fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR, 520 einj_debug_dir, &error_param1); 521 if (!fentry) 522 goto err_unmap; 523 fentry = debugfs_create_x64("param2", S_IRUSR | S_IWUSR, 524 einj_debug_dir, &error_param2); 525 if (!fentry) 526 goto err_unmap; 527 } else 528 pr_warn(EINJ_PFX "Parameter extension is not supported.\n"); 529 } 530 531 pr_info(EINJ_PFX "Error INJection is initialized.\n"); 532 533 return 0; 534 535err_unmap: 536 if (einj_param) 537 iounmap(einj_param); 538 apei_exec_post_unmap_gars(&ctx); 539err_release: 540 apei_resources_release(&einj_resources); 541err_fini: 542 apei_resources_fini(&einj_resources); 543err_cleanup: 544 debugfs_remove_recursive(einj_debug_dir); 545 546 return rc; 547} 548 549static void __exit einj_exit(void) 550{ 551 struct apei_exec_context ctx; 552 553 if (einj_param) 554 iounmap(einj_param); 555 einj_exec_ctx_init(&ctx); 556 apei_exec_post_unmap_gars(&ctx); 557 apei_resources_release(&einj_resources); 558 apei_resources_fini(&einj_resources); 559 debugfs_remove_recursive(einj_debug_dir); 560} 561 562module_init(einj_init); 563module_exit(einj_exit); 564 565MODULE_AUTHOR("Huang Ying"); 566MODULE_DESCRIPTION("APEI Error INJection support"); 567MODULE_LICENSE("GPL");