# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1234245060 0
# Node ID 4ac8bc60c000500f7fa1aeccea708d2191f5f31a
# Parent 09ea7eea81229fc64276b5682778a131f2fd1e1b
x86: mce: Provide extended physical CPU info.
Provide extended physial CPU info for the sake of dom0 MCE handling.
This information includes <cpu,core,thread> info for all logical CPUs,
cpuid information from all of them, and initial MSR values for a few
MSRs that are important to MCE handling.
Signed-off-by: Frank van der Linden <Frank.Vanderlinden@xxxxxxx>
---
xen/arch/x86/cpu/mcheck/amd_k8.c | 14 +--
xen/arch/x86/cpu/mcheck/amd_nonfatal.c | 13 +--
xen/arch/x86/cpu/mcheck/mce.c | 130 +++++++++++++++++++++++++++++++++
xen/arch/x86/cpu/mcheck/mce.h | 3
xen/arch/x86/cpu/mcheck/mce_intel.c | 8 --
xen/include/public/arch-x86/xen-mca.h | 48 +++++++++++-
6 files changed, 194 insertions(+), 22 deletions(-)
diff -r 09ea7eea8122 -r 4ac8bc60c000 xen/arch/x86/cpu/mcheck/amd_k8.c
--- a/xen/arch/x86/cpu/mcheck/amd_k8.c Tue Feb 10 05:47:00 2009 +0000
+++ b/xen/arch/x86/cpu/mcheck/amd_k8.c Tue Feb 10 05:51:00 2009 +0000
@@ -99,6 +99,8 @@ void k8_machine_check(struct cpu_user_re
mc_data = x86_mcinfo_getptr();
cpu_nr = smp_processor_id();
+ BUG_ON(cpu_nr != vcpu->processor);
+
curdom = vcpu->domain;
memset(&mc_global, 0, sizeof(mc_global));
@@ -106,14 +108,12 @@ void k8_machine_check(struct cpu_user_re
mc_global.common.size = sizeof(mc_global);
mc_global.mc_domid = curdom->domain_id; /* impacted domain */
- mc_global.mc_coreid = vcpu->processor; /* impacted physical cpu */
- BUG_ON(cpu_nr != vcpu->processor);
- mc_global.mc_core_threadid = 0;
+
+ x86_mc_get_cpu_info(cpu_nr, &mc_global.mc_socketid,
+ &mc_global.mc_coreid, &mc_global.mc_core_threadid,
+ &mc_global.mc_apicid, NULL, NULL, NULL);
+
mc_global.mc_vcpuid = vcpu->vcpu_id; /* impacted vcpu */
-#if 0 /* TODO: on which socket is this physical core?
- It's not clear to me how to figure this out. */
- mc_global.mc_socketid = ???;
-#endif
mc_global.mc_flags |= MC_FLAG_UNCORRECTABLE;
rdmsrl(MSR_IA32_MCG_STATUS, mc_global.mc_gstatus);
diff -r 09ea7eea8122 -r 4ac8bc60c000 xen/arch/x86/cpu/mcheck/amd_nonfatal.c
--- a/xen/arch/x86/cpu/mcheck/amd_nonfatal.c Tue Feb 10 05:47:00 2009 +0000
+++ b/xen/arch/x86/cpu/mcheck/amd_nonfatal.c Tue Feb 10 05:51:00 2009 +0000
@@ -95,6 +95,7 @@ void mce_amd_checkregs(void *info)
mc_data = NULL;
cpu_nr = smp_processor_id();
+ BUG_ON(cpu_nr != vcpu->processor);
event_enabled = guest_enabled_event(dom0->vcpu[0], VIRQ_MCA);
error_found = 0;
@@ -103,14 +104,12 @@ void mce_amd_checkregs(void *info)
mc_global.common.size = sizeof(mc_global);
mc_global.mc_domid = vcpu->domain->domain_id; /* impacted domain */
- mc_global.mc_coreid = vcpu->processor; /* impacted physical cpu */
- BUG_ON(cpu_nr != vcpu->processor);
- mc_global.mc_core_threadid = 0;
mc_global.mc_vcpuid = vcpu->vcpu_id; /* impacted vcpu */
-#if 0 /* TODO: on which socket is this physical core?
- It's not clear to me how to figure this out. */
- mc_global.mc_socketid = ???;
-#endif
+
+ x86_mc_get_cpu_info(cpu_nr, &mc_global.mc_socketid,
+ &mc_global.mc_coreid, &mc_global.mc_core_threadid,
+ &mc_global.mc_apicid, NULL, NULL, NULL);
+
mc_global.mc_flags |= MC_FLAG_CORRECTABLE;
rdmsrl(MSR_IA32_MCG_STATUS, mc_global.mc_gstatus);
diff -r 09ea7eea8122 -r 4ac8bc60c000 xen/arch/x86/cpu/mcheck/mce.c
--- a/xen/arch/x86/cpu/mcheck/mce.c Tue Feb 10 05:47:00 2009 +0000
+++ b/xen/arch/x86/cpu/mcheck/mce.c Tue Feb 10 05:51:00 2009 +0000
@@ -443,6 +443,96 @@ next:
+static void do_mc_get_cpu_info(void *v)
+{
+ int cpu = smp_processor_id();
+ int cindex, cpn;
+ struct cpuinfo_x86 *c;
+ xen_mc_logical_cpu_t *log_cpus, *xcp;
+ uint32_t junk, ebx;
+
+ log_cpus = v;
+ c = &cpu_data[cpu];
+ cindex = 0;
+ cpn = cpu - 1;
+
+ /*
+ * Deal with sparse masks, condensed into a contig array.
+ */
+ while (cpn >= 0) {
+ if (cpu_isset(cpn, cpu_online_map))
+ cindex++;
+ cpn--;
+ }
+
+ xcp = &log_cpus[cindex];
+ c = &cpu_data[cpu];
+ xcp->mc_cpunr = cpu;
+ x86_mc_get_cpu_info(cpu, &xcp->mc_chipid,
+ &xcp->mc_coreid, &xcp->mc_threadid,
+ &xcp->mc_apicid, &xcp->mc_ncores,
+ &xcp->mc_ncores_active, &xcp->mc_nthreads);
+ xcp->mc_cpuid_level = c->cpuid_level;
+ xcp->mc_family = c->x86;
+ xcp->mc_vendor = c->x86_vendor;
+ xcp->mc_model = c->x86_model;
+ xcp->mc_step = c->x86_mask;
+ xcp->mc_cache_size = c->x86_cache_size;
+ xcp->mc_cache_alignment = c->x86_cache_alignment;
+ memcpy(xcp->mc_vendorid, c->x86_vendor_id, sizeof xcp->mc_vendorid);
+ memcpy(xcp->mc_brandid, c->x86_model_id, sizeof xcp->mc_brandid);
+ memcpy(xcp->mc_cpu_caps, c->x86_capability, sizeof xcp->mc_cpu_caps);
+
+ /*
+ * This part needs to run on the CPU itself.
+ */
+ xcp->mc_nmsrvals = __MC_NMSRS;
+ xcp->mc_msrvalues[0].reg = MSR_IA32_MCG_CAP;
+ rdmsrl(MSR_IA32_MCG_CAP, xcp->mc_msrvalues[0].value);
+
+ if (c->cpuid_level >= 1) {
+ cpuid(1, &junk, &ebx, &junk, &junk);
+ xcp->mc_clusterid = (ebx >> 24) & 0xff;
+ } else
+ xcp->mc_clusterid = hard_smp_processor_id();
+}
+
+
+void x86_mc_get_cpu_info(unsigned cpu, uint32_t *chipid, uint16_t *coreid,
+ uint16_t *threadid, uint32_t *apicid,
+ unsigned *ncores, unsigned *ncores_active,
+ unsigned *nthreads)
+{
+ struct cpuinfo_x86 *c;
+
+ *apicid = cpu_physical_id(cpu);
+ c = &cpu_data[cpu];
+ if (c->apicid == BAD_APICID) {
+ *chipid = cpu;
+ *coreid = 0;
+ *threadid = 0;
+ if (ncores != NULL)
+ *ncores = 1;
+ if (ncores_active != NULL)
+ *ncores_active = 1;
+ if (nthreads != NULL)
+ *nthreads = 1;
+ } else {
+ *chipid = phys_proc_id[cpu];
+ if (c->x86_max_cores > 1)
+ *coreid = cpu_core_id[cpu];
+ else
+ *coreid = 0;
+ *threadid = c->apicid & ((1 << (c->x86_num_siblings - 1)) - 1);
+ if (ncores != NULL)
+ *ncores = c->x86_max_cores;
+ if (ncores_active != NULL)
+ *ncores_active = c->booted_cores;
+ if (nthreads != NULL)
+ *nthreads = c->x86_num_siblings;
+ }
+}
+
/* Machine Check Architecture Hypercall */
long do_mca(XEN_GUEST_HANDLE(xen_mc_t) u_xen_mc)
{
@@ -452,6 +542,7 @@ long do_mca(XEN_GUEST_HANDLE(xen_mc_t) u
struct domain *domU;
struct xen_mc_fetch *mc_fetch;
struct xen_mc_notifydomain *mc_notifydomain;
+ struct xen_mc_physcpuinfo *mc_physcpuinfo;
struct mc_info *mi;
uint32_t flags;
uint32_t fetch_idx;
@@ -460,6 +551,8 @@ long do_mca(XEN_GUEST_HANDLE(xen_mc_t) u
* a DomU to fetch mc data while Dom0 notifies another DomU. */
static DEFINE_SPINLOCK(mc_lock);
static DEFINE_SPINLOCK(mc_notify_lock);
+ int nlcpu;
+ xen_mc_logical_cpu_t *log_cpus = NULL;
if ( copy_from_guest(op, u_xen_mc, 1) )
return -EFAULT;
@@ -580,6 +673,43 @@ long do_mca(XEN_GUEST_HANDLE(xen_mc_t) u
spin_unlock(&mc_notify_lock);
break;
+
+ case XEN_MC_physcpuinfo:
+ if ( !IS_PRIV(v->domain) )
+ return -EPERM;
+
+ mc_physcpuinfo = &op->u.mc_physcpuinfo;
+ nlcpu = num_online_cpus();
+
+ if (!guest_handle_is_null(mc_physcpuinfo->info)) {
+ if (mc_physcpuinfo->ncpus <= 0)
+ return -EINVAL;
+ nlcpu = min(nlcpu, (int)mc_physcpuinfo->ncpus);
+ log_cpus = xmalloc_array(xen_mc_logical_cpu_t, nlcpu);
+ if (log_cpus == NULL)
+ return -ENOMEM;
+
+ if (on_each_cpu(do_mc_get_cpu_info, log_cpus,
+ 1, 1) != 0) {
+ xfree(log_cpus);
+ return -EIO;
+ }
+ }
+
+ mc_physcpuinfo->ncpus = nlcpu;
+
+ if (copy_to_guest(u_xen_mc, op, 1)) {
+ if (log_cpus != NULL)
+ xfree(log_cpus);
+ return -EFAULT;
+ }
+
+ if (!guest_handle_is_null(mc_physcpuinfo->info)) {
+ if (copy_to_guest(mc_physcpuinfo->info,
+ log_cpus, nlcpu))
+ ret = -EFAULT;
+ xfree(log_cpus);
+ }
}
return ret;
diff -r 09ea7eea8122 -r 4ac8bc60c000 xen/arch/x86/cpu/mcheck/mce.h
--- a/xen/arch/x86/cpu/mcheck/mce.h Tue Feb 10 05:47:00 2009 +0000
+++ b/xen/arch/x86/cpu/mcheck/mce.h Tue Feb 10 05:51:00 2009 +0000
@@ -34,4 +34,5 @@ int x86_mcinfo_add(struct mc_info *mi, v
int x86_mcinfo_add(struct mc_info *mi, void *mcinfo);
void x86_mcinfo_dump(struct mc_info *mi);
void mc_panic(char *s);
-
+void x86_mc_get_cpu_info(unsigned, uint32_t *, uint16_t *, uint16_t *,
+ uint32_t *, uint32_t *, uint32_t *, uint32_t *);
diff -r 09ea7eea8122 -r 4ac8bc60c000 xen/arch/x86/cpu/mcheck/mce_intel.c
--- a/xen/arch/x86/cpu/mcheck/mce_intel.c Tue Feb 10 05:47:00 2009 +0000
+++ b/xen/arch/x86/cpu/mcheck/mce_intel.c Tue Feb 10 05:51:00 2009 +0000
@@ -182,11 +182,9 @@ static struct mc_info *machine_check_pol
mcg.mc_flags = MC_FLAG_POLLED;
else if (calltype == MC_FLAG_CMCI)
mcg.mc_flags = MC_FLAG_CMCI;
- mcg.mc_socketid = phys_proc_id[cpu];
- mcg.mc_coreid = cpu_core_id[cpu];
- mcg.mc_apicid = cpu_physical_id(cpu);
- mcg.mc_core_threadid =
- mcg.mc_apicid & ( 1 << (cpu_data[cpu].x86_num_siblings - 1));
+ x86_mc_get_cpu_info(
+ cpu, &mcg.mc_socketid, &mcg.mc_coreid,
+ &mcg.mc_core_threadid, &mcg.mc_apicid, NULL, NULL, NULL);
rdmsrl(MSR_IA32_MCG_STATUS, mcg.mc_gstatus);
for ( i = 0; i < nr_mce_banks; i++ ) {
diff -r 09ea7eea8122 -r 4ac8bc60c000 xen/include/public/arch-x86/xen-mca.h
--- a/xen/include/public/arch-x86/xen-mca.h Tue Feb 10 05:47:00 2009 +0000
+++ b/xen/include/public/arch-x86/xen-mca.h Tue Feb 10 05:51:00 2009 +0000
@@ -56,7 +56,7 @@
/* Hypercall */
#define __HYPERVISOR_mca __HYPERVISOR_arch_0
-#define XEN_MCA_INTERFACE_VERSION 0x03000001
+#define XEN_MCA_INTERFACE_VERSION 0x03000002
/* IN: Dom0 calls hypercall from MC event handler. */
#define XEN_MC_CORRECTABLE 0x0
@@ -118,7 +118,7 @@ struct mcinfo_global {
uint16_t mc_domid;
uint32_t mc_socketid; /* physical socket of the physical core */
uint16_t mc_coreid; /* physical impacted core */
- uint8_t mc_apicid;
+ uint32_t mc_apicid;
uint16_t mc_core_threadid; /* core thread of physical core */
uint16_t mc_vcpuid; /* virtual cpu scheduled for mc_domid */
uint64_t mc_gstatus; /* global status */
@@ -175,6 +175,41 @@ struct mc_info {
};
typedef struct mc_info mc_info_t;
+#define __MC_MSR_ARRAYSIZE 8
+#define __MC_NMSRS 1
+#define MC_NCAPS 7 /* 7 CPU feature flag words */
+#define MC_CAPS_STD_EDX 0 /* cpuid level 0x00000001 (%edx) */
+#define MC_CAPS_AMD_EDX 1 /* cpuid level 0x80000001 (%edx) */
+#define MC_CAPS_TM 2 /* cpuid level 0x80860001 (TransMeta) */
+#define MC_CAPS_LINUX 3 /* Linux-defined */
+#define MC_CAPS_STD_ECX 4 /* cpuid level 0x00000001 (%ecx) */
+#define MC_CAPS_VIA 5 /* cpuid level 0xc0000001 */
+#define MC_CAPS_AMD_ECX 6 /* cpuid level 0x80000001 (%ecx) */
+
+typedef struct mcinfo_logical_cpu {
+ uint32_t mc_cpunr;
+ uint32_t mc_chipid;
+ uint16_t mc_coreid;
+ uint16_t mc_threadid;
+ uint32_t mc_apicid;
+ uint32_t mc_clusterid;
+ uint32_t mc_ncores;
+ uint32_t mc_ncores_active;
+ uint32_t mc_nthreads;
+ int32_t mc_cpuid_level;
+ uint32_t mc_family;
+ uint32_t mc_vendor;
+ uint32_t mc_model;
+ uint32_t mc_step;
+ char mc_vendorid[16];
+ char mc_brandid[64];
+ uint32_t mc_cpu_caps[MC_NCAPS];
+ uint32_t mc_cache_size;
+ uint32_t mc_cache_alignment;
+ int32_t mc_nmsrvals;
+ struct mcinfo_msr mc_msrvalues[__MC_MSR_ARRAYSIZE];
+} xen_mc_logical_cpu_t;
+DEFINE_XEN_GUEST_HANDLE(xen_mc_logical_cpu_t);
/*
@@ -272,6 +307,14 @@ typedef struct xen_mc_notifydomain xen_m
typedef struct xen_mc_notifydomain xen_mc_notifydomain_t;
DEFINE_XEN_GUEST_HANDLE(xen_mc_notifydomain_t);
+#define XEN_MC_physcpuinfo 3
+struct xen_mc_physcpuinfo {
+ /* IN/OUT */
+ uint32_t ncpus;
+ uint32_t pad0;
+ /* OUT */
+ XEN_GUEST_HANDLE(xen_mc_logical_cpu_t) info;
+};
struct xen_mc {
uint32_t cmd;
@@ -279,6 +322,7 @@ struct xen_mc {
union {
struct xen_mc_fetch mc_fetch;
struct xen_mc_notifydomain mc_notifydomain;
+ struct xen_mc_physcpuinfo mc_physcpuinfo;
uint8_t pad[MCINFO_HYPERCALLSIZE];
} u;
};
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|