x86, mce, severity: Extend the the mce_severity mechanism to handle UCNA/DEFERRED...
authorChen Yucong <slaoub@gmail.com>
Tue, 18 Nov 2014 02:09:19 +0000 (10:09 +0800)
committerTony Luck <tony.luck@intel.com>
Wed, 19 Nov 2014 18:55:43 +0000 (10:55 -0800)
Until now, the mce_severity mechanism can only identify the severity
of UCNA error as MCE_KEEP_SEVERITY. Meanwhile, it is not able to filter
out DEFERRED error for AMD platform.

This patch extends the mce_severity mechanism for handling
UCNA/DEFERRED error. In order to do this, the patch introduces a new
severity level - MCE_UCNA/DEFERRED_SEVERITY.

In addition, mce_severity is specific to machine check exception,
and it will check MCIP/EIPV/RIPV bits. In order to use mce_severity
mechanism in non-exception context, the patch also introduces a new
argument (is_excp) for mce_severity. `is_excp' is used to explicitly
specify the calling context of mce_severity.

Reviewed-by: Aravind Gopalakrishnan <Aravind.Gopalakrishnan@amd.com>
Signed-off-by: Chen Yucong <slaoub@gmail.com>
Signed-off-by: Tony Luck <tony.luck@intel.com>
arch/x86/include/asm/mce.h
arch/x86/kernel/cpu/mcheck/mce-internal.h
arch/x86/kernel/cpu/mcheck/mce-severity.c
arch/x86/kernel/cpu/mcheck/mce.c
drivers/edac/mce_amd.h

index 276392f121fb98f95dd88cce1730006d77e101f3..51b26e895933cddc06e90904e11471ee4c3f998b 100644 (file)
 #define MCI_STATUS_S    (1ULL<<56)  /* Signaled machine check */
 #define MCI_STATUS_AR   (1ULL<<55)  /* Action required */
 
+/* AMD-specific bits */
+#define MCI_STATUS_DEFERRED    (1ULL<<44)  /* declare an uncorrected error */
+#define MCI_STATUS_POISON      (1ULL<<43)  /* access poisonous data */
+
 /*
  * Note that the full MCACOD field of IA32_MCi_STATUS MSR is
  * bits 15:0.  But bit 12 is the 'F' bit, defined for corrected
index 09edd0b65fefbb1eda927e3af5ac84a8e4ab40cd..10b46906767fd4857389570322757fa89bbc8e6c 100644 (file)
@@ -3,6 +3,8 @@
 
 enum severity_level {
        MCE_NO_SEVERITY,
+       MCE_DEFERRED_SEVERITY,
+       MCE_UCNA_SEVERITY = MCE_DEFERRED_SEVERITY,
        MCE_KEEP_SEVERITY,
        MCE_SOME_SEVERITY,
        MCE_AO_SEVERITY,
@@ -21,7 +23,7 @@ struct mce_bank {
        char                    attrname[ATTR_LEN];     /* attribute name */
 };
 
-int mce_severity(struct mce *a, int tolerant, char **msg);
+int mce_severity(struct mce *a, int tolerant, char **msg, bool is_excp);
 struct dentry *mce_get_debugfs_dir(void);
 
 extern struct mce_bank *mce_banks;
index c370e1c4468ba1a82d98eaef03d7100c05922eeb..8bb433043a7f6877beaa8b38ccb8ec9684069212 100644 (file)
@@ -31,6 +31,7 @@
 
 enum context { IN_KERNEL = 1, IN_USER = 2 };
 enum ser { SER_REQUIRED = 1, NO_SER = 2 };
+enum exception { EXCP_CONTEXT = 1, NO_EXCP = 2 };
 
 static struct severity {
        u64 mask;
@@ -40,6 +41,7 @@ static struct severity {
        unsigned char mcgres;
        unsigned char ser;
        unsigned char context;
+       unsigned char excp;
        unsigned char covered;
        char *msg;
 } severities[] = {
@@ -48,6 +50,8 @@ static struct severity {
 #define  USER          .context = IN_USER
 #define  SER           .ser = SER_REQUIRED
 #define  NOSER         .ser = NO_SER
+#define  EXCP          .excp = EXCP_CONTEXT
+#define  NOEXCP                .excp = NO_EXCP
 #define  BITCLR(x)     .mask = x, .result = 0
 #define  BITSET(x)     .mask = x, .result = x
 #define  MCGMASK(x, y) .mcgmask = x, .mcgres = y
@@ -62,7 +66,7 @@ static struct severity {
                ),
        MCESEV(
                NO, "Not enabled",
-               BITCLR(MCI_STATUS_EN)
+               EXCP, BITCLR(MCI_STATUS_EN)
                ),
        MCESEV(
                PANIC, "Processor context corrupt",
@@ -71,16 +75,20 @@ static struct severity {
        /* When MCIP is not set something is very confused */
        MCESEV(
                PANIC, "MCIP not set in MCA handler",
-               MCGMASK(MCG_STATUS_MCIP, 0)
+               EXCP, MCGMASK(MCG_STATUS_MCIP, 0)
                ),
        /* Neither return not error IP -- no chance to recover -> PANIC */
        MCESEV(
                PANIC, "Neither restart nor error IP",
-               MCGMASK(MCG_STATUS_RIPV|MCG_STATUS_EIPV, 0)
+               EXCP, MCGMASK(MCG_STATUS_RIPV|MCG_STATUS_EIPV, 0)
                ),
        MCESEV(
                PANIC, "In kernel and no restart IP",
-               KERNEL, MCGMASK(MCG_STATUS_RIPV, 0)
+               EXCP, KERNEL, MCGMASK(MCG_STATUS_RIPV, 0)
+               ),
+       MCESEV(
+               DEFERRED, "Deferred error",
+               NOSER, MASK(MCI_STATUS_UC|MCI_STATUS_DEFERRED|MCI_STATUS_POISON, MCI_STATUS_DEFERRED)
                ),
        MCESEV(
                KEEP, "Corrected error",
@@ -89,7 +97,7 @@ static struct severity {
 
        /* ignore OVER for UCNA */
        MCESEV(
-               KEEP, "Uncorrected no action required",
+               UCNA, "Uncorrected no action required",
                SER, MASK(MCI_UC_SAR, MCI_STATUS_UC)
                ),
        MCESEV(
@@ -178,8 +186,9 @@ static int error_context(struct mce *m)
        return ((m->cs & 3) == 3) ? IN_USER : IN_KERNEL;
 }
 
-int mce_severity(struct mce *m, int tolerant, char **msg)
+int mce_severity(struct mce *m, int tolerant, char **msg, bool is_excp)
 {
+       enum exception excp = (is_excp ? EXCP_CONTEXT : NO_EXCP);
        enum context ctx = error_context(m);
        struct severity *s;
 
@@ -194,6 +203,8 @@ int mce_severity(struct mce *m, int tolerant, char **msg)
                        continue;
                if (s->context && ctx != s->context)
                        continue;
+               if (s->excp && excp != s->excp)
+                       continue;
                if (msg)
                        *msg = s->msg;
                s->covered = 1;
index 61a9668cebfde8d0ca22ce7dd5bde07f99a2e65f..453e9bf90968fdf586d1627c4d2af537d307b612 100644 (file)
@@ -668,7 +668,8 @@ static int mce_no_way_out(struct mce *m, char **msg, unsigned long *validp,
                        if (quirk_no_way_out)
                                quirk_no_way_out(i, m, regs);
                }
-               if (mce_severity(m, mca_cfg.tolerant, msg) >= MCE_PANIC_SEVERITY)
+               if (mce_severity(m, mca_cfg.tolerant, msg, true) >=
+                   MCE_PANIC_SEVERITY)
                        ret = 1;
        }
        return ret;
@@ -754,7 +755,7 @@ static void mce_reign(void)
        for_each_possible_cpu(cpu) {
                int severity = mce_severity(&per_cpu(mces_seen, cpu),
                                            mca_cfg.tolerant,
-                                           &nmsg);
+                                           &nmsg, true);
                if (severity > global_worst) {
                        msg = nmsg;
                        global_worst = severity;
@@ -1095,13 +1096,14 @@ void do_machine_check(struct pt_regs *regs, long error_code)
                 */
                add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE);
 
-               severity = mce_severity(&m, cfg->tolerant, NULL);
+               severity = mce_severity(&m, cfg->tolerant, NULL, true);
 
                /*
-                * When machine check was for corrected handler don't touch,
-                * unless we're panicing.
+                * When machine check was for corrected/deferred handler don't
+                * touch, unless we're panicing.
                 */
-               if (severity == MCE_KEEP_SEVERITY && !no_way_out)
+               if ((severity == MCE_KEEP_SEVERITY ||
+                    severity == MCE_UCNA_SEVERITY) && !no_way_out)
                        continue;
                __set_bit(i, toclear);
                if (severity == MCE_NO_SEVERITY) {
index 51b7e3a36e3729e0b322ea9d4dc24f0cde0b658b..c2359a1ea6b300443f750624fd4cb6beb295d05c 100644 (file)
@@ -32,9 +32,6 @@
 #define R4(x)                          (((x) >> 4) & 0xf)
 #define R4_MSG(x)                      ((R4(x) < 9) ?  rrrr_msgs[R4(x)] : "Wrong R4!")
 
-#define MCI_STATUS_DEFERRED            BIT_64(44)
-#define MCI_STATUS_POISON              BIT_64(43)
-
 extern const char * const pp_msgs[];
 
 enum tt_ids {