921 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * APEI Error INJection support4 *5 * EINJ provides a hardware error injection mechanism, this is useful6 * for debugging and testing of other APEI and RAS features.7 *8 * For more information about EINJ, please refer to ACPI Specification9 * version 4.0, section 17.5.10 *11 * Copyright 2009-2010 Intel Corp.12 * Author: Huang Ying <ying.huang@intel.com>13 */14 15#include <linux/kernel.h>16#include <linux/module.h>17#include <linux/init.h>18#include <linux/io.h>19#include <linux/debugfs.h>20#include <linux/seq_file.h>21#include <linux/nmi.h>22#include <linux/delay.h>23#include <linux/mm.h>24#include <linux/platform_device.h>25#include <linux/unaligned.h>26 27#include "apei-internal.h"28 29#undef pr_fmt30#define pr_fmt(fmt) "EINJ: " fmt31 32#define SLEEP_UNIT_MIN 1000 /* 1ms */33#define SLEEP_UNIT_MAX 5000 /* 5ms */34/* Firmware should respond within 1 seconds */35#define FIRMWARE_TIMEOUT (1 * USEC_PER_SEC)36#define ACPI5_VENDOR_BIT BIT(31)37#define MEM_ERROR_MASK (ACPI_EINJ_MEMORY_CORRECTABLE | \38 ACPI_EINJ_MEMORY_UNCORRECTABLE | \39 ACPI_EINJ_MEMORY_FATAL)40#define CXL_ERROR_MASK (ACPI_EINJ_CXL_CACHE_CORRECTABLE | \41 ACPI_EINJ_CXL_CACHE_UNCORRECTABLE | \42 ACPI_EINJ_CXL_CACHE_FATAL | \43 ACPI_EINJ_CXL_MEM_CORRECTABLE | \44 ACPI_EINJ_CXL_MEM_UNCORRECTABLE | \45 ACPI_EINJ_CXL_MEM_FATAL)46 47/*48 * ACPI version 5 provides a SET_ERROR_TYPE_WITH_ADDRESS action.49 */50static int acpi5;51 52struct set_error_type_with_address {53 u32 type;54 u32 vendor_extension;55 u32 flags;56 u32 apicid;57 u64 memory_address;58 u64 memory_address_range;59 u32 pcie_sbdf;60};61enum {62 SETWA_FLAGS_APICID = 1,63 SETWA_FLAGS_MEM = 2,64 SETWA_FLAGS_PCIE_SBDF = 4,65};66 67/*68 * Vendor extensions for platform specific operations69 */70struct vendor_error_type_extension {71 u32 length;72 u32 pcie_sbdf;73 u16 vendor_id;74 u16 device_id;75 u8 rev_id;76 u8 reserved[3];77};78 79static u32 notrigger;80 81static u32 vendor_flags;82static struct debugfs_blob_wrapper vendor_blob;83static struct debugfs_blob_wrapper vendor_errors;84static char vendor_dev[64];85 86/*87 * Some BIOSes allow parameters to the SET_ERROR_TYPE entries in the88 * EINJ table through an unpublished extension. Use with caution as89 * most will ignore the parameter and make their own choice of address90 * for error injection. This extension is used only if91 * param_extension module parameter is specified.92 */93struct einj_parameter {94 u64 type;95 u64 reserved1;96 u64 reserved2;97 u64 param1;98 u64 param2;99};100 101#define EINJ_OP_BUSY 0x1102#define EINJ_STATUS_SUCCESS 0x0103#define EINJ_STATUS_FAIL 0x1104#define EINJ_STATUS_INVAL 0x2105 106#define EINJ_TAB_ENTRY(tab) \107 ((struct acpi_whea_header *)((char *)(tab) + \108 sizeof(struct acpi_table_einj)))109 110static bool param_extension;111module_param(param_extension, bool, 0);112 113static struct acpi_table_einj *einj_tab;114 115static struct apei_resources einj_resources;116 117static struct apei_exec_ins_type einj_ins_type[] = {118 [ACPI_EINJ_READ_REGISTER] = {119 .flags = APEI_EXEC_INS_ACCESS_REGISTER,120 .run = apei_exec_read_register,121 },122 [ACPI_EINJ_READ_REGISTER_VALUE] = {123 .flags = APEI_EXEC_INS_ACCESS_REGISTER,124 .run = apei_exec_read_register_value,125 },126 [ACPI_EINJ_WRITE_REGISTER] = {127 .flags = APEI_EXEC_INS_ACCESS_REGISTER,128 .run = apei_exec_write_register,129 },130 [ACPI_EINJ_WRITE_REGISTER_VALUE] = {131 .flags = APEI_EXEC_INS_ACCESS_REGISTER,132 .run = apei_exec_write_register_value,133 },134 [ACPI_EINJ_NOOP] = {135 .flags = 0,136 .run = apei_exec_noop,137 },138};139 140/*141 * Prevent EINJ interpreter to run simultaneously, because the142 * corresponding firmware implementation may not work properly when143 * invoked simultaneously.144 */145static DEFINE_MUTEX(einj_mutex);146 147/*148 * Exported APIs use this flag to exit early if einj_probe() failed.149 */150bool einj_initialized __ro_after_init;151 152static void *einj_param;153 154static void einj_exec_ctx_init(struct apei_exec_context *ctx)155{156 apei_exec_ctx_init(ctx, einj_ins_type, ARRAY_SIZE(einj_ins_type),157 EINJ_TAB_ENTRY(einj_tab), einj_tab->entries);158}159 160static int __einj_get_available_error_type(u32 *type)161{162 struct apei_exec_context ctx;163 int rc;164 165 einj_exec_ctx_init(&ctx);166 rc = apei_exec_run(&ctx, ACPI_EINJ_GET_ERROR_TYPE);167 if (rc)168 return rc;169 *type = apei_exec_ctx_get_output(&ctx);170 171 return 0;172}173 174/* Get error injection capabilities of the platform */175int einj_get_available_error_type(u32 *type)176{177 int rc;178 179 mutex_lock(&einj_mutex);180 rc = __einj_get_available_error_type(type);181 mutex_unlock(&einj_mutex);182 183 return rc;184}185 186static int einj_timedout(u64 *t)187{188 if ((s64)*t < SLEEP_UNIT_MIN) {189 pr_warn(FW_WARN "Firmware does not respond in time\n");190 return 1;191 }192 *t -= SLEEP_UNIT_MIN;193 usleep_range(SLEEP_UNIT_MIN, SLEEP_UNIT_MAX);194 195 return 0;196}197 198static void get_oem_vendor_struct(u64 paddr, int offset,199 struct vendor_error_type_extension *v)200{201 unsigned long vendor_size;202 u64 target_pa = paddr + offset + sizeof(struct vendor_error_type_extension);203 204 vendor_size = v->length - sizeof(struct vendor_error_type_extension);205 206 if (vendor_size)207 vendor_errors.data = acpi_os_map_memory(target_pa, vendor_size);208 209 if (vendor_errors.data)210 vendor_errors.size = vendor_size;211}212 213static void check_vendor_extension(u64 paddr,214 struct set_error_type_with_address *v5param)215{216 int offset = v5param->vendor_extension;217 struct vendor_error_type_extension *v;218 u32 sbdf;219 220 if (!offset)221 return;222 v = acpi_os_map_iomem(paddr + offset, sizeof(*v));223 if (!v)224 return;225 get_oem_vendor_struct(paddr, offset, v);226 sbdf = v->pcie_sbdf;227 sprintf(vendor_dev, "%x:%x:%x.%x vendor_id=%x device_id=%x rev_id=%x\n",228 sbdf >> 24, (sbdf >> 16) & 0xff,229 (sbdf >> 11) & 0x1f, (sbdf >> 8) & 0x7,230 v->vendor_id, v->device_id, v->rev_id);231 acpi_os_unmap_iomem(v, sizeof(*v));232}233 234static void *einj_get_parameter_address(void)235{236 int i;237 u64 pa_v4 = 0, pa_v5 = 0;238 struct acpi_whea_header *entry;239 240 entry = EINJ_TAB_ENTRY(einj_tab);241 for (i = 0; i < einj_tab->entries; i++) {242 if (entry->action == ACPI_EINJ_SET_ERROR_TYPE &&243 entry->instruction == ACPI_EINJ_WRITE_REGISTER &&244 entry->register_region.space_id ==245 ACPI_ADR_SPACE_SYSTEM_MEMORY)246 pa_v4 = get_unaligned(&entry->register_region.address);247 if (entry->action == ACPI_EINJ_SET_ERROR_TYPE_WITH_ADDRESS &&248 entry->instruction == ACPI_EINJ_WRITE_REGISTER &&249 entry->register_region.space_id ==250 ACPI_ADR_SPACE_SYSTEM_MEMORY)251 pa_v5 = get_unaligned(&entry->register_region.address);252 entry++;253 }254 if (pa_v5) {255 struct set_error_type_with_address *v5param;256 257 v5param = acpi_os_map_iomem(pa_v5, sizeof(*v5param));258 if (v5param) {259 acpi5 = 1;260 check_vendor_extension(pa_v5, v5param);261 return v5param;262 }263 }264 if (param_extension && pa_v4) {265 struct einj_parameter *v4param;266 267 v4param = acpi_os_map_iomem(pa_v4, sizeof(*v4param));268 if (!v4param)269 return NULL;270 if (v4param->reserved1 || v4param->reserved2) {271 acpi_os_unmap_iomem(v4param, sizeof(*v4param));272 return NULL;273 }274 return v4param;275 }276 277 return NULL;278}279 280/* do sanity check to trigger table */281static int einj_check_trigger_header(struct acpi_einj_trigger *trigger_tab)282{283 if (trigger_tab->header_size != sizeof(struct acpi_einj_trigger))284 return -EINVAL;285 if (trigger_tab->table_size > PAGE_SIZE ||286 trigger_tab->table_size < trigger_tab->header_size)287 return -EINVAL;288 if (trigger_tab->entry_count !=289 (trigger_tab->table_size - trigger_tab->header_size) /290 sizeof(struct acpi_einj_entry))291 return -EINVAL;292 293 return 0;294}295 296static struct acpi_generic_address *einj_get_trigger_parameter_region(297 struct acpi_einj_trigger *trigger_tab, u64 param1, u64 param2)298{299 int i;300 struct acpi_whea_header *entry;301 302 entry = (struct acpi_whea_header *)303 ((char *)trigger_tab + sizeof(struct acpi_einj_trigger));304 for (i = 0; i < trigger_tab->entry_count; i++) {305 if (entry->action == ACPI_EINJ_TRIGGER_ERROR &&306 entry->instruction <= ACPI_EINJ_WRITE_REGISTER_VALUE &&307 entry->register_region.space_id ==308 ACPI_ADR_SPACE_SYSTEM_MEMORY &&309 (entry->register_region.address & param2) == (param1 & param2))310 return &entry->register_region;311 entry++;312 }313 314 return NULL;315}316/* Execute instructions in trigger error action table */317static int __einj_error_trigger(u64 trigger_paddr, u32 type,318 u64 param1, u64 param2)319{320 struct acpi_einj_trigger *trigger_tab = NULL;321 struct apei_exec_context trigger_ctx;322 struct apei_resources trigger_resources;323 struct acpi_whea_header *trigger_entry;324 struct resource *r;325 u32 table_size;326 int rc = -EIO;327 struct acpi_generic_address *trigger_param_region = NULL;328 329 r = request_mem_region(trigger_paddr, sizeof(*trigger_tab),330 "APEI EINJ Trigger Table");331 if (!r) {332 pr_err("Can not request [mem %#010llx-%#010llx] for Trigger table\n",333 (unsigned long long)trigger_paddr,334 (unsigned long long)trigger_paddr +335 sizeof(*trigger_tab) - 1);336 goto out;337 }338 trigger_tab = ioremap_cache(trigger_paddr, sizeof(*trigger_tab));339 if (!trigger_tab) {340 pr_err("Failed to map trigger table!\n");341 goto out_rel_header;342 }343 rc = einj_check_trigger_header(trigger_tab);344 if (rc) {345 pr_warn(FW_BUG "Invalid trigger error action table.\n");346 goto out_rel_header;347 }348 349 /* No action structures in the TRIGGER_ERROR table, nothing to do */350 if (!trigger_tab->entry_count)351 goto out_rel_header;352 353 rc = -EIO;354 table_size = trigger_tab->table_size;355 r = request_mem_region(trigger_paddr + sizeof(*trigger_tab),356 table_size - sizeof(*trigger_tab),357 "APEI EINJ Trigger Table");358 if (!r) {359 pr_err("Can not request [mem %#010llx-%#010llx] for Trigger Table Entry\n",360 (unsigned long long)trigger_paddr + sizeof(*trigger_tab),361 (unsigned long long)trigger_paddr + table_size - 1);362 goto out_rel_header;363 }364 iounmap(trigger_tab);365 trigger_tab = ioremap_cache(trigger_paddr, table_size);366 if (!trigger_tab) {367 pr_err("Failed to map trigger table!\n");368 goto out_rel_entry;369 }370 trigger_entry = (struct acpi_whea_header *)371 ((char *)trigger_tab + sizeof(struct acpi_einj_trigger));372 apei_resources_init(&trigger_resources);373 apei_exec_ctx_init(&trigger_ctx, einj_ins_type,374 ARRAY_SIZE(einj_ins_type),375 trigger_entry, trigger_tab->entry_count);376 rc = apei_exec_collect_resources(&trigger_ctx, &trigger_resources);377 if (rc)378 goto out_fini;379 rc = apei_resources_sub(&trigger_resources, &einj_resources);380 if (rc)381 goto out_fini;382 /*383 * Some firmware will access target address specified in384 * param1 to trigger the error when injecting memory error.385 * This will cause resource conflict with regular memory. So386 * remove it from trigger table resources.387 */388 if ((param_extension || acpi5) && (type & MEM_ERROR_MASK) && param2) {389 struct apei_resources addr_resources;390 391 apei_resources_init(&addr_resources);392 trigger_param_region = einj_get_trigger_parameter_region(393 trigger_tab, param1, param2);394 if (trigger_param_region) {395 rc = apei_resources_add(&addr_resources,396 trigger_param_region->address,397 trigger_param_region->bit_width/8, true);398 if (rc)399 goto out_fini;400 rc = apei_resources_sub(&trigger_resources,401 &addr_resources);402 }403 apei_resources_fini(&addr_resources);404 if (rc)405 goto out_fini;406 }407 rc = apei_resources_request(&trigger_resources, "APEI EINJ Trigger");408 if (rc)409 goto out_fini;410 rc = apei_exec_pre_map_gars(&trigger_ctx);411 if (rc)412 goto out_release;413 414 rc = apei_exec_run(&trigger_ctx, ACPI_EINJ_TRIGGER_ERROR);415 416 apei_exec_post_unmap_gars(&trigger_ctx);417out_release:418 apei_resources_release(&trigger_resources);419out_fini:420 apei_resources_fini(&trigger_resources);421out_rel_entry:422 release_mem_region(trigger_paddr + sizeof(*trigger_tab),423 table_size - sizeof(*trigger_tab));424out_rel_header:425 release_mem_region(trigger_paddr, sizeof(*trigger_tab));426out:427 if (trigger_tab)428 iounmap(trigger_tab);429 430 return rc;431}432 433static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2,434 u64 param3, u64 param4)435{436 struct apei_exec_context ctx;437 u64 val, trigger_paddr, timeout = FIRMWARE_TIMEOUT;438 int rc;439 440 einj_exec_ctx_init(&ctx);441 442 rc = apei_exec_run_optional(&ctx, ACPI_EINJ_BEGIN_OPERATION);443 if (rc)444 return rc;445 apei_exec_ctx_set_input(&ctx, type);446 if (acpi5) {447 struct set_error_type_with_address *v5param = einj_param;448 449 v5param->type = type;450 if (type & ACPI5_VENDOR_BIT) {451 switch (vendor_flags) {452 case SETWA_FLAGS_APICID:453 v5param->apicid = param1;454 break;455 case SETWA_FLAGS_MEM:456 v5param->memory_address = param1;457 v5param->memory_address_range = param2;458 break;459 case SETWA_FLAGS_PCIE_SBDF:460 v5param->pcie_sbdf = param1;461 break;462 }463 v5param->flags = vendor_flags;464 } else if (flags) {465 v5param->flags = flags;466 v5param->memory_address = param1;467 v5param->memory_address_range = param2;468 v5param->apicid = param3;469 v5param->pcie_sbdf = param4;470 } else {471 switch (type) {472 case ACPI_EINJ_PROCESSOR_CORRECTABLE:473 case ACPI_EINJ_PROCESSOR_UNCORRECTABLE:474 case ACPI_EINJ_PROCESSOR_FATAL:475 v5param->apicid = param1;476 v5param->flags = SETWA_FLAGS_APICID;477 break;478 case ACPI_EINJ_MEMORY_CORRECTABLE:479 case ACPI_EINJ_MEMORY_UNCORRECTABLE:480 case ACPI_EINJ_MEMORY_FATAL:481 v5param->memory_address = param1;482 v5param->memory_address_range = param2;483 v5param->flags = SETWA_FLAGS_MEM;484 break;485 case ACPI_EINJ_PCIX_CORRECTABLE:486 case ACPI_EINJ_PCIX_UNCORRECTABLE:487 case ACPI_EINJ_PCIX_FATAL:488 v5param->pcie_sbdf = param1;489 v5param->flags = SETWA_FLAGS_PCIE_SBDF;490 break;491 }492 }493 } else {494 rc = apei_exec_run(&ctx, ACPI_EINJ_SET_ERROR_TYPE);495 if (rc)496 return rc;497 if (einj_param) {498 struct einj_parameter *v4param = einj_param;499 500 v4param->param1 = param1;501 v4param->param2 = param2;502 }503 }504 rc = apei_exec_run(&ctx, ACPI_EINJ_EXECUTE_OPERATION);505 if (rc)506 return rc;507 for (;;) {508 rc = apei_exec_run(&ctx, ACPI_EINJ_CHECK_BUSY_STATUS);509 if (rc)510 return rc;511 val = apei_exec_ctx_get_output(&ctx);512 if (!(val & EINJ_OP_BUSY))513 break;514 if (einj_timedout(&timeout))515 return -EIO;516 }517 rc = apei_exec_run(&ctx, ACPI_EINJ_GET_COMMAND_STATUS);518 if (rc)519 return rc;520 val = apei_exec_ctx_get_output(&ctx);521 if (val == EINJ_STATUS_FAIL)522 return -EBUSY;523 else if (val == EINJ_STATUS_INVAL)524 return -EINVAL;525 526 /*527 * The error is injected into the platform successfully, then it needs528 * to trigger the error.529 */530 rc = apei_exec_run(&ctx, ACPI_EINJ_GET_TRIGGER_TABLE);531 if (rc)532 return rc;533 trigger_paddr = apei_exec_ctx_get_output(&ctx);534 if (notrigger == 0) {535 rc = __einj_error_trigger(trigger_paddr, type, param1, param2);536 if (rc)537 return rc;538 }539 rc = apei_exec_run_optional(&ctx, ACPI_EINJ_END_OPERATION);540 541 return rc;542}543 544/* Inject the specified hardware error */545int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, u64 param3,546 u64 param4)547{548 int rc;549 u64 base_addr, size;550 551 /* If user manually set "flags", make sure it is legal */552 if (flags && (flags &553 ~(SETWA_FLAGS_APICID|SETWA_FLAGS_MEM|SETWA_FLAGS_PCIE_SBDF)))554 return -EINVAL;555 556 /*557 * We need extra sanity checks for memory errors.558 * Other types leap directly to injection.559 */560 561 /* ensure param1/param2 existed */562 if (!(param_extension || acpi5))563 goto inject;564 565 /* ensure injection is memory related */566 if (type & ACPI5_VENDOR_BIT) {567 if (vendor_flags != SETWA_FLAGS_MEM)568 goto inject;569 } else if (!(type & MEM_ERROR_MASK) && !(flags & SETWA_FLAGS_MEM)) {570 goto inject;571 }572 573 /*574 * Injections targeting a CXL 1.0/1.1 port have to be injected575 * via the einj_cxl_rch_error_inject() path as that does the proper576 * validation of the given RCRB base (MMIO) address.577 */578 if (einj_is_cxl_error_type(type) && (flags & SETWA_FLAGS_MEM))579 return -EINVAL;580 581 /*582 * Disallow crazy address masks that give BIOS leeway to pick583 * injection address almost anywhere. Insist on page or584 * better granularity and that target address is normal RAM or585 * NVDIMM.586 */587 base_addr = param1 & param2;588 size = ~param2 + 1;589 590 if (((param2 & PAGE_MASK) != PAGE_MASK) ||591 ((region_intersects(base_addr, size, IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE)592 != REGION_INTERSECTS) &&593 (region_intersects(base_addr, size, IORESOURCE_MEM, IORES_DESC_PERSISTENT_MEMORY)594 != REGION_INTERSECTS) &&595 (region_intersects(base_addr, size, IORESOURCE_MEM, IORES_DESC_SOFT_RESERVED)596 != REGION_INTERSECTS) &&597 !arch_is_platform_page(base_addr)))598 return -EINVAL;599 600 if (is_zero_pfn(base_addr >> PAGE_SHIFT))601 return -EADDRINUSE;602 603inject:604 mutex_lock(&einj_mutex);605 rc = __einj_error_inject(type, flags, param1, param2, param3, param4);606 mutex_unlock(&einj_mutex);607 608 return rc;609}610 611int einj_cxl_rch_error_inject(u32 type, u32 flags, u64 param1, u64 param2,612 u64 param3, u64 param4)613{614 int rc;615 616 if (!(einj_is_cxl_error_type(type) && (flags & SETWA_FLAGS_MEM)))617 return -EINVAL;618 619 mutex_lock(&einj_mutex);620 rc = __einj_error_inject(type, flags, param1, param2, param3, param4);621 mutex_unlock(&einj_mutex);622 623 return rc;624}625 626static u32 error_type;627static u32 error_flags;628static u64 error_param1;629static u64 error_param2;630static u64 error_param3;631static u64 error_param4;632static struct dentry *einj_debug_dir;633static struct { u32 mask; const char *str; } const einj_error_type_string[] = {634 { BIT(0), "Processor Correctable" },635 { BIT(1), "Processor Uncorrectable non-fatal" },636 { BIT(2), "Processor Uncorrectable fatal" },637 { BIT(3), "Memory Correctable" },638 { BIT(4), "Memory Uncorrectable non-fatal" },639 { BIT(5), "Memory Uncorrectable fatal" },640 { BIT(6), "PCI Express Correctable" },641 { BIT(7), "PCI Express Uncorrectable non-fatal" },642 { BIT(8), "PCI Express Uncorrectable fatal" },643 { BIT(9), "Platform Correctable" },644 { BIT(10), "Platform Uncorrectable non-fatal" },645 { BIT(11), "Platform Uncorrectable fatal"},646 { BIT(31), "Vendor Defined Error Types" },647};648 649static int available_error_type_show(struct seq_file *m, void *v)650{651 int rc;652 u32 error_type = 0;653 654 rc = einj_get_available_error_type(&error_type);655 if (rc)656 return rc;657 for (int pos = 0; pos < ARRAY_SIZE(einj_error_type_string); pos++)658 if (error_type & einj_error_type_string[pos].mask)659 seq_printf(m, "0x%08x\t%s\n", einj_error_type_string[pos].mask,660 einj_error_type_string[pos].str);661 662 return 0;663}664 665DEFINE_SHOW_ATTRIBUTE(available_error_type);666 667static int error_type_get(void *data, u64 *val)668{669 *val = error_type;670 671 return 0;672}673 674bool einj_is_cxl_error_type(u64 type)675{676 return (type & CXL_ERROR_MASK) && (!(type & ACPI5_VENDOR_BIT));677}678 679int einj_validate_error_type(u64 type)680{681 u32 tval, vendor, available_error_type = 0;682 int rc;683 684 /* Only low 32 bits for error type are valid */685 if (type & GENMASK_ULL(63, 32))686 return -EINVAL;687 688 /*689 * Vendor defined types have 0x80000000 bit set, and690 * are not enumerated by ACPI_EINJ_GET_ERROR_TYPE691 */692 vendor = type & ACPI5_VENDOR_BIT;693 tval = type & GENMASK(30, 0);694 695 /* Only one error type can be specified */696 if (tval & (tval - 1))697 return -EINVAL;698 if (!vendor) {699 rc = einj_get_available_error_type(&available_error_type);700 if (rc)701 return rc;702 if (!(type & available_error_type))703 return -EINVAL;704 }705 706 return 0;707}708 709static int error_type_set(void *data, u64 val)710{711 int rc;712 713 rc = einj_validate_error_type(val);714 if (rc)715 return rc;716 717 error_type = val;718 719 return 0;720}721 722DEFINE_DEBUGFS_ATTRIBUTE(error_type_fops, error_type_get, error_type_set,723 "0x%llx\n");724 725static int error_inject_set(void *data, u64 val)726{727 if (!error_type)728 return -EINVAL;729 730 return einj_error_inject(error_type, error_flags, error_param1, error_param2,731 error_param3, error_param4);732}733 734DEFINE_DEBUGFS_ATTRIBUTE(error_inject_fops, NULL, error_inject_set, "%llu\n");735 736static int einj_check_table(struct acpi_table_einj *einj_tab)737{738 if ((einj_tab->header_length !=739 (sizeof(struct acpi_table_einj) - sizeof(einj_tab->header)))740 && (einj_tab->header_length != sizeof(struct acpi_table_einj)))741 return -EINVAL;742 if (einj_tab->header.length < sizeof(struct acpi_table_einj))743 return -EINVAL;744 if (einj_tab->entries !=745 (einj_tab->header.length - sizeof(struct acpi_table_einj)) /746 sizeof(struct acpi_einj_entry))747 return -EINVAL;748 749 return 0;750}751 752static int __init einj_probe(struct platform_device *pdev)753{754 int rc;755 acpi_status status;756 struct apei_exec_context ctx;757 758 if (acpi_disabled) {759 pr_debug("ACPI disabled.\n");760 return -ENODEV;761 }762 763 status = acpi_get_table(ACPI_SIG_EINJ, 0,764 (struct acpi_table_header **)&einj_tab);765 if (status == AE_NOT_FOUND) {766 pr_debug("EINJ table not found.\n");767 return -ENODEV;768 } else if (ACPI_FAILURE(status)) {769 pr_err("Failed to get EINJ table: %s\n",770 acpi_format_exception(status));771 return -EINVAL;772 }773 774 rc = einj_check_table(einj_tab);775 if (rc) {776 pr_warn(FW_BUG "Invalid EINJ table.\n");777 goto err_put_table;778 }779 780 rc = -ENOMEM;781 einj_debug_dir = debugfs_create_dir("einj", apei_get_debugfs_dir());782 783 debugfs_create_file("available_error_type", S_IRUSR, einj_debug_dir,784 NULL, &available_error_type_fops);785 debugfs_create_file_unsafe("error_type", 0600, einj_debug_dir,786 NULL, &error_type_fops);787 debugfs_create_file_unsafe("error_inject", 0200, einj_debug_dir,788 NULL, &error_inject_fops);789 790 apei_resources_init(&einj_resources);791 einj_exec_ctx_init(&ctx);792 rc = apei_exec_collect_resources(&ctx, &einj_resources);793 if (rc) {794 pr_err("Error collecting EINJ resources.\n");795 goto err_fini;796 }797 798 rc = apei_resources_request(&einj_resources, "APEI EINJ");799 if (rc) {800 pr_err("Error requesting memory/port resources.\n");801 goto err_fini;802 }803 804 rc = apei_exec_pre_map_gars(&ctx);805 if (rc) {806 pr_err("Error pre-mapping GARs.\n");807 goto err_release;808 }809 810 einj_param = einj_get_parameter_address();811 if ((param_extension || acpi5) && einj_param) {812 debugfs_create_x32("flags", S_IRUSR | S_IWUSR, einj_debug_dir,813 &error_flags);814 debugfs_create_x64("param1", S_IRUSR | S_IWUSR, einj_debug_dir,815 &error_param1);816 debugfs_create_x64("param2", S_IRUSR | S_IWUSR, einj_debug_dir,817 &error_param2);818 debugfs_create_x64("param3", S_IRUSR | S_IWUSR, einj_debug_dir,819 &error_param3);820 debugfs_create_x64("param4", S_IRUSR | S_IWUSR, einj_debug_dir,821 &error_param4);822 debugfs_create_x32("notrigger", S_IRUSR | S_IWUSR,823 einj_debug_dir, ¬rigger);824 }825 826 if (vendor_dev[0]) {827 vendor_blob.data = vendor_dev;828 vendor_blob.size = strlen(vendor_dev);829 debugfs_create_blob("vendor", S_IRUSR, einj_debug_dir,830 &vendor_blob);831 debugfs_create_x32("vendor_flags", S_IRUSR | S_IWUSR,832 einj_debug_dir, &vendor_flags);833 }834 835 if (vendor_errors.size)836 debugfs_create_blob("oem_error", 0600, einj_debug_dir,837 &vendor_errors);838 839 pr_info("Error INJection is initialized.\n");840 841 return 0;842 843err_release:844 apei_resources_release(&einj_resources);845err_fini:846 apei_resources_fini(&einj_resources);847 debugfs_remove_recursive(einj_debug_dir);848err_put_table:849 acpi_put_table((struct acpi_table_header *)einj_tab);850 851 return rc;852}853 854static void __exit einj_remove(struct platform_device *pdev)855{856 struct apei_exec_context ctx;857 858 if (einj_param) {859 acpi_size size = (acpi5) ?860 sizeof(struct set_error_type_with_address) :861 sizeof(struct einj_parameter);862 863 acpi_os_unmap_iomem(einj_param, size);864 if (vendor_errors.size)865 acpi_os_unmap_memory(vendor_errors.data, vendor_errors.size);866 }867 einj_exec_ctx_init(&ctx);868 apei_exec_post_unmap_gars(&ctx);869 apei_resources_release(&einj_resources);870 apei_resources_fini(&einj_resources);871 debugfs_remove_recursive(einj_debug_dir);872 acpi_put_table((struct acpi_table_header *)einj_tab);873}874 875static struct platform_device *einj_dev;876/*877 * einj_remove() lives in .exit.text. For drivers registered via878 * platform_driver_probe() this is ok because they cannot get unbound at879 * runtime. So mark the driver struct with __refdata to prevent modpost880 * triggering a section mismatch warning.881 */882static struct platform_driver einj_driver __refdata = {883 .remove_new = __exit_p(einj_remove),884 .driver = {885 .name = "acpi-einj",886 },887};888 889static int __init einj_init(void)890{891 struct platform_device_info einj_dev_info = {892 .name = "acpi-einj",893 .id = -1,894 };895 int rc;896 897 einj_dev = platform_device_register_full(&einj_dev_info);898 if (IS_ERR(einj_dev))899 return PTR_ERR(einj_dev);900 901 rc = platform_driver_probe(&einj_driver, einj_probe);902 einj_initialized = rc == 0;903 904 return 0;905}906 907static void __exit einj_exit(void)908{909 if (einj_initialized)910 platform_driver_unregister(&einj_driver);911 912 platform_device_unregister(einj_dev);913}914 915module_init(einj_init);916module_exit(einj_exit);917 918MODULE_AUTHOR("Huang Ying");919MODULE_DESCRIPTION("APEI Error INJection support");920MODULE_LICENSE("GPL");921