bool
config X86_MCE
- bool "Machine check support" if EMBEDDED
- depends on !X86_64_XEN
+ bool "Machine check support"
+ depends on (!XEN_UNPRIVILEGED_GUEST)
default y
help
Include a machine check error handler to report hardware errors.
config X86_MCE_INTEL
bool "Intel MCE features"
- depends on X86_MCE && X86_LOCAL_APIC
+ depends on X86_MCE && X86_LOCAL_APIC && !X86_64_XEN
default y
help
Additional support for intel specific MCE features such as
config X86_MCE_AMD
bool "AMD MCE features"
- depends on X86_MCE && X86_LOCAL_APIC
+ depends on X86_MCE && X86_LOCAL_APIC && !X86_64_XEN
default y
help
Additional support for AMD specific MCE features such as
the DRAM Error Threshold.
+config X86_XEN_MCE
+ def_bool y
+ depends on X86_64_XEN && X86_MCE
+
config KEXEC
bool "kexec system call (EXPERIMENTAL)"
depends on EXPERIMENTAL && !XEN_UNPRIVILEGED_GUEST
/*
* Periodic polling timer for "silent" machine check errors.
- */
+ * We will disable polling in DOM0 since all CMCI/Polling
+ * mechanism will be done in XEN for Intel CPUs
+*/
+#if defined (CONFIG_X86_XEN_MCE)
+static int check_interval = 0; /* disable polling */
+#else
static int check_interval = 5 * 60; /* 5 minutes */
+#endif
+
static void mcheck_timer(void *data);
static DECLARE_WORK(mcheck_work, mcheck_timer, NULL);
static void __cpuinit mce_cpu_features(struct cpuinfo_x86 *c)
{
+#ifndef CONFIG_X86_64_XEN
switch (c->x86_vendor) {
case X86_VENDOR_INTEL:
mce_intel_feature_init(c);
default:
break;
}
+#endif
}
-
/*
* Called for each booted CPU to set up machine checks.
* Must be called with preempt off.
};
#endif
+extern void bind_virq_for_mce(void);
static __init int mce_init_device(void)
{
int err;
register_hotcpu_notifier(&mce_cpu_notifier);
misc_register(&mce_log_device);
+
+ /*Register vIRQ handler for MCE LOG processing*/
+#if defined(CONFIG_X86_XEN_MCE)
+ printk(KERN_DEBUG "MCE: bind virq for DOM0 Logging\n");
+ bind_virq_for_mce();
+#endif
+
return err;
}
--- /dev/null
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <xen/interface/xen.h>
+#include <xen/evtchn.h>
+#include <xen/interface/vcpu.h>
+#include <asm/hypercall.h>
+#include <asm/mce.h>
+
+static int convert_log(struct mc_info *mi)
+{
+ struct mcinfo_common *mic = NULL;
+ struct mcinfo_global *mc_global;
+ struct mcinfo_bank *mc_bank;
+ struct mce m;
+
+ x86_mcinfo_lookup(mic, mi, MC_TYPE_GLOBAL);
+ if (mic == NULL)
+ {
+ printk(KERN_ERR "DOM0_MCE_LOG: global data is NULL\n");
+ return -1;
+ }
+
+ mc_global = (struct mcinfo_global*)mic;
+ m.mcgstatus = mc_global->mc_gstatus;
+ m.cpu = mc_global->mc_coreid;/*for test*/
+ x86_mcinfo_lookup(mic, mi, MC_TYPE_BANK);
+ do
+ {
+ if (mic == NULL || mic->size == 0)
+ break;
+ if (mic->type == MC_TYPE_BANK)
+ {
+ mc_bank = (struct mcinfo_bank*)mic;
+ m.misc = mc_bank->mc_misc;
+ m.status = mc_bank->mc_status;
+ m.addr = mc_bank->mc_addr;
+ m.tsc = mc_bank->mc_tsc;
+ m.res1 = mc_bank->mc_ctrl2;
+ m.bank = mc_bank->mc_bank;
+ printk(KERN_DEBUG "[CPU%d, BANK%d, addr %llx, state %llx]\n",
+ m.bank, m.cpu, m.addr, m.status);
+ /*log this record*/
+ mce_log(&m);
+ }
+ mic = x86_mcinfo_next(mic);
+ }while (1);
+
+ return 0;
+}
+
+static struct mc_info *g_mi;
+
+/*dom0 mce virq handler, logging physical mce error info*/
+
+static irqreturn_t mce_dom0_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ xen_mc_t mc_op;
+ int result = 0;
+
+ printk(KERN_DEBUG "MCE_DOM0_LOG: enter dom0 mce vIRQ handler\n");
+ mc_op.cmd = XEN_MC_fetch;
+ mc_op.interface_version = XEN_MCA_INTERFACE_VERSION;
+ set_xen_guest_handle(mc_op.u.mc_fetch.data, g_mi);
+urgent:
+ mc_op.u.mc_fetch.flags = XEN_MC_URGENT;
+ result = HYPERVISOR_mca(&mc_op);
+ if (result || mc_op.u.mc_fetch.flags & XEN_MC_NODATA ||
+ mc_op.u.mc_fetch.flags & XEN_MC_FETCHFAILED)
+ {
+ printk(KERN_DEBUG "MCE_DOM0_LOG: No more urgent data\n");
+ goto nonurgent;
+ }
+ else
+ {
+ result = convert_log(g_mi);
+ if (result) {
+ printk(KERN_ERR "MCE_DOM0_LOG: Log conversion failed\n");
+ goto end;
+ }
+ /* After fetching the telem from DOM0, we need to dec the telem's
+ * refcnt and release the entry. The telem is reserved and inc
+ * refcnt when filling the telem.
+ */
+ mc_op.u.mc_fetch.flags = XEN_MC_URGENT | XEN_MC_ACK;
+ result = HYPERVISOR_mca(&mc_op);
+
+ goto urgent;
+ }
+nonurgent:
+ mc_op.u.mc_fetch.flags = XEN_MC_NONURGENT;
+ result = HYPERVISOR_mca(&mc_op);
+ if (result || mc_op.u.mc_fetch.flags & XEN_MC_NODATA ||
+ mc_op.u.mc_fetch.flags & XEN_MC_FETCHFAILED)
+ {
+ printk(KERN_DEBUG "MCE_DOM0_LOG: No more nonurgent data\n");
+ goto end;
+ }
+ else
+ {
+ result = convert_log(g_mi);
+ if (result) {
+ printk(KERN_ERR "MCE_DOM0_LOG: Log conversion failed\n");
+ goto end;
+ }
+ /* After fetching the telem from DOM0, we need to dec the telem's
+ * refcnt and release the entry. The telem is reserved and inc
+ * refcnt when filling the telem.
+ */
+ mc_op.u.mc_fetch.flags = XEN_MC_NONURGENT | XEN_MC_ACK;
+ result = HYPERVISOR_mca(&mc_op);
+
+ goto nonurgent;
+ }
+end:
+ return IRQ_HANDLED;
+}
+
+void bind_virq_for_mce(void)
+{
+ int ret;
+
+ ret = bind_virq_to_irqhandler(VIRQ_MCA, 0,
+ mce_dom0_interrupt, 0, "mce", NULL);
+
+ g_mi = kmalloc(sizeof(struct mc_info), GFP_KERNEL);
+ if (ret < 0)
+ printk(KERN_ERR "MCE_DOM0_LOG: bind_virq for DOM0 failed\n");
+}
+