All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] provide detailed physical CPU info for dom0 MCE handling
@ 2009-02-09 19:04 Frank van der Linden
  0 siblings, 0 replies; only message in thread
From: Frank van der Linden @ 2009-02-09 19:04 UTC (permalink / raw)
  To: Xen-Devel (E-mail)

[-- Attachment #1: Type: text/plain, Size: 761 bytes --]

The attached patch introduces a hypercall to provide detailed physical 
CPU information for dom0. While there is already a physinfo call, much 
more detailed information is needed for dom0 to have enough knowledge of 
the system to be able to deal with the MCE information provided when an 
actual exception occurs, and to store this information so that it can be 
used across reboots.

Most of the needed information is gleaned from the already present 
global cpu info structures. A few things are collected at call time.

This patch also bumps the mc_apicid in the global MC info field to 
32bits, for future extension and better alignment.

This patch was discussed with and agreed upon by both the AMD and Intel 
engineers working on MCE for Xen.

- Frank

[-- Attachment #2: mca-cpuinfo --]
[-- Type: text/plain, Size: 11259 bytes --]

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@Sun.COM>

diff --git a/xen/arch/x86/cpu/mcheck/amd_k8.c b/xen/arch/x86/cpu/mcheck/amd_k8.c
--- a/xen/arch/x86/cpu/mcheck/amd_k8.c
+++ b/xen/arch/x86/cpu/mcheck/amd_k8.c
@@ -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 --git a/xen/arch/x86/cpu/mcheck/amd_nonfatal.c b/xen/arch/x86/cpu/mcheck/amd_nonfatal.c
--- a/xen/arch/x86/cpu/mcheck/amd_nonfatal.c
+++ b/xen/arch/x86/cpu/mcheck/amd_nonfatal.c
@@ -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 --git a/xen/arch/x86/cpu/mcheck/mce.c b/xen/arch/x86/cpu/mcheck/mce.c
--- a/xen/arch/x86/cpu/mcheck/mce.c
+++ b/xen/arch/x86/cpu/mcheck/mce.c
@@ -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 --git a/xen/arch/x86/cpu/mcheck/mce.h b/xen/arch/x86/cpu/mcheck/mce.h
--- a/xen/arch/x86/cpu/mcheck/mce.h
+++ b/xen/arch/x86/cpu/mcheck/mce.h
@@ -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 --git a/xen/arch/x86/cpu/mcheck/mce_intel.c b/xen/arch/x86/cpu/mcheck/mce_intel.c
--- a/xen/arch/x86/cpu/mcheck/mce_intel.c
+++ b/xen/arch/x86/cpu/mcheck/mce_intel.c
@@ -188,11 +188,8 @@ static int machine_check_poll(struct mc_
         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 --git a/xen/include/public/arch-x86/xen-mca.h b/xen/include/public/arch-x86/xen-mca.h
--- a/xen/include/public/arch-x86/xen-mca.h
+++ b/xen/include/public/arch-x86/xen-mca.h
@@ -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;
 };

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2009-02-09 19:04 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-02-09 19:04 [PATCH] provide detailed physical CPU info for dom0 MCE handling Frank van der Linden

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.