mce: Clean-up mcheck_init handler
authorKeir Fraser <keir.fraser@citrix.com>
Wed, 9 Jun 2010 06:42:19 +0000 (07:42 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Wed, 9 Jun 2010 06:42:19 +0000 (07:42 +0100)
Firstly and most importantly, the maxium MCA banks are hard-coded as
MAX_NR_BANKS, which is 30. This is not architecture correct. This
patch removes this definition, replacig the cpu_banks_t with
mca_banks, and provide some basic function, like
set/clear/test/alloc/free for mcabanks_t.

Secondly, remove the broadcast_check code to intel specific, since
only Intel platform support broadcast now.

Thirdly, the X86_FEATURE_MCA check and CR4_MCE enable is done in every
vendor-specifc callback, that's redundant, move it to
mcheck_init. Also, we should enable CR4_MCE only in the end of the
mcheck_init, to close the small window between CR4_enable and the mca
setup.

And we also move vmce specific code to vmce.c as vmce_init, to make
code clean.

Signed-off-by: Jiang, Yunhong <yunhong.jiang@intel.com>
Acked-By: Christoph Egger <Christoph.Egger@amd.com>
xen/arch/x86/cpu/mcheck/amd_k8.c
xen/arch/x86/cpu/mcheck/k7.c
xen/arch/x86/cpu/mcheck/mce.c
xen/arch/x86/cpu/mcheck/mce.h
xen/arch/x86/cpu/mcheck/mce_intel.c
xen/arch/x86/cpu/mcheck/non-fatal.c
xen/arch/x86/cpu/mcheck/vmce.c
xen/arch/x86/cpu/mcheck/x86_mca.h
xen/include/asm-x86/mce.h

index 13be7cbb288f20dc13a4213a4a9c61e3a210e6b0..9d5e6913b7e3d85729c79a67578b69e8654c8343 100644 (file)
@@ -81,13 +81,8 @@ enum mcheck_type amd_k8_mcheck_init(struct cpuinfo_x86 *c)
        uint32_t i;
        enum mcequirk_amd_flags quirkflag;
 
-       /* Check for PPro style MCA; our caller has confirmed MCE support. */
-       if (!cpu_has(c, X86_FEATURE_MCA))
-               return mcheck_none;
-
        quirkflag = mcequirk_lookup_amd_quirkdata(c);
 
-       mce_cap_init();
        x86_mce_vector_register(k8_machine_check);
 
        for (i = 0; i < nr_mce_banks; i++) {
@@ -101,7 +96,5 @@ enum mcheck_type amd_k8_mcheck_init(struct cpuinfo_x86 *c)
                }
        }
 
-       set_in_cr4(X86_CR4_MCE);
-
        return mcheck_amd_k8;
 }
index be73261b821fa67e5463ab52e27ba0b930c0a7fb..343b38bdd85813908bf052a46ca5f28b50dacbbc 100644 (file)
@@ -70,20 +70,10 @@ static fastcall void k7_machine_check(struct cpu_user_regs * regs, long error_co
 /* AMD K7 machine check */
 enum mcheck_type amd_k7_mcheck_init(struct cpuinfo_x86 *c)
 {
-       u32 l, h;
        int i;
 
-       /* Check for PPro style MCA; our caller has confirmed MCE support. */
-       if (!cpu_has(c, X86_FEATURE_MCA))
-               return mcheck_none;
-
        x86_mce_vector_register(k7_machine_check);
 
-       rdmsr (MSR_IA32_MCG_CAP, l, h);
-       if (l & (1<<8)) /* Control register present ? */
-               wrmsr (MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
-       nr_mce_banks = l & 0xff;
-
        /* Clear status for MC index 0 separately, we don't touch CTL,
         * as some Athlons cause spurious MCEs when its enabled. */
        wrmsr (MSR_IA32_MC0_STATUS, 0x0, 0x0);
@@ -92,7 +82,5 @@ enum mcheck_type amd_k7_mcheck_init(struct cpuinfo_x86 *c)
                wrmsr (MSR_IA32_MC0_STATUS+4*i, 0x0, 0x0);
        }
 
-       set_in_cr4 (X86_CR4_MCE);
-
        return mcheck_amd_k7;
 }
index b08299892587a0c94f86a9e21c775d1bffeb0ca7..14e97f7887e0375fcfac98cd929b9268260f6b81 100644 (file)
 
 int mce_disabled;
 invbool_param("mce", mce_disabled);
-static int mce_force_broadcast;
-boolean_param("mce_fb", mce_force_broadcast);
 int is_mc_panic;
 unsigned int nr_mce_banks;
 
 int mce_broadcast = 0;
-uint64_t g_mcg_cap;
-
-/* Real value in physical CTL MSR */
-uint64_t h_mcg_ctl = 0UL;
-uint64_t *h_mci_ctrl;
 int firstbank;
 
 static void intpose_init(void);
 static void mcinfo_clear(struct mc_info *);
+struct mca_banks *mca_allbanks;
 
 #define        SEG_PL(segsel)                  ((segsel) & 0x3)
 #define _MC_MSRINJ_F_REQ_HWCR_WREN     (1 << 16)
@@ -55,8 +49,6 @@ static int x86_mcerr(const char *msg, int err)
 #define x86_mcerr(msg, err) (err)
 #endif
 
-cpu_banks_t mca_allbanks;
-
 int mce_verbosity;
 static void __init mce_set_verbosity(char *str)
 {
@@ -113,6 +105,36 @@ void mce_recoverable_register(mce_recoverable_t cbfunc)
     mc_recoverable_scan = cbfunc;
 }
 
+struct mca_banks *mcabanks_alloc(void)
+{
+    struct mca_banks *mb;
+
+    mb = xmalloc(struct mca_banks);
+    if (!mb)
+        return NULL;
+
+    mb->bank_map = xmalloc_array(unsigned long,
+            BITS_TO_LONGS(nr_mce_banks));
+    if (!mb->bank_map)
+    {
+        xfree(mb);
+        return NULL;
+    }
+
+    mb->num = nr_mce_banks;
+    memset(mb->bank_map, 0, sizeof(long) * BITS_TO_LONGS(nr_mce_banks));
+
+    return mb;
+}
+
+void mcabanks_free(struct mca_banks *banks)
+{
+    if (banks == NULL)
+        return;
+    if (banks->bank_map)
+        xfree(banks->bank_map);
+    xfree(banks);
+}
 /* Judging whether to Clear Machine Check error bank callback handler
  * According to Intel latest MCA OS Recovery Writer's Guide, 
  * whether the error MCA bank needs to be cleared is decided by the mca_source
@@ -218,8 +240,8 @@ static int mca_init_global(uint32_t flags, struct mcinfo_global *mig)
  * For Intel latest CPU, whether to clear the error bank status needs to
  * be judged by the callback function defined above.
  */
-mctelem_cookie_t mcheck_mca_logout(enum mca_source who, cpu_banks_t bankmask,
-    struct mca_summary *sp, cpu_banks_t* clear_bank)
+mctelem_cookie_t mcheck_mca_logout(enum mca_source who, struct mca_banks *bankmask,
+    struct mca_summary *sp, struct mca_banks* clear_bank)
 {
        uint64_t gstatus, status;
        struct mcinfo_global *mig = NULL;       /* on stack */
@@ -262,7 +284,7 @@ mctelem_cookie_t mcheck_mca_logout(enum mca_source who, cpu_banks_t bankmask,
                struct mcinfo_bank *mib;                /* on stack */
 
                /* Skip bank if corresponding bit in bankmask is clear */
-               if (!test_bit(i, bankmask))
+               if (!mcabanks_test(i, bankmask))
                        continue;
 
                mca_rdmsrl(MSR_IA32_MC0_STATUS + i * 4, status);
@@ -325,7 +347,7 @@ mctelem_cookie_t mcheck_mca_logout(enum mca_source who, cpu_banks_t bankmask,
                        /* Clear status */
                        mca_wrmsrl(MSR_IA32_MC0_STATUS + 4 * i, 0x0ULL);
                else if ( who == MCA_MCE_SCAN && need_clear)
-                       set_bit(i, clear_bank);
+                       mcabanks_set(i, clear_bank);
 
                wmb();
        }
@@ -359,7 +381,7 @@ mctelem_cookie_t mcheck_mca_logout(enum mca_source who, cpu_banks_t bankmask,
 
 /* Shared #MC handler. */
 void mcheck_cmn_handler(struct cpu_user_regs *regs, long error_code,
-    cpu_banks_t bankmask)
+    struct mca_banks *bankmask)
 {
        int xen_state_lost, dom0_state_lost, domU_state_lost;
        struct vcpu *v = current;
@@ -575,13 +597,13 @@ cmn_handler_done:
        }
 }
 
-void mcheck_mca_clearbanks(cpu_banks_t bankmask)
+void mcheck_mca_clearbanks(struct mca_banks *bankmask)
 {
        int i;
        uint64_t status;
 
        for (i = 0; i < 32 && i < nr_mce_banks; i++) {
-               if (!test_bit(i, bankmask))
+               if (!mcabanks_test(i, bankmask))
                        continue;
                mca_rdmsrl(MSR_IA32_MC0_STATUS + i * 4, status);
                if (!(status & MCi_STATUS_VAL))
@@ -620,21 +642,6 @@ int mce_available(struct cpuinfo_x86 *c)
        return cpu_has(c, X86_FEATURE_MCE) && cpu_has(c, X86_FEATURE_MCA);
 }
 
-static int mce_is_broadcast(struct cpuinfo_x86 *c)
-{
-    if (mce_force_broadcast)
-        return 1;
-
-    /* According to Intel SDM Dec, 2009, 15.10.4.1, For processors with
-     * DisplayFamily_DisplayModel encoding of 06H_EH and above,
-     * a MCA signal is broadcast to all logical processors in the system
-     */
-    if (c->x86_vendor == X86_VENDOR_INTEL && c->x86 == 6 &&
-        c->x86_model >= 0xe)
-            return 1;
-    return 0;
-}
-
 /*
  * Check if bank 0 is usable for MCE. It isn't for AMD K7,
  * and Intel P6 family before model 0x1a.
@@ -652,77 +659,9 @@ int mce_firstbank(struct cpuinfo_x86 *c)
        return 0;
 }
 
-/* This has to be run for each processor */
-void mcheck_init(struct cpuinfo_x86 *c)
+int show_mca_info(int inited, struct cpuinfo_x86 *c)
 {
-       int i, broadcast;
-       enum mcheck_type inited = mcheck_none;
        static enum mcheck_type g_type = mcheck_unset;
-    static int broadcast_check;
-
-       if (mce_disabled == 1) {
-               dprintk(XENLOG_INFO, "MCE support disabled by bootparam\n");
-               return;
-       }
-
-    broadcast = mce_is_broadcast(c);
-    if (broadcast_check && (broadcast != mce_broadcast) )
-            dprintk(XENLOG_INFO,
-                "CPUs have mixed broadcast support"
-                "may cause undetermined result!!!\n");
-
-    broadcast_check = 1;
-    if (broadcast)
-        mce_broadcast = broadcast;
-
-       for (i = 0; i < MAX_NR_BANKS; i++)
-               set_bit(i,mca_allbanks);
-
-       /* Enforce at least MCE support in CPUID information.  Individual
-        * families may also need to enforce a check for MCA support. */
-       if (!cpu_has(c, X86_FEATURE_MCE)) {
-               printk(XENLOG_INFO "CPU%i: No machine check support available\n",
-                       smp_processor_id());
-               return;
-       }
-
-       intpose_init();
-       mctelem_init(sizeof (struct mc_info));
-
-       switch (c->x86_vendor) {
-       case X86_VENDOR_AMD:
-               inited = amd_mcheck_init(c);
-               break;
-
-       case X86_VENDOR_INTEL:
-               switch (c->x86) {
-               case 6:
-               case 15:
-                       inited = intel_mcheck_init(c);
-                       break;
-               }
-               break;
-
-       default:
-               break;
-       }
-
-    if ( !h_mci_ctrl )
-    {
-        h_mci_ctrl = xmalloc_array(uint64_t, nr_mce_banks);
-        if (!h_mci_ctrl)
-        {
-            dprintk(XENLOG_INFO, "Failed to alloc h_mci_ctrl\n");
-            return;
-        }
-        /* Don't care banks before firstbank */
-        memset(h_mci_ctrl, 0xff, sizeof(h_mci_ctrl));
-        for (i = firstbank; i < nr_mce_banks; i++)
-            rdmsrl(MSR_IA32_MC0_CTL + 4*i, h_mci_ctrl[i]);
-    }
-    if (g_mcg_cap & MCG_CTL_P)
-        rdmsrl(MSR_IA32_MCG_CTL, h_mcg_ctl);
-    set_poll_bankmask(c);
 
        if (inited != g_type) {
                char prefix[20];
@@ -751,32 +690,130 @@ void mcheck_init(struct cpuinfo_x86 *c)
                        printk("%sNo machine check initialization\n", prefix);
                        break;
                }
-
-               g_type = inited;
+        g_type = inited;
        }
+
+    return 0;
+}
+
+int set_poll_bankmask(struct cpuinfo_x86 *c)
+{
+    int cpu = smp_processor_id();
+    struct mca_banks *mb;
+
+    mb = mcabanks_alloc();
+    if (!mb)
+        return -ENOMEM;
+
+    if (cmci_support && !mce_disabled) {
+        mb->num = per_cpu(no_cmci_banks, cpu)->num;
+        bitmap_copy(mb->bank_map, per_cpu(no_cmci_banks, cpu)->bank_map,
+            nr_mce_banks);
+    }
+    else {
+        bitmap_copy(mb->bank_map, mca_allbanks->bank_map, nr_mce_banks);
+        if (mce_firstbank(c))
+            mcabanks_clear(0, mb);
+    }
+    per_cpu(poll_bankmask, cpu) = mb;
+
+    return 0;
 }
 
-u64 mce_cap_init(void)
+/* The perbank ctl/status init is platform specific because of AMD's quirk */
+int mca_cap_init(void)
 {
     u32 l, h;
     u64 value;
 
     rdmsr(MSR_IA32_MCG_CAP, l, h);
     value = ((u64)h << 32) | l;
-    /* For Guest vMCE usage */
-    g_mcg_cap = value & ~MCG_CMCI_P;
 
     if (l & MCG_CTL_P) /* Control register present ? */
         wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
 
+    if (nr_mce_banks &&  (l & MCG_CAP_COUNT) != nr_mce_banks)
+    {
+        dprintk(XENLOG_WARNING, "Different bank number on cpu %x\n",
+                smp_processor_id());
+        return -ENODEV;
+    }
     nr_mce_banks = l & MCG_CAP_COUNT;
-    if ( nr_mce_banks > MAX_NR_BANKS )
+
+    /* mcabanks_alloc depends on nr_mcebanks */
+    if (!mca_allbanks)
     {
-        printk(KERN_WARNING "MCE: exceed max mce banks\n");
-        g_mcg_cap = (g_mcg_cap & ~MCG_CAP_COUNT) | MAX_NR_BANKS;
+        int i;
+
+        mca_allbanks = mcabanks_alloc();
+        for ( i = 0; i < nr_mce_banks; i++)
+            mcabanks_set(i, mca_allbanks);
     }
 
-    return value;
+    return mca_allbanks ? 0:-ENOMEM;
+}
+
+/* This has to be run for each processor */
+void mcheck_init(struct cpuinfo_x86 *c)
+{
+       enum mcheck_type inited = mcheck_none;
+
+       if (mce_disabled == 1) {
+               dprintk(XENLOG_INFO, "MCE support disabled by bootparam\n");
+               return;
+       }
+
+       if (!mce_available(c))
+       {
+               printk(XENLOG_INFO "CPU%i: No machine check support available\n",
+                 smp_processor_id());
+               return;
+       }
+
+       /*Hardware Enable */
+       if (mca_cap_init())
+               return;
+
+       switch (c->x86_vendor) {
+       case X86_VENDOR_AMD:
+               inited = amd_mcheck_init(c);
+               break;
+
+       case X86_VENDOR_INTEL:
+               switch (c->x86) {
+               case 6:
+               case 15:
+                       inited = intel_mcheck_init(c);
+                       break;
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       show_mca_info(inited, c);
+       if (inited == mcheck_none || inited == mcheck_unset)
+               goto out;
+
+       intpose_init();
+
+       mctelem_init(sizeof(struct mc_info));
+
+       vmce_init(c);
+
+    /* Turn on MCE now */
+       set_in_cr4(X86_CR4_MCE);
+
+       set_poll_bankmask(c);
+
+       return;
+out:
+       if (smp_processor_id() == 0)
+       {
+               mcabanks_free(mca_allbanks);
+               mca_allbanks = NULL;
+       }
 }
 
 static void mcinfo_clear(struct mc_info *mi)
@@ -1047,23 +1084,6 @@ void intpose_inval(unsigned int cpu_nr, uint64_t msr)
     (r) <= MSR_IA32_MC0_MISC + (nr_mce_banks - 1) * 4 && \
     ((r) - MSR_IA32_MC0_CTL) % 4 != 0) /* excludes MCi_CTL */
 
-int mca_ctl_conflict(struct mcinfo_bank *bank, struct domain *d)
-{
-    int bank_nr;
-
-    if ( !bank || !d || !h_mci_ctrl )
-        return 1;
-
-    /* Will MCE happen in host if If host mcg_ctl is 0? */
-    if ( ~d->arch.vmca_msrs->mcg_ctl & h_mcg_ctl )
-        return 1;
-
-    bank_nr = bank->mc_bank;
-    if (~d->arch.vmca_msrs->mci_ctl[bank_nr] & h_mci_ctrl[bank_nr] )
-        return 1;
-    return 0;
-}
-
 static int x86_mc_msrinject_verify(struct xen_mc_msrinject *mci)
 {
        struct cpuinfo_x86 *c;
@@ -1435,19 +1455,7 @@ long do_mca(XEN_GUEST_HANDLE(xen_mc_t) u_xen_mc)
 
        return ret;
 }
-void set_poll_bankmask(struct cpuinfo_x86 *c)
-{
 
-    if (cmci_support && !mce_disabled) {
-        memcpy(&(__get_cpu_var(poll_bankmask)),
-                &(__get_cpu_var(no_cmci_banks)), sizeof(cpu_banks_t));
-    }
-    else {
-        memcpy(&(get_cpu_var(poll_bankmask)), &mca_allbanks, sizeof(cpu_banks_t));
-        if (mce_firstbank(c))
-            clear_bit(0, get_cpu_var(poll_bankmask));
-    }
-}
 void mc_panic(char *s)
 {
     is_mc_panic = 1;
index 4c557356120e14284fd3ae0738ea2830f539f472..8e17bc0a5b33cc8e3e766c7d3bdaf85cdac84d84 100644 (file)
@@ -72,7 +72,7 @@ extern void x86_mce_vector_register(x86_mce_vector_t);
 
 /* Common generic MCE handler that implementations may nominate
  * via x86_mce_vector_register. */
-extern void mcheck_cmn_handler(struct cpu_user_regs *, long, cpu_banks_t);
+extern void mcheck_cmn_handler(struct cpu_user_regs *, long, struct mca_banks *);
 
 /* Register a handler for judging whether mce is recoverable. */
 typedef int (*mce_recoverable_t)(u64 status);
@@ -120,18 +120,17 @@ struct mca_summary {
        uint32_t        recoverable; 
 };
 
-extern cpu_banks_t mca_allbanks;
-void set_poll_bankmask(struct cpuinfo_x86 *c);
-DECLARE_PER_CPU(cpu_banks_t, poll_bankmask);
-DECLARE_PER_CPU(cpu_banks_t, no_cmci_banks);
+DECLARE_PER_CPU(struct mca_banks *, poll_bankmask);
+DECLARE_PER_CPU(struct mca_banks *, no_cmci_banks);
+
 extern int cmci_support;
 extern int ser_support;
 extern int is_mc_panic;
 extern int mce_broadcast;
-extern void mcheck_mca_clearbanks(cpu_banks_t);
+extern void mcheck_mca_clearbanks(struct mca_banks *);
 
-extern mctelem_cookie_t mcheck_mca_logout(enum mca_source, cpu_banks_t,
-    struct mca_summary *, cpu_banks_t*);
+extern mctelem_cookie_t mcheck_mca_logout(enum mca_source, struct mca_banks *,
+    struct mca_summary *, struct mca_banks *);
 
 /* Register a callback to be made during bank telemetry logout.
  * This callback is only available to those machine check handlers
@@ -164,10 +163,7 @@ int fill_vmsr_data(struct mcinfo_bank *mc_bank, struct domain *d,
 int inject_vmce(struct domain *d);
 int vmce_domain_inject(struct mcinfo_bank *bank, struct domain *d, struct mcinfo_global *global);
 
-extern uint64_t g_mcg_cap;
-/* Real value in physical CTL MSR */
-extern uint64_t h_mcg_ctl;
-extern uint64_t *h_mci_ctrl;
+extern int vmce_init(struct cpuinfo_x86 *c);
 
 extern unsigned int nr_mce_banks;
 
index fbd4f41c58a5f5b48876e0a77401b57cbb680fdf..9dfd6f14f0638be82389b39c4713b860c33f595e 100644 (file)
 #include "mce.h"
 #include "x86_mca.h"
 
-DEFINE_PER_CPU(cpu_banks_t, mce_banks_owned);
-DEFINE_PER_CPU(cpu_banks_t, no_cmci_banks);
+DEFINE_PER_CPU(struct mca_banks *, mce_banks_owned);
+DEFINE_PER_CPU(struct mca_banks *, no_cmci_banks);
+DEFINE_PER_CPU(struct mca_banks *, mce_clear_banks);
 int cmci_support = 0;
 int ser_support = 0;
+static int mce_force_broadcast;
+boolean_param("mce_fb", mce_force_broadcast);
 
 static int nr_intel_ext_msrs = 0;
 
@@ -528,12 +531,14 @@ static void intel_machine_check(struct cpu_user_regs * regs, long error_code)
     uint64_t gstatus;
     mctelem_cookie_t mctc = NULL;
     struct mca_summary bs;
-    cpu_banks_t clear_bank;
+    struct mca_banks *clear_bank;
 
     mce_spin_lock(&mce_logout_lock);
 
-    memset( &clear_bank, 0x0, sizeof(cpu_banks_t));
-    mctc = mcheck_mca_logout(MCA_MCE_SCAN, mca_allbanks, &bs, &clear_bank);
+    clear_bank = __get_cpu_var(mce_clear_banks);
+    memset( clear_bank->bank_map, 0x0,
+        sizeof(long) * BITS_TO_LONGS(clear_bank->num));
+    mctc = mcheck_mca_logout(MCA_MCE_SCAN, mca_allbanks, &bs, clear_bank);
 
     if (bs.errcnt) {
         /* dump MCE error */
@@ -699,7 +704,7 @@ static int do_cmci_discover(int i)
     rdmsrl(msr, val);
     /* Some other CPU already owns this bank. */
     if (val & CMCI_EN) {
-        clear_bit(i, __get_cpu_var(mce_banks_owned));
+        mcabanks_clear(i, __get_cpu_var(mce_banks_owned));
         goto out;
     }
 
@@ -709,12 +714,12 @@ static int do_cmci_discover(int i)
 
     if (!(val & CMCI_EN)) {
         /* This bank does not support CMCI. Polling timer has to handle it. */
-        set_bit(i, __get_cpu_var(no_cmci_banks));
+        mcabanks_set(i, __get_cpu_var(no_cmci_banks));
         return 0;
     }
-    set_bit(i, __get_cpu_var(mce_banks_owned));
+    mcabanks_set(i, __get_cpu_var(mce_banks_owned));
 out:
-    clear_bit(i, __get_cpu_var(no_cmci_banks));
+    mcabanks_clear(i, __get_cpu_var(no_cmci_banks));
     return 1;
 }
 
@@ -730,7 +735,7 @@ static void cmci_discover(void)
     spin_lock_irqsave(&cmci_discover_lock, flags);
 
     for (i = 0; i < nr_mce_banks; i++)
-        if (!test_bit(i, __get_cpu_var(mce_banks_owned)))
+        if (!mcabanks_test(i, __get_cpu_var(mce_banks_owned)))
             do_cmci_discover(i);
 
     spin_unlock_irqrestore(&cmci_discover_lock, flags);
@@ -757,8 +762,8 @@ static void cmci_discover(void)
 
     mce_printk(MCE_VERBOSE, "CMCI: CPU%d owner_map[%lx], no_cmci_map[%lx]\n",
            smp_processor_id(),
-           *((unsigned long *)__get_cpu_var(mce_banks_owned)),
-           *((unsigned long *)__get_cpu_var(no_cmci_banks)));
+           *((unsigned long *)__get_cpu_var(mce_banks_owned)->bank_map),
+           *((unsigned long *)__get_cpu_var(no_cmci_banks)->bank_map));
 }
 
 /*
@@ -804,12 +809,12 @@ static void clear_cmci(void)
     for (i = 0; i < nr_mce_banks; i++) {
         unsigned msr = MSR_IA32_MC0_CTL2 + i;
         u64 val;
-        if (!test_bit(i, __get_cpu_var(mce_banks_owned)))
+        if (!mcabanks_test(i, __get_cpu_var(mce_banks_owned)))
             continue;
         rdmsrl(msr, val);
         if (val & (CMCI_EN|CMCI_THRESHOLD_MASK))
             wrmsrl(msr, val & ~(CMCI_EN|CMCI_THRESHOLD_MASK));
-        clear_bit(i, __get_cpu_var(mce_banks_owned));
+        mcabanks_clear(i, __get_cpu_var(mce_banks_owned));
     }
 }
 
@@ -878,16 +883,44 @@ fastcall void smp_cmci_interrupt(struct cpu_user_regs *regs)
 
 void mce_intel_feature_init(struct cpuinfo_x86 *c)
 {
-
 #ifdef CONFIG_X86_MCE_THERMAL
     intel_init_thermal(c);
 #endif
     intel_init_cmci(c);
 }
 
-static void _mce_cap_init(struct cpuinfo_x86 *c)
+static int mce_is_broadcast(struct cpuinfo_x86 *c)
+{
+    if (mce_force_broadcast)
+        return 1;
+
+    /* According to Intel SDM Dec, 2009, 15.10.4.1, For processors with
+     * DisplayFamily_DisplayModel encoding of 06H_EH and above,
+     * a MCA signal is broadcast to all logical processors in the system
+     */
+    if (c->x86_vendor == X86_VENDOR_INTEL && c->x86 == 6 &&
+        c->x86_model >= 0xe)
+            return 1;
+    return 0;
+}
+
+static void intel_mca_cap_init(struct cpuinfo_x86 *c)
 {
-    u32 l = mce_cap_init();
+    static int broadcast_check;
+    int broadcast;
+    u32 l, h;
+
+    broadcast = mce_is_broadcast(c);
+    if (broadcast_check && (broadcast != mce_broadcast) )
+            dprintk(XENLOG_INFO,
+                "CPUs have mixed broadcast support"
+                "may cause undetermined result!!!\n");
+
+    broadcast_check = 1;
+    if (broadcast)
+        mce_broadcast = broadcast;
+
+    rdmsr(MSR_IA32_MCG_CAP, l, h);
 
     if ((l & MCG_CMCI_P) && cpu_has_apic)
         cmci_support = 1;
@@ -912,8 +945,6 @@ static void mce_init(void)
     mctelem_cookie_t mctc;
     struct mca_summary bs;
 
-    clear_in_cr4(X86_CR4_MCE);
-
     mce_barrier_init(&mce_inside_bar);
     mce_barrier_init(&mce_severity_bar);
     mce_barrier_init(&mce_trap_bar);
@@ -930,8 +961,6 @@ static void mce_init(void)
         mctelem_commit(mctc);
     }
 
-    set_in_cr4(X86_CR4_MCE);
-
     for (i = firstbank; i < nr_mce_banks; i++)
     {
         /* Some banks are shared across cores, use MCi_CTRL to judge whether
@@ -949,10 +978,35 @@ static void mce_init(void)
         wrmsr (MSR_IA32_MC0_STATUS, 0x0, 0x0);
 }
 
+static int init_mca_banks(void)
+{
+    struct mca_banks *mb1, *mb2, * mb3;
+
+    mb1 = mcabanks_alloc();
+    mb2 = mcabanks_alloc();
+    mb3 = mcabanks_alloc();
+    if (!mb1 || !mb2 || !mb3)
+        goto out;
+
+    __get_cpu_var(mce_clear_banks) = mb1;
+    __get_cpu_var(no_cmci_banks) = mb2;
+    __get_cpu_var(mce_banks_owned) = mb3;
+
+    return 0;
+out:
+    mcabanks_free(mb1);
+    mcabanks_free(mb2);
+    mcabanks_free(mb3);
+    return -ENOMEM;
+}
+
 /* p4/p6 family have similar MCA initialization process */
 enum mcheck_type intel_mcheck_init(struct cpuinfo_x86 *c)
 {
-    _mce_cap_init(c);
+    if (init_mca_banks())
+        return mcheck_none;
+
+    intel_mca_cap_init(c);
 
     /* machine check is available */
     x86_mce_vector_register(intel_machine_check);
@@ -969,17 +1023,14 @@ enum mcheck_type intel_mcheck_init(struct cpuinfo_x86 *c)
 
 int intel_mce_wrmsr(uint32_t msr, uint64_t val)
 {
-    int ret = 1;
+    int ret = 0;
 
-    switch ( msr )
+    if (msr > MSR_IA32_MC0_CTL2 &&
+        msr < (MSR_IA32_MC0_CTL2 + nr_mce_banks - 1))
     {
-    case MSR_IA32_MC0_CTL2 ... MSR_IA32_MC0_CTL2 + MAX_NR_BANKS - 1:
         mce_printk(MCE_QUIET, "We have disabled CMCI capability, "
                  "Guest should not write this MSR!\n");
-        break;
-    default:
-        ret = 0;
-        break;
+         ret = 1;
     }
 
     return ret;
@@ -987,17 +1038,14 @@ int intel_mce_wrmsr(uint32_t msr, uint64_t val)
 
 int intel_mce_rdmsr(uint32_t msr, uint64_t *val)
 {
-    int ret = 1;
+    int ret = 0;
 
-    switch ( msr )
+    if (msr > MSR_IA32_MC0_CTL2 &&
+        msr < (MSR_IA32_MC0_CTL2 + nr_mce_banks - 1))
     {
-    case MSR_IA32_MC0_CTL2 ... MSR_IA32_MC0_CTL2 + MAX_NR_BANKS - 1:
         mce_printk(MCE_QUIET, "We have disabled CMCI capability, "
                  "Guest should not read this MSR!\n");
-        break;
-    default:
-        ret = 0;
-        break;
+        ret = 1;
     }
 
     return ret;
index 2ab2b5cbc25aa56bc25386aac6df480676246054..7448f479cba9b33fdaa135ff766aaa07010fc679 100644 (file)
@@ -22,7 +22,7 @@
 
 #include "mce.h"
 
-DEFINE_PER_CPU(cpu_banks_t, poll_bankmask);
+DEFINE_PER_CPU(struct mca_banks *, poll_bankmask);
 static struct timer mce_timer;
 
 #define MCE_PERIOD MILLISECS(8000)
@@ -94,6 +94,9 @@ static int __init init_nonfatal_mce_checker(void)
        if (mce_disabled || !mce_available(c))
                return -ENODEV;
 
+    if ( __get_cpu_var(poll_bankmask) == NULL )
+        return -EINVAL;
+
        /*
         * Check for non-fatal errors every MCE_RATE s
         */
index 238e47b7dff1fb7cf281f6addc086f13aed1665f..353bae4f5b7affa658480a5489dde0e2c8ced229 100644 (file)
 
 #define dom_vmce(x)   ((x)->arch.vmca_msrs)
 
+uint64_t g_mcg_cap;
+
+/* Real value in physical CTL MSR */
+uint64_t h_mcg_ctl = 0UL;
+uint64_t *h_mci_ctrl;
+
 int vmce_init_msr(struct domain *d)
 {
     dom_vmce(d) = xmalloc(struct domain_mca_msrs);
@@ -431,3 +437,50 @@ int vmce_domain_inject(
     return inject_vmce(d);
 }
 
+int vmce_init(struct cpuinfo_x86 *c)
+{
+    u32 l, h;
+    u64 value;
+    int i;
+
+    if ( !h_mci_ctrl )
+    {
+        h_mci_ctrl = xmalloc_array(uint64_t, nr_mce_banks);
+        if (!h_mci_ctrl)
+        {
+            dprintk(XENLOG_INFO, "Failed to alloc h_mci_ctrl\n");
+            return -ENOMEM;
+        }
+        /* Don't care banks before firstbank */
+        memset(h_mci_ctrl, 0xff, sizeof(h_mci_ctrl));
+        for (i = firstbank; i < nr_mce_banks; i++)
+            rdmsrl(MSR_IA32_MC0_CTL + 4*i, h_mci_ctrl[i]);
+    }
+
+    if (g_mcg_cap & MCG_CTL_P)
+        rdmsrl(MSR_IA32_MCG_CTL, h_mcg_ctl);
+
+    rdmsr(MSR_IA32_MCG_CAP, l, h);
+    value = ((u64)h << 32) | l;
+    /* For Guest vMCE usage */
+    g_mcg_cap = value & ~MCG_CMCI_P;
+
+    return 0;
+}
+
+int mca_ctl_conflict(struct mcinfo_bank *bank, struct domain *d)
+{
+    int bank_nr;
+
+    if ( !bank || !d || !h_mci_ctrl )
+        return 1;
+
+    /* Will MCE happen in host if If host mcg_ctl is 0? */
+    if ( ~d->arch.vmca_msrs->mcg_ctl & h_mcg_ctl )
+        return 1;
+
+    bank_nr = bank->mc_bank;
+    if (~d->arch.vmca_msrs->mci_ctl[bank_nr] & h_mci_ctrl[bank_nr] )
+        return 1;
+    return 0;
+}
index 85c624efe347c9e063c06fb88ffb00c7ab79a803..3271ec846ee3c18e9ad1739a8932f69f271d2c29 100644 (file)
 #define CMCI_THRESHOLD                 0x2
 
 #include <asm/domain.h>
-typedef DECLARE_BITMAP(cpu_banks_t, MAX_NR_BANKS);
-DECLARE_PER_CPU(cpu_banks_t, mce_banks_owned);
+
+struct mca_banks
+{
+    int num;
+    unsigned long *bank_map;
+};
+
+static inline void mcabanks_clear(int bit, struct mca_banks *banks)    \
+{
+    if (!banks || !banks->bank_map || bit >= banks->num)
+        return ;
+    clear_bit(bit, banks->bank_map);
+}
+
+static inline void mcabanks_set(int bit, struct mca_banks* banks)
+{
+    if (!banks || !banks->bank_map || bit >= banks->num)
+        return;
+    set_bit(bit, banks->bank_map);
+}
+
+static inline int mcabanks_test(int bit, struct mca_banks* banks)
+{
+    if (!banks || !banks->bank_map || bit >= banks->num)
+        return 0;
+    return test_bit(bit, banks->bank_map);
+}
+
+struct mca_banks *mcabanks_alloc(void);
+void mcabanks_free(struct mca_banks *banks);
+extern struct mca_banks *mca_allbanks;
 
 /* Below interfaces are defined for MCA internal processing:
  * a. pre_handler will be called early in MCA ISR context, mainly for early
index 4baa0b80219b729f01ddcaa2201f6b919f304ac4..e533c6574893b45cb034c671242c60e0d5d31664 100644 (file)
@@ -2,8 +2,6 @@
 #include <public/arch-x86/xen-mca.h>
 #ifndef _XEN_X86_MCE_H
 #define _XEN_X86_MCE_H
-/* Define for GUEST MCA handling */
-#define MAX_NR_BANKS 30
 
 /* This entry is for recording bank nodes for the impacted domain,
  * put into impact_header list. */