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@Sun.COM>
This commit is contained in:
Keir Fraser committed 2009-02-10 05:51:00 +00:00
1 parent ab620f29ef
commit e16fc5ba59
6 files changed
+194 -22

No files matched your search

+7 -7
View File
@@ -99,6 +99,8 @@ void k8_machine_check(struct cpu_user_regs *regs, long error_code)
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_regs *regs, long error_code)
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);
+6 -7
View File
@@ -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);
+130
View File
@@ -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_xen_mc)
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_xen_mc)
* 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_xen_mc)
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;
+2 -1
View File
@@ -34,4 +34,5 @@ void x86_mcinfo_clear(struct mc_info *mi);
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 *);
+3 -5
View File
@@ -182,11 +182,9 @@ static struct mc_info *machine_check_poll(int calltype)
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++ ) {
+46 -2
View File
@@ -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 @@ struct xen_mc_notifydomain {
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;
};
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.