diff options
Diffstat (limited to 'drivers/acpi/apei/einj.c')
| -rw-r--r-- | drivers/acpi/apei/einj.c | 69 |
1 files changed, 48 insertions, 21 deletions
diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index fb57d03e698..a095d4f858d 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c @@ -33,7 +33,7 @@ #include <linux/nmi.h> #include <linux/delay.h> #include <linux/mm.h> -#include <acpi/acpi.h> +#include <asm/unaligned.h> #include "apei-internal.h" @@ -202,7 +202,7 @@ static void check_vendor_extension(u64 paddr, if (!offset) return; - v = acpi_os_map_memory(paddr + offset, sizeof(*v)); + v = acpi_os_map_iomem(paddr + offset, sizeof(*v)); if (!v) return; sbdf = v->pcie_sbdf; @@ -210,13 +210,13 @@ static void check_vendor_extension(u64 paddr, sbdf >> 24, (sbdf >> 16) & 0xff, (sbdf >> 11) & 0x1f, (sbdf >> 8) & 0x7, v->vendor_id, v->device_id, v->rev_id); - acpi_os_unmap_memory(v, sizeof(*v)); + acpi_os_unmap_iomem(v, sizeof(*v)); } static void *einj_get_parameter_address(void) { int i; - u64 paddrv4 = 0, paddrv5 = 0; + u64 pa_v4 = 0, pa_v5 = 0; struct acpi_whea_header *entry; entry = EINJ_TAB_ENTRY(einj_tab); @@ -225,34 +225,32 @@ static void *einj_get_parameter_address(void) entry->instruction == ACPI_EINJ_WRITE_REGISTER && entry->register_region.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) - memcpy(&paddrv4, &entry->register_region.address, - sizeof(paddrv4)); + pa_v4 = get_unaligned(&entry->register_region.address); if (entry->action == ACPI_EINJ_SET_ERROR_TYPE_WITH_ADDRESS && entry->instruction == ACPI_EINJ_WRITE_REGISTER && entry->register_region.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) - memcpy(&paddrv5, &entry->register_region.address, - sizeof(paddrv5)); + pa_v5 = get_unaligned(&entry->register_region.address); entry++; } - if (paddrv5) { + if (pa_v5) { struct set_error_type_with_address *v5param; - v5param = acpi_os_map_memory(paddrv5, sizeof(*v5param)); + v5param = acpi_os_map_iomem(pa_v5, sizeof(*v5param)); if (v5param) { acpi5 = 1; - check_vendor_extension(paddrv5, v5param); + check_vendor_extension(pa_v5, v5param); return v5param; } } - if (param_extension && paddrv4) { + if (param_extension && pa_v4) { struct einj_parameter *v4param; - v4param = acpi_os_map_memory(paddrv4, sizeof(*v4param)); + v4param = acpi_os_map_iomem(pa_v4, sizeof(*v4param)); if (!v4param) return NULL; if (v4param->reserved1 || v4param->reserved2) { - acpi_os_unmap_memory(v4param, sizeof(*v4param)); + acpi_os_unmap_iomem(v4param, sizeof(*v4param)); return NULL; } return v4param; @@ -416,7 +414,8 @@ out: return rc; } -static int __einj_error_inject(u32 type, u64 param1, u64 param2) +static int __einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, + u64 param3, u64 param4) { struct apei_exec_context ctx; u64 val, trigger_paddr, timeout = FIRMWARE_TIMEOUT; @@ -446,6 +445,12 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2) break; } v5param->flags = vendor_flags; + } else if (flags) { + v5param->flags = flags; + v5param->memory_address = param1; + v5param->memory_address_range = param2; + v5param->apicid = param3; + v5param->pcie_sbdf = param4; } else { switch (type) { case ACPI_EINJ_PROCESSOR_CORRECTABLE: @@ -514,11 +519,17 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2) } /* Inject the specified hardware error */ -static int einj_error_inject(u32 type, u64 param1, u64 param2) +static int einj_error_inject(u32 type, u32 flags, u64 param1, u64 param2, + u64 param3, u64 param4) { int rc; unsigned long pfn; + /* If user manually set "flags", make sure it is legal */ + if (flags && (flags & + ~(SETWA_FLAGS_APICID|SETWA_FLAGS_MEM|SETWA_FLAGS_PCIE_SBDF))) + return -EINVAL; + /* * We need extra sanity checks for memory errors. * Other types leap directly to injection. @@ -532,7 +543,7 @@ static int einj_error_inject(u32 type, u64 param1, u64 param2) if (type & ACPI5_VENDOR_BIT) { if (vendor_flags != SETWA_FLAGS_MEM) goto inject; - } else if (!(type & MEM_ERROR_MASK)) + } else if (!(type & MEM_ERROR_MASK) && !(flags & SETWA_FLAGS_MEM)) goto inject; /* @@ -546,15 +557,18 @@ static int einj_error_inject(u32 type, u64 param1, u64 param2) inject: mutex_lock(&einj_mutex); - rc = __einj_error_inject(type, param1, param2); + rc = __einj_error_inject(type, flags, param1, param2, param3, param4); mutex_unlock(&einj_mutex); return rc; } static u32 error_type; +static u32 error_flags; static u64 error_param1; static u64 error_param2; +static u64 error_param3; +static u64 error_param4; static struct dentry *einj_debug_dir; static int available_error_type_show(struct seq_file *m, void *v) @@ -648,7 +662,8 @@ static int error_inject_set(void *data, u64 val) if (!error_type) return -EINVAL; - return einj_error_inject(error_type, error_param1, error_param2); + return einj_error_inject(error_type, error_flags, error_param1, error_param2, + error_param3, error_param4); } DEFINE_SIMPLE_ATTRIBUTE(error_inject_fops, NULL, @@ -729,6 +744,10 @@ static int __init einj_init(void) rc = -ENOMEM; einj_param = einj_get_parameter_address(); if ((param_extension || acpi5) && einj_param) { + fentry = debugfs_create_x32("flags", S_IRUSR | S_IWUSR, + einj_debug_dir, &error_flags); + if (!fentry) + goto err_unmap; fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR, einj_debug_dir, &error_param1); if (!fentry) @@ -737,6 +756,14 @@ static int __init einj_init(void) einj_debug_dir, &error_param2); if (!fentry) goto err_unmap; + fentry = debugfs_create_x64("param3", S_IRUSR | S_IWUSR, + einj_debug_dir, &error_param3); + if (!fentry) + goto err_unmap; + fentry = debugfs_create_x64("param4", S_IRUSR | S_IWUSR, + einj_debug_dir, &error_param4); + if (!fentry) + goto err_unmap; fentry = debugfs_create_x32("notrigger", S_IRUSR | S_IWUSR, einj_debug_dir, ¬rigger); @@ -767,7 +794,7 @@ err_unmap: sizeof(struct set_error_type_with_address) : sizeof(struct einj_parameter); - acpi_os_unmap_memory(einj_param, size); + acpi_os_unmap_iomem(einj_param, size); } apei_exec_post_unmap_gars(&ctx); err_release: @@ -789,7 +816,7 @@ static void __exit einj_exit(void) sizeof(struct set_error_type_with_address) : sizeof(struct einj_parameter); - acpi_os_unmap_memory(einj_param, size); + acpi_os_unmap_iomem(einj_param, size); } einj_exec_ctx_init(&ctx); apei_exec_post_unmap_gars(&ctx); |
