RAS changes for v3.14
Subsystems (8)
Linus,
Please pull the latest x86-ras-for-linus git tree from:
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86-ras-for-linus
# HEAD: b769e014f3ae4af8a56c6327077b3c40410dedad Merge tag 'ras_for_3.14_p2' of git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras into x86/ras
The main changes:
* SCI reporting for other error types not only correctable ones
* GHES cleanups
* Add the functionality to override error reporting agents as some machines are sporting a new extended error logging capability which, if done properly in the BIOS, makes a corresponding EDAC module redundant
* PCIe AER tracepoint severity levels fix
* Error path correction for the mce device init
* MCE timer fix
* Add more flexibility to the error injection (EINJ) debugfs interface
out-of-topic modifications in x86-ras-for-linus:
--------------------------------------------------
drivers/acpi/acpi_extlog.c # 42139eb: ACPI, eMCA: Combine eMCA/EDAC eve
drivers/acpi/apei/apei-base.c # d3ab3ed: ACPI, APEI: Cleanup alignment-awa
drivers/acpi/apei/einj.c # d3ab3ed: ACPI, APEI: Cleanup alignment-awa
# 3482fb5: ACPI, APEI, EINJ: Changes to the
drivers/acpi/apei/erst.c # d3ab3ed: ACPI, APEI: Cleanup alignment-awa
drivers/acpi/apei/ghes.c # ca104ed: ACPI, APEI, GHES: Cleanup ghes me
# addccbb: ACPI, APEI, GHES: Do not report o
drivers/edac/edac_stub.c # c700f01: EDAC: Add an edac_report paramete
drivers/edac/sb_edac.c # fd52103: EDAC, sb_edac: Modify H/W event r
include/linux/edac.h # c700f01: EDAC: Add an edac_report paramete
include/trace/events/ras.h # 545104d: PCI, AER: Fix severity usage in aThanks,
Ingo
------------------>
Borislav Petkov (1):
x86, mce: Fix mce_start_timer semantics
Chen, Gong (6):
EDAC: Add an edac_report parameter to EDAC
EDAC, sb_edac: Modify H/W event reporting policy ACPI, eMCA: Combine eMCA/EDAC event reporting priority ACPI, APEI, GHES: Do not report only correctable errors with SCI ACPI, APEI: Cleanup alignment-aware accesses
ACPI, APEI, GHES: Cleanup ghes memory error handling
Levente Kurusa (1):
x86, mce: Call put_device on device_register failure
Rui Wang (1):
PCI, AER: Fix severity usage in aer trace event
Tony Luck (1):
ACPI, APEI, EINJ: Changes to the ACPI/APEI/EINJ debugfs interface
Documentation/acpi/apei/einj.txt | 19 +++++++++++- Documentation/kernel-parameters.txt | 8 +++++ arch/x86/kernel/cpu/mcheck/mce-apei.c | 14 ++++++--- arch/x86/kernel/cpu/mcheck/mce.c | 12 +++++--- drivers/acpi/acpi_extlog.c | 18 +++++++++-- drivers/acpi/apei/apei-base.c | 4 +-- drivers/acpi/apei/einj.c | 58 ++++++++++++++++++++++++++--------- drivers/acpi/apei/erst.c | 2 +- drivers/acpi/apei/ghes.c | 39 ++++++++++++----------- drivers/edac/edac_stub.c | 19 ++++++++++++ drivers/edac/sb_edac.c | 6 +++- include/linux/edac.h | 28 +++++++++++++++++ include/trace/events/ras.h | 10 +++--- 13 files changed, 183 insertions(+), 54 deletions(-)
Documentation/acpi/apei/einj.txt +18 -1
@@ -45,11 +45,22 @@ directory apei/einj. The following files are provided. injection. Before this, please specify all necessary error parameters. +- flags + Present for kernel version 3.13 and above. Used to specify which + of param{1..4} are valid and should be used by BIOS during injection. + Value is a bitmask as specified in ACPI5.0 spec for the + SET_ERROR_TYPE_WITH_ADDRESS data structure: + Bit 0 - Processor APIC field valid (see param3 below) + Bit 1 - Memory address and mask valid (param1 and param2) + Bit 2 - PCIe (seg,bus,dev,fn) valid (param4 below) + If set to zero, legacy behaviour is used where the type of injection + specifies just one bit set, and param1 is multiplexed. + - param1 This file is used to set the first error parameter value. Effect of parameter depends on error_type specified. For example, if error type is memory related type, the param1 should be a valid physical - memory address. + memory address. [Unless "flag" is set - see above] - param2 This file is used to set the second error parameter value. Effect of
@@ -58,6 +69,12 @@ directory apei/einj. The following files are provided. address mask. Linux requires page or narrower granularity, say, 0xfffffffffffff000. +- param3 + Used when the 0x1 bit is set in "flag" to specify the APIC id + +- param4 + Used when the 0x4 bit is set in "flag" to specify target PCIe device + - notrigger The EINJ mechanism is a two step process. First inject the error, then perform some actions to trigger it. Setting "notrigger" to 1 skips the
Documentation/kernel-parameters.txt +8 -0
@@ -881,6 +881,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted. The xen output can only be used by Xen PV guests. + edac_report= [HW,EDAC] Control how to report EDAC event + Format: {"on" | "off" | "force"} + on: enable EDAC to report H/W event. May be overridden + by other higher priority error reporting module. + off: disable H/W event reporting through EDAC. + force: enforce the use of EDAC to report H/W event. + default: on. + ekgdboc= [X86,KGDB] Allow early kernel console debugging ekgdboc=kbd
arch/x86/kernel/cpu/mcheck/mce-apei.c +10 -4
@@ -33,22 +33,28 @@#include <linux/acpi.h> #include <linux/cper.h> #include <acpi/apei.h> +#include <acpi/ghes.h> #include <asm/mce.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; -/* Only corrected MC is reported */ -if (!corrected || !(mem_err->validation_bits &CPER_MEM_VALID_PA )) +if (!(mem_err->validation_bits &CPER_MEM_VALID_PA ))return ;mce_setup (&m); 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 ; + +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;mce_log (&m);mce_notify_irq ();
arch/x86/kernel/cpu/mcheck/mce.c +7 -5
@@ -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) { -unsigned long iv =mce_adjust_timer (check_interval *HZ ); - -__this_cpu_write (mce_next_interval, iv); +unsigned long iv = check_interval *HZ ;if (mca_cfg.ignore_ce || !iv)return ; +per_cpu (mce_next_interval, cpu) = 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 )
@@ -2272,8 +2272,10 @@ static int mce_device_create(unsigned int cpu) dev->release = &mce_device_release; err =device_register (dev); -if (err) +if (err) { +put_device (dev);return err; + }for (i =0 ; mce_device_attrs[i]; i++) { err =device_create_file (dev, mce_device_attrs[i]);
drivers/acpi/acpi_extlog.c +16 -2
@@ -12,6 +12,7 @@#include <acpi/acpi_bus.h> #include <linux/cper.h> #include <linux/ratelimit.h> +#include <linux/edac.h> #include <asm/cpu.h> #include <asm/mce.h>
@@ -43,6 +44,8 @@ struct extlog_l1_head {u8 rev1[12 ]; }; +static int old_edac_report_status; +static u8 extlog_dsm_uuid[] ="663E35AF-CC10-41A4-88EA-5470AF055295" ;/* L1 table related physical address */
@@ -150,7 +153,7 @@ static int extlog_print(struct notifier_block *nb, unsigned long val, rc =print_extlog_rcd (NULL , (struct acpi_generic_status *)elog_buf, cpu); -return NOTIFY_DONE ; +return NOTIFY_STOP ; }static int extlog_get_dsm (acpi_handle handle,int rev,int func,u64 *ret)
@@ -231,8 +234,12 @@ static int __init extlog_init(void)u64 cap;int rc; - rc = -ENODEV ; +if (get_edac_report_status () ==EDAC_REPORTING_FORCE ) { +pr_warn ("Not loading eMCA, error reporting force-enabled through EDAC.\n" ); +return -EPERM ; + } + rc = -ENODEV ;rdmsrl (MSR_IA32_MCG_CAP , cap);if (!(cap &MCG_ELOG_P ))return rc;
@@ -287,6 +294,12 @@ static int __init extlog_init(void)if (elog_buf ==NULL ) goto err_release_elog; +/* +* eMCA event report method has higher priority than EDAC method, +* unless EDAC event report method is mandatory. +*/ + old_edac_report_status =get_edac_report_status (); +set_edac_report_status (EDAC_REPORTING_DISABLED );mce_register_decode_chain (&extlog_mce_dec);/* enable OS to be involved to take over management from BIOS */ ((struct extlog_l1_head *)extlog_l1_addr)->flags |=FLAG_OS_OPTIN ;
@@ -308,6 +321,7 @@ err: static void __exit extlog_exit(void) { +set_edac_report_status (old_edac_report_status);mce_unregister_decode_chain (&extlog_mce_dec); ((struct extlog_l1_head *)extlog_l1_addr)->flags &= ~FLAG_OS_OPTIN ;if (extlog_l1_addr)
drivers/acpi/apei/apei-base.c +2 -2
@@ -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",
drivers/acpi/apei/einj.c +43 -15
151 lines not on this page · raw message
drivers/acpi/apei/erst.c +1 -1
@@ -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;
drivers/acpi/apei/ghes.c +21 -18
@@ -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); }
drivers/edac/edac_stub.c +19 -0
@@ -29,6 +29,25 @@ EXPORT_SYMBOL_GPL(edac_err_assert);static atomic_t edac_subsys_valid =ATOMIC_INIT (0 ); +int edac_report_status =EDAC_REPORTING_ENABLED ; +EXPORT_SYMBOL_GPL (edac_report_status); + +static int __init edac_report_setup (char *str) +{ +if (!str) +return -EINVAL ; + +if (!strncmp (str,"on" ,2 )) +set_edac_report_status (EDAC_REPORTING_ENABLED ); +else if (!strncmp (str,"off" ,3 )) +set_edac_report_status (EDAC_REPORTING_DISABLED ); +else if (!strncmp (str,"force" ,5 )) +set_edac_report_status (EDAC_REPORTING_FORCE ); + +return 0 ; +} +__setup ("edac_report=" , edac_report_setup); +/* * called to determine if there is an EDAC driver interested in * knowing an event (such as NMI) occurred
drivers/edac/sb_edac.c +5 -1
@@ -1829,6 +1829,9 @@ static int sbridge_mce_check_error(struct notifier_block *nb, unsigned long val,struct mem_ctl_info *mci;struct sbridge_pvt *pvt; +if (get_edac_report_status () ==EDAC_REPORTING_DISABLED ) +return NOTIFY_DONE ; + mci =get_mci_for_node_id (mce->socketid);if (!mci)return NOTIFY_BAD ;
@@ -2142,9 +2145,10 @@ static int __init sbridge_init(void)opstate_init (); pci_rc =pci_register_driver (&sbridge_driver); -if (pci_rc >=0 ) {mce_register_decode_chain (&sbridge_mce_dec); +if (get_edac_report_status () ==EDAC_REPORTING_DISABLED ) +sbridge_printk (KERN_WARNING ,"Loading driver, error reporting disabled.\n" );return 0 ; }
include/linux/edac.h +28 -0
@@ -35,6 +35,34 @@ extern void edac_atomic_assert_error(void);extern struct bus_type *edac_get_sysfs_subsys (void );extern void edac_put_sysfs_subsys (void ); +enum { +EDAC_REPORTING_ENABLED , +EDAC_REPORTING_DISABLED , +EDAC_REPORTING_FORCE +}; + +extern int edac_report_status; +#ifdef CONFIG_EDAC +static inline int get_edac_report_status (void ) +{ +return edac_report_status; +} + +static inline void set_edac_report_status (int new) +{ + edac_report_status = new; +} +#else +static inline int get_edac_report_status (void ) +{ +return EDAC_REPORTING_DISABLED ; +} + +static inline void set_edac_report_status (int new) +{ +} +#endif +static inline void opstate_init (void ) {switch (edac_op_state) {
include/trace/events/ras.h +5 -5
@@ -5,7 +5,7 @@#define _TRACE_AER_H#include <linux/tracepoint.h> -#include <linux/edac.h> +#include <linux/aer.h> /*
@@ -63,10 +63,10 @@ TRACE_EVENT(aer_event,TP_printk ("%s PCIe Bus Error: severity=%s, %s\n" ,__get_str (dev_name), - __entry->severity ==HW_EVENT_ERR_CORRECTED ?"Corrected" : - __entry->severity ==HW_EVENT_ERR_FATAL ? -"Fatal" :"Uncorrected" , - __entry->severity ==HW_EVENT_ERR_CORRECTED ? + __entry->severity ==AER_CORRECTABLE ?"Corrected" : + __entry->severity ==AER_FATAL ? +"Fatal" :"Uncorrected, non-fatal" , + __entry->severity ==AER_CORRECTABLE ?__print_flags (__entry->status,"|" , aer_correctable_errors) :__print_flags (__entry->status,"|" , aer_uncorrectable_errors)) );