[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 12/19] x86/mce: handle LMCE locally



LMCE is sent to only one CPU thread, so MCE handler, barriers and
softirq handler should go without waiting for other CPUs, when
handling LMCE. Note LMCE is still broadcast to all vcpus as regular
MCE on Intel CPU right now.

Signed-off-by: Haozhong Zhang <haozhong.zhang@xxxxxxxxx>
---
Cc: Christoph Egger <chegger@xxxxxxxxx>
Cc: Liu Jinsong <jinsong.liu@xxxxxxxxxxxxxxx>
Cc: Jan Beulich <jbeulich@xxxxxxxx>
Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
---
 xen/arch/x86/cpu/mcheck/barrier.c  |  4 ++--
 xen/arch/x86/cpu/mcheck/mcaction.c |  4 +++-
 xen/arch/x86/cpu/mcheck/mce.c      | 25 ++++++++++++++++++++++---
 xen/arch/x86/cpu/mcheck/mce.h      |  3 +++
 xen/arch/x86/cpu/mcheck/x86_mca.h  |  4 +++-
 5 files changed, 33 insertions(+), 7 deletions(-)

diff --git a/xen/arch/x86/cpu/mcheck/barrier.c 
b/xen/arch/x86/cpu/mcheck/barrier.c
index 5dce1fb..869fd20 100644
--- a/xen/arch/x86/cpu/mcheck/barrier.c
+++ b/xen/arch/x86/cpu/mcheck/barrier.c
@@ -20,7 +20,7 @@ void mce_barrier_enter(struct mce_softirq_barrier *bar)
 {
     int gen;
 
-    if (!mce_broadcast)
+    if ( !mce_broadcast || __get_cpu_var(lmce_in_process) )
         return;
     atomic_inc(&bar->ingen);
     gen = atomic_read(&bar->outgen);
@@ -38,7 +38,7 @@ void mce_barrier_exit(struct mce_softirq_barrier *bar)
 {
     int gen;
 
-    if ( !mce_broadcast )
+    if ( !mce_broadcast || __get_cpu_var(lmce_in_process) )
         return;
     atomic_inc(&bar->outgen);
     gen = atomic_read(&bar->ingen);
diff --git a/xen/arch/x86/cpu/mcheck/mcaction.c 
b/xen/arch/x86/cpu/mcheck/mcaction.c
index 8b2b834..90c68ff 100644
--- a/xen/arch/x86/cpu/mcheck/mcaction.c
+++ b/xen/arch/x86/cpu/mcheck/mcaction.c
@@ -95,7 +95,9 @@ mc_memerr_dhandler(struct mca_binfo *binfo,
 
                 bank->mc_addr = gfn << PAGE_SHIFT |
                   (bank->mc_addr & (PAGE_SIZE -1 ));
-                if ( fill_vmsr_data(bank, d, global->mc_gstatus,
+                /* TODO: support injecting LMCE */
+                if ( fill_vmsr_data(bank, d,
+                                    global->mc_gstatus & ~MCG_STATUS_LMCE,
                                     vmce_vcpuid == VMCE_INJECT_BROADCAST) == 
-1 )
                 {
                     mce_printk(MCE_QUIET, "Fill vMCE# data for DOM%d "
diff --git a/xen/arch/x86/cpu/mcheck/mce.c b/xen/arch/x86/cpu/mcheck/mce.c
index 95a9da3..2d69222 100644
--- a/xen/arch/x86/cpu/mcheck/mce.c
+++ b/xen/arch/x86/cpu/mcheck/mce.c
@@ -42,6 +42,17 @@ DEFINE_PER_CPU_READ_MOSTLY(struct mca_banks *, 
poll_bankmask);
 DEFINE_PER_CPU_READ_MOSTLY(struct mca_banks *, no_cmci_banks);
 DEFINE_PER_CPU_READ_MOSTLY(struct mca_banks *, mce_clear_banks);
 
+/*
+ * Flag to indicate whether the current MCE on this CPU is a LMCE.
+ *
+ * The MCE handler should set/clear this flag before entering any MCE
+ * barriers and raising MCE softirq. MCE barriers rely on this flag to
+ * decide whether they need to wait for other CPUs. MCE softirq handler
+ * relies on this flag to decide whether it needs to handle pending
+ * MCEs on other CPUs.
+ */
+DEFINE_PER_CPU(bool, lmce_in_process);
+
 static void intpose_init(void);
 static void mcinfo_clear(struct mc_info *);
 struct mca_banks *mca_allbanks;
@@ -399,6 +410,7 @@ mcheck_mca_logout(enum mca_source who, struct mca_banks 
*bankmask,
         sp->errcnt = errcnt;
         sp->ripv = (gstatus & MCG_STATUS_RIPV) != 0;
         sp->eipv = (gstatus & MCG_STATUS_EIPV) != 0;
+        sp->lmce = (gstatus & MCG_STATUS_LMCE) != 0;
         sp->uc = uc;
         sp->pcc = pcc;
         sp->recoverable = recover;
@@ -462,6 +474,7 @@ void mcheck_cmn_handler(const struct cpu_user_regs *regs)
     uint64_t gstatus;
     mctelem_cookie_t mctc = NULL;
     struct mca_summary bs;
+    bool *lmce_in_process = &__get_cpu_var(lmce_in_process);
 
     mce_spin_lock(&mce_logout_lock);
 
@@ -505,6 +518,8 @@ void mcheck_cmn_handler(const struct cpu_user_regs *regs)
     }
     mce_spin_unlock(&mce_logout_lock);
 
+    *lmce_in_process = bs.lmce;
+
     mce_barrier_enter(&mce_trap_bar);
     if ( mctc != NULL && mce_urgent_action(regs, mctc))
         cpumask_set_cpu(smp_processor_id(), &mce_fatal_cpus);
@@ -1709,6 +1724,7 @@ static void mce_softirq(void)
 {
     int cpu = smp_processor_id();
     unsigned int workcpu;
+    bool lmce = per_cpu(lmce_in_process, cpu);
 
     mce_printk(MCE_VERBOSE, "CPU%d enter softirq\n", cpu);
 
@@ -1738,9 +1754,12 @@ static void mce_softirq(void)
         /* Step1: Fill DOM0 LOG buffer, vMCE injection buffer and
          * vMCE MSRs virtualization buffer
          */
-        for_each_online_cpu(workcpu) {
-            mctelem_process_deferred(workcpu, mce_delayed_action);
-        }
+        if ( lmce )
+            mctelem_process_deferred(cpu, mce_delayed_action);
+        else
+            for_each_online_cpu(workcpu) {
+                mctelem_process_deferred(workcpu, mce_delayed_action);
+            }
 
         /* Step2: Send Log to DOM0 through vIRQ */
         if (dom0_vmce_enabled()) {
diff --git a/xen/arch/x86/cpu/mcheck/mce.h b/xen/arch/x86/cpu/mcheck/mce.h
index 2f4e7a4..2c033af 100644
--- a/xen/arch/x86/cpu/mcheck/mce.h
+++ b/xen/arch/x86/cpu/mcheck/mce.h
@@ -110,12 +110,15 @@ struct mca_summary {
     bool_t      uc;     /* UC flag */
     bool_t      pcc;    /* PCC flag */
     bool_t      recoverable; /* software error recoverable flag */
+    bool_t      lmce;   /* LMCE flag (Intel specific) */
 };
 
 DECLARE_PER_CPU(struct mca_banks *, poll_bankmask);
 DECLARE_PER_CPU(struct mca_banks *, no_cmci_banks);
 DECLARE_PER_CPU(struct mca_banks *, mce_clear_banks);
 
+DECLARE_PER_CPU(bool, lmce_in_process);
+
 extern bool_t cmci_support;
 extern bool_t is_mc_panic;
 extern bool_t mce_broadcast;
diff --git a/xen/arch/x86/cpu/mcheck/x86_mca.h 
b/xen/arch/x86/cpu/mcheck/x86_mca.h
index e25d619..322b7d4 100644
--- a/xen/arch/x86/cpu/mcheck/x86_mca.h
+++ b/xen/arch/x86/cpu/mcheck/x86_mca.h
@@ -42,7 +42,9 @@
 #define MCG_STATUS_RIPV         0x0000000000000001ULL
 #define MCG_STATUS_EIPV         0x0000000000000002ULL
 #define MCG_STATUS_MCIP         0x0000000000000004ULL
-/* Bits 3-63 are reserved */
+#define MCG_STATUS_LMCE         0x0000000000000008ULL  /* Intel specific */
+/* Bits 3-63 are reserved on CPU not supporting LMCE */
+/* Bits 4-63 are reserved on CPU supporting LMCE */
 
 /* Bitfield of MSR_K8_MCi_STATUS registers */
 /* MCA error code */
-- 
2.10.1


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.