SCI reporting for other error types not only correctable ones

+ APEI GHES cleanups
 + mce timer fix
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.15 (GNU/Linux)
 
 iQIcBAABAgAGBQJS0qbXAAoJEBLB8Bhh3lVK0G4P/1fjGcBzCiC4qp0vUzhdvu1d
 CXVTtF20fdGP+hgwVU/1DLuIeUhyBLFM57rPgz0FxfvPo/bTYq92Lw9sElQpiVad
 trIRpw3bemjDY/8E91vR94SqLKTddoJifldK5ZTUpRJN9up06MwLky4IurdL2ixE
 QLaI20ZQIDjxe+pmh4wHtyV5qPdtkiXY2ICcdTXwAW7RdiG7pXXd5gLljL4oFUMF
 bp0QzM074szkDvhBgZg6KTAy1zfNzZVM9hUBOAesi1tfXqkT7pCEbUkYKZ6QFNVV
 haQNt+RtkVvYcFcZK+9TkRM32KHSy1MVuicv2W6eNvRDtauGFtSEwBBuvyq3Imjb
 PTY6Vd5g/hR/+o968ieYUYdFua4xaza2wqC3mwL6WuNoWGzzb/f4dk9+wU/x0Khu
 th1NMSwy7VfNqi8pbTTy13LG1yjqqorrMLAEAfsNAMjZPIPsBREFYu8J5kko4ird
 1aEsaENUdkzgoDEUxwO7vQEfAL3RBOC8kr4SrBGd5jQtbN4SYRyP0bYVIsQL3Psz
 fo0H+9sVLwkSxcx7MM0bboBcv0NYazvTS5aIiivSdwMq0uxDsRWRmUCr70AlJDp9
 h7EfyovynCpfOcAOIz212A9bRzBcfW46KnQm6xkcgVdKKhEbc5EWhx6Nz3kCMNQZ
 Or1B6ZtUe7Acdg2kRTRL
 =+eFf
 -----END PGP SIGNATURE-----

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: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
Ingo Molnar 2014-01-12 17:56:54 +01:00
commit b769e014f3
6 changed files with 47 additions and 39 deletions

View file

@ -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();

View file

@ -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)

View file

@ -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,
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",

View file

@ -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,
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)
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) {

View file

@ -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;

View file

@ -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 (!(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 && if (sec_sev == GHES_SEV_CORRECTED &&
(gdata->flags & CPER_SEC_ERROR_THRESHOLD_EXCEEDED) && (gdata->flags & CPER_SEC_ERROR_THRESHOLD_EXCEEDED))
(mem_err->validation_bits & CPER_MEM_VALID_PA)) { flags = MF_SOFT_OFFLINE;
pfn = mem_err->physical_addr >> PAGE_SHIFT; if (sev == GHES_SEV_RECOVERABLE && sec_sev == GHES_SEV_RECOVERABLE)
if (pfn_valid(pfn)) flags = 0;
memory_failure_queue(pfn, 0, MF_SOFT_OFFLINE);
else if (printk_ratelimit()) if (flags != -1)
pr_warn(FW_WARN GHES_PFX memory_failure_queue(pfn, 0, flags);
"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);
}
#endif #endif
} }
@ -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);
} }