Commit b769e014 authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'ras_for_3.14_p2' of git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras into x86/ras

Pull RAS updates from Borislav Petkov:

 " SCI reporting for other error types not only correctable ones
   + APEI GHES cleanups
   + mce timer fix
 "
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents da454075 4f75d841
...@@ -33,22 +33,28 @@ ...@@ -33,22 +33,28 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/cper.h> #include <linux/cper.h>
#include <acpi/apei.h> #include <acpi/apei.h>
#include <acpi/ghes.h>
#include <asm/mce.h> #include <asm/mce.h>
#include "mce-internal.h" #include "mce-internal.h"
void apei_mce_report_mem_error(int corrected, struct cper_sec_mem_err *mem_err) void apei_mce_report_mem_error(int severity, struct cper_sec_mem_err *mem_err)
{ {
struct mce m; struct mce m;
/* Only corrected MC is reported */ if (!(mem_err->validation_bits & CPER_MEM_VALID_PA))
if (!corrected || !(mem_err->validation_bits & CPER_MEM_VALID_PA))
return; return;
mce_setup(&m); mce_setup(&m);
m.bank = 1; m.bank = 1;
/* Fake a memory read corrected error with unknown channel */ /* Fake a memory read error with unknown channel */
m.status = MCI_STATUS_VAL | MCI_STATUS_EN | MCI_STATUS_ADDRV | 0x9f; m.status = MCI_STATUS_VAL | MCI_STATUS_EN | MCI_STATUS_ADDRV | 0x9f;
if (severity >= GHES_SEV_RECOVERABLE)
m.status |= MCI_STATUS_UC;
if (severity >= GHES_SEV_PANIC)
m.status |= MCI_STATUS_PCC;
m.addr = mem_err->physical_addr; m.addr = mem_err->physical_addr;
mce_log(&m); mce_log(&m);
mce_notify_irq(); mce_notify_irq();
......
...@@ -1638,15 +1638,15 @@ static void __mcheck_cpu_init_vendor(struct cpuinfo_x86 *c) ...@@ -1638,15 +1638,15 @@ static void __mcheck_cpu_init_vendor(struct cpuinfo_x86 *c)
static void mce_start_timer(unsigned int cpu, struct timer_list *t) static void mce_start_timer(unsigned int cpu, struct timer_list *t)
{ {
unsigned long iv = mce_adjust_timer(check_interval * HZ); unsigned long iv = check_interval * HZ;
__this_cpu_write(mce_next_interval, iv);
if (mca_cfg.ignore_ce || !iv) if (mca_cfg.ignore_ce || !iv)
return; return;
per_cpu(mce_next_interval, cpu) = iv;
t->expires = round_jiffies(jiffies + iv); t->expires = round_jiffies(jiffies + iv);
add_timer_on(t, smp_processor_id()); add_timer_on(t, cpu);
} }
static void __mcheck_cpu_init_timer(void) static void __mcheck_cpu_init_timer(void)
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include <linux/rculist.h> #include <linux/rculist.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <asm/unaligned.h>
#include "apei-internal.h" #include "apei-internal.h"
...@@ -567,8 +568,7 @@ static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr, ...@@ -567,8 +568,7 @@ static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr,
bit_offset = reg->bit_offset; bit_offset = reg->bit_offset;
access_size_code = reg->access_width; access_size_code = reg->access_width;
space_id = reg->space_id; space_id = reg->space_id;
/* Handle possible alignment issues */ *paddr = get_unaligned(&reg->address);
memcpy(paddr, &reg->address, sizeof(*paddr));
if (!*paddr) { if (!*paddr) {
pr_warning(FW_BUG APEI_PFX pr_warning(FW_BUG APEI_PFX
"Invalid physical address in GAR [0x%llx/%u/%u/%u/%u]\n", "Invalid physical address in GAR [0x%llx/%u/%u/%u/%u]\n",
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <acpi/acpi.h> #include <acpi/acpi.h>
#include <asm/unaligned.h>
#include "apei-internal.h" #include "apei-internal.h"
...@@ -216,7 +217,7 @@ static void check_vendor_extension(u64 paddr, ...@@ -216,7 +217,7 @@ static void check_vendor_extension(u64 paddr,
static void *einj_get_parameter_address(void) static void *einj_get_parameter_address(void)
{ {
int i; int i;
u64 paddrv4 = 0, paddrv5 = 0; u64 pa_v4 = 0, pa_v5 = 0;
struct acpi_whea_header *entry; struct acpi_whea_header *entry;
entry = EINJ_TAB_ENTRY(einj_tab); entry = EINJ_TAB_ENTRY(einj_tab);
...@@ -225,30 +226,28 @@ static void *einj_get_parameter_address(void) ...@@ -225,30 +226,28 @@ static void *einj_get_parameter_address(void)
entry->instruction == ACPI_EINJ_WRITE_REGISTER && entry->instruction == ACPI_EINJ_WRITE_REGISTER &&
entry->register_region.space_id == entry->register_region.space_id ==
ACPI_ADR_SPACE_SYSTEM_MEMORY) ACPI_ADR_SPACE_SYSTEM_MEMORY)
memcpy(&paddrv4, &entry->register_region.address, pa_v4 = get_unaligned(&entry->register_region.address);
sizeof(paddrv4));
if (entry->action == ACPI_EINJ_SET_ERROR_TYPE_WITH_ADDRESS && if (entry->action == ACPI_EINJ_SET_ERROR_TYPE_WITH_ADDRESS &&
entry->instruction == ACPI_EINJ_WRITE_REGISTER && entry->instruction == ACPI_EINJ_WRITE_REGISTER &&
entry->register_region.space_id == entry->register_region.space_id ==
ACPI_ADR_SPACE_SYSTEM_MEMORY) ACPI_ADR_SPACE_SYSTEM_MEMORY)
memcpy(&paddrv5, &entry->register_region.address, pa_v5 = get_unaligned(&entry->register_region.address);
sizeof(paddrv5));
entry++; entry++;
} }
if (paddrv5) { if (pa_v5) {
struct set_error_type_with_address *v5param; 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) { if (v5param) {
acpi5 = 1; acpi5 = 1;
check_vendor_extension(paddrv5, v5param); check_vendor_extension(pa_v5, v5param);
return v5param; return v5param;
} }
} }
if (param_extension && paddrv4) { if (param_extension && pa_v4) {
struct einj_parameter *v4param; struct einj_parameter *v4param;
v4param = acpi_os_map_memory(paddrv4, sizeof(*v4param)); v4param = acpi_os_map_memory(pa_v4, sizeof(*v4param));
if (!v4param) if (!v4param)
return NULL; return NULL;
if (v4param->reserved1 || v4param->reserved2) { if (v4param->reserved1 || v4param->reserved2) {
......
...@@ -611,7 +611,7 @@ static void __erst_record_id_cache_compact(void) ...@@ -611,7 +611,7 @@ static void __erst_record_id_cache_compact(void)
if (entries[i] == APEI_ERST_INVALID_RECORD_ID) if (entries[i] == APEI_ERST_INVALID_RECORD_ID)
continue; continue;
if (wpos != i) if (wpos != i)
memcpy(&entries[wpos], &entries[i], sizeof(entries[i])); entries[wpos] = entries[i];
wpos++; wpos++;
} }
erst_record_id_cache.len = wpos; erst_record_id_cache.len = wpos;
......
...@@ -413,27 +413,31 @@ static void ghes_handle_memory_failure(struct acpi_generic_data *gdata, int sev) ...@@ -413,27 +413,31 @@ static void ghes_handle_memory_failure(struct acpi_generic_data *gdata, int sev)
{ {
#ifdef CONFIG_ACPI_APEI_MEMORY_FAILURE #ifdef CONFIG_ACPI_APEI_MEMORY_FAILURE
unsigned long pfn; unsigned long pfn;
int flags = -1;
int sec_sev = ghes_severity(gdata->error_severity); int sec_sev = ghes_severity(gdata->error_severity);
struct cper_sec_mem_err *mem_err; struct cper_sec_mem_err *mem_err;
mem_err = (struct cper_sec_mem_err *)(gdata + 1); mem_err = (struct cper_sec_mem_err *)(gdata + 1);
if (sec_sev == GHES_SEV_CORRECTED && if (!(mem_err->validation_bits & CPER_MEM_VALID_PA))
(gdata->flags & CPER_SEC_ERROR_THRESHOLD_EXCEEDED) && return;
(mem_err->validation_bits & CPER_MEM_VALID_PA)) {
pfn = mem_err->physical_addr >> PAGE_SHIFT; pfn = mem_err->physical_addr >> PAGE_SHIFT;
if (pfn_valid(pfn)) if (!pfn_valid(pfn)) {
memory_failure_queue(pfn, 0, MF_SOFT_OFFLINE); pr_warn_ratelimited(FW_WARN GHES_PFX
else if (printk_ratelimit()) "Invalid address in generic error data: %#llx\n",
pr_warn(FW_WARN GHES_PFX mem_err->physical_addr);
"Invalid address in generic error data: %#llx\n", return;
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);
} }
/* 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 #endif
} }
...@@ -453,8 +457,7 @@ static void ghes_do_proc(struct ghes *ghes, ...@@ -453,8 +457,7 @@ static void ghes_do_proc(struct ghes *ghes,
ghes_edac_report_mem_error(ghes, sev, mem_err); ghes_edac_report_mem_error(ghes, sev, mem_err);
#ifdef CONFIG_X86_MCE #ifdef CONFIG_X86_MCE
apei_mce_report_mem_error(sev == GHES_SEV_CORRECTED, apei_mce_report_mem_error(sev, mem_err);
mem_err);
#endif #endif
ghes_handle_memory_failure(gdata, sev); ghes_handle_memory_failure(gdata, sev);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment