diff options
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/apei/apei-base.c | 4 | ||||
-rw-r--r-- | drivers/acpi/apei/einj.c | 19 | ||||
-rw-r--r-- | drivers/acpi/apei/erst.c | 2 | ||||
-rw-r--r-- | drivers/acpi/apei/ghes.c | 39 |
4 files changed, 33 insertions, 31 deletions
diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c index 6d2c49b86b7f..e55584a072c6 100644 --- a/drivers/acpi/apei/apei-base.c +++ b/drivers/acpi/apei/apei-base.c @@ -41,6 +41,7 @@ #include <linux/rculist.h> #include <linux/interrupt.h> #include <linux/debugfs.h> +#include <asm/unaligned.h> #include "apei-internal.h" @@ -567,8 +568,7 @@ static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr, bit_offset = reg->bit_offset; access_size_code = reg->access_width; space_id = reg->space_id; - /* Handle possible alignment issues */ - memcpy(paddr, ®->address, sizeof(*paddr)); + *paddr = get_unaligned(®->address); if (!*paddr) { pr_warning(FW_BUG APEI_PFX "Invalid physical address in GAR [0x%llx/%u/%u/%u/%u]\n", diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index c76674e2a01f..7dcc8a824aae 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c @@ -34,6 +34,7 @@ #include <linux/delay.h> #include <linux/mm.h> #include <acpi/acpi.h> +#include <asm/unaligned.h> #include "apei-internal.h" @@ -216,7 +217,7 @@ static void check_vendor_extension(u64 paddr, 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,30 +226,28 @@ 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_memory(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_memory(pa_v4, sizeof(*v4param)); if (!v4param) return NULL; if (v4param->reserved1 || v4param->reserved2) { diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index cb1d557fc22c..ed65e9c4b5b0 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -611,7 +611,7 @@ static void __erst_record_id_cache_compact(void) if (entries[i] == APEI_ERST_INVALID_RECORD_ID) continue; if (wpos != i) - memcpy(&entries[wpos], &entries[i], sizeof(entries[i])); + entries[wpos] = entries[i]; wpos++; } erst_record_id_cache.len = wpos; diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index a30bc313787b..46766ef7ef5d 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -413,27 +413,31 @@ static void ghes_handle_memory_failure(struct acpi_generic_data *gdata, int sev) { #ifdef CONFIG_ACPI_APEI_MEMORY_FAILURE unsigned long pfn; + int flags = -1; int sec_sev = ghes_severity(gdata->error_severity); struct cper_sec_mem_err *mem_err; mem_err = (struct cper_sec_mem_err *)(gdata + 1); - if (sec_sev == GHES_SEV_CORRECTED && - (gdata->flags & CPER_SEC_ERROR_THRESHOLD_EXCEEDED) && - (mem_err->validation_bits & CPER_MEM_VALID_PA)) { - pfn = mem_err->physical_addr >> PAGE_SHIFT; - if (pfn_valid(pfn)) - memory_failure_queue(pfn, 0, MF_SOFT_OFFLINE); - else if (printk_ratelimit()) - pr_warn(FW_WARN GHES_PFX - "Invalid address in generic error data: %#llx\n", - mem_err->physical_addr); - } - if (sev == GHES_SEV_RECOVERABLE && - sec_sev == GHES_SEV_RECOVERABLE && - mem_err->validation_bits & CPER_MEM_VALID_PA) { - pfn = mem_err->physical_addr >> PAGE_SHIFT; - memory_failure_queue(pfn, 0, 0); + if (!(mem_err->validation_bits & CPER_MEM_VALID_PA)) + return; + + pfn = mem_err->physical_addr >> PAGE_SHIFT; + if (!pfn_valid(pfn)) { + pr_warn_ratelimited(FW_WARN GHES_PFX + "Invalid address in generic error data: %#llx\n", + mem_err->physical_addr); + return; } + + /* iff following two events can be handled properly by now */ + if (sec_sev == GHES_SEV_CORRECTED && + (gdata->flags & CPER_SEC_ERROR_THRESHOLD_EXCEEDED)) + flags = MF_SOFT_OFFLINE; + if (sev == GHES_SEV_RECOVERABLE && sec_sev == GHES_SEV_RECOVERABLE) + flags = 0; + + if (flags != -1) + memory_failure_queue(pfn, 0, flags); #endif } @@ -453,8 +457,7 @@ static void ghes_do_proc(struct ghes *ghes, ghes_edac_report_mem_error(ghes, sev, mem_err); #ifdef CONFIG_X86_MCE - apei_mce_report_mem_error(sev == GHES_SEV_CORRECTED, - mem_err); + apei_mce_report_mem_error(sev, mem_err); #endif ghes_handle_memory_failure(gdata, sev); } |