ia64/xen-unstable

changeset 19189:4ac8bc60c000

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>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Feb 10 05:51:00 2009 +0000 (2009-02-10)
parents 09ea7eea8122
children 8d7a6bc2575d
files xen/arch/x86/cpu/mcheck/amd_k8.c xen/arch/x86/cpu/mcheck/amd_nonfatal.c xen/arch/x86/cpu/mcheck/mce.c xen/arch/x86/cpu/mcheck/mce.h xen/arch/x86/cpu/mcheck/mce_intel.c xen/include/public/arch-x86/xen-mca.h
line diff
     1.1 --- a/xen/arch/x86/cpu/mcheck/amd_k8.c	Tue Feb 10 05:47:00 2009 +0000
     1.2 +++ b/xen/arch/x86/cpu/mcheck/amd_k8.c	Tue Feb 10 05:51:00 2009 +0000
     1.3 @@ -99,6 +99,8 @@ void k8_machine_check(struct cpu_user_re
     1.4  
     1.5  	mc_data = x86_mcinfo_getptr();
     1.6  	cpu_nr = smp_processor_id();
     1.7 +	BUG_ON(cpu_nr != vcpu->processor);
     1.8 +
     1.9  	curdom = vcpu->domain;
    1.10  
    1.11  	memset(&mc_global, 0, sizeof(mc_global));
    1.12 @@ -106,14 +108,12 @@ void k8_machine_check(struct cpu_user_re
    1.13  	mc_global.common.size = sizeof(mc_global);
    1.14  
    1.15  	mc_global.mc_domid = curdom->domain_id; /* impacted domain */
    1.16 -	mc_global.mc_coreid = vcpu->processor; /* impacted physical cpu */
    1.17 -	BUG_ON(cpu_nr != vcpu->processor);
    1.18 -	mc_global.mc_core_threadid = 0;
    1.19 +
    1.20 +	x86_mc_get_cpu_info(cpu_nr, &mc_global.mc_socketid,
    1.21 +	    &mc_global.mc_coreid, &mc_global.mc_core_threadid,
    1.22 +	    &mc_global.mc_apicid, NULL, NULL, NULL);
    1.23 +
    1.24  	mc_global.mc_vcpuid = vcpu->vcpu_id; /* impacted vcpu */
    1.25 -#if 0 /* TODO: on which socket is this physical core?
    1.26 -         It's not clear to me how to figure this out. */
    1.27 -	mc_global.mc_socketid = ???;
    1.28 -#endif
    1.29  	mc_global.mc_flags |= MC_FLAG_UNCORRECTABLE;
    1.30  	rdmsrl(MSR_IA32_MCG_STATUS, mc_global.mc_gstatus);
    1.31  
     2.1 --- a/xen/arch/x86/cpu/mcheck/amd_nonfatal.c	Tue Feb 10 05:47:00 2009 +0000
     2.2 +++ b/xen/arch/x86/cpu/mcheck/amd_nonfatal.c	Tue Feb 10 05:51:00 2009 +0000
     2.3 @@ -95,6 +95,7 @@ void mce_amd_checkregs(void *info)
     2.4  	mc_data = NULL;
     2.5  
     2.6  	cpu_nr = smp_processor_id();
     2.7 +	BUG_ON(cpu_nr != vcpu->processor);
     2.8  	event_enabled = guest_enabled_event(dom0->vcpu[0], VIRQ_MCA);
     2.9  	error_found = 0;
    2.10  
    2.11 @@ -103,14 +104,12 @@ void mce_amd_checkregs(void *info)
    2.12  	mc_global.common.size = sizeof(mc_global);
    2.13  
    2.14  	mc_global.mc_domid = vcpu->domain->domain_id; /* impacted domain */
    2.15 -	mc_global.mc_coreid = vcpu->processor; /* impacted physical cpu */
    2.16 -	BUG_ON(cpu_nr != vcpu->processor);
    2.17 -	mc_global.mc_core_threadid = 0;
    2.18  	mc_global.mc_vcpuid = vcpu->vcpu_id; /* impacted vcpu */
    2.19 -#if 0 /* TODO: on which socket is this physical core?
    2.20 -         It's not clear to me how to figure this out. */
    2.21 -	mc_global.mc_socketid = ???;
    2.22 -#endif
    2.23 +
    2.24 +	x86_mc_get_cpu_info(cpu_nr, &mc_global.mc_socketid,
    2.25 +	    &mc_global.mc_coreid, &mc_global.mc_core_threadid,
    2.26 +	    &mc_global.mc_apicid, NULL, NULL, NULL);
    2.27 +
    2.28  	mc_global.mc_flags |= MC_FLAG_CORRECTABLE;
    2.29  	rdmsrl(MSR_IA32_MCG_STATUS, mc_global.mc_gstatus);
    2.30  
     3.1 --- a/xen/arch/x86/cpu/mcheck/mce.c	Tue Feb 10 05:47:00 2009 +0000
     3.2 +++ b/xen/arch/x86/cpu/mcheck/mce.c	Tue Feb 10 05:51:00 2009 +0000
     3.3 @@ -443,6 +443,96 @@ next:
     3.4  
     3.5  
     3.6  
     3.7 +static void do_mc_get_cpu_info(void *v)
     3.8 +{
     3.9 +	int cpu = smp_processor_id();
    3.10 +	int cindex, cpn;
    3.11 +	struct cpuinfo_x86 *c;
    3.12 +	xen_mc_logical_cpu_t *log_cpus, *xcp;
    3.13 +	uint32_t junk, ebx;
    3.14 +
    3.15 +	log_cpus = v;
    3.16 +	c = &cpu_data[cpu];
    3.17 +	cindex = 0;
    3.18 +	cpn = cpu - 1;
    3.19 +
    3.20 +	/*
    3.21 +	 * Deal with sparse masks, condensed into a contig array.
    3.22 +	 */
    3.23 +	while (cpn >= 0) {
    3.24 +		if (cpu_isset(cpn, cpu_online_map))
    3.25 +			cindex++;
    3.26 +		cpn--;
    3.27 +	}
    3.28 +
    3.29 +	xcp = &log_cpus[cindex];
    3.30 +	c = &cpu_data[cpu];
    3.31 +	xcp->mc_cpunr = cpu;
    3.32 +	x86_mc_get_cpu_info(cpu, &xcp->mc_chipid,
    3.33 +	    &xcp->mc_coreid, &xcp->mc_threadid,
    3.34 +	    &xcp->mc_apicid, &xcp->mc_ncores,
    3.35 +	    &xcp->mc_ncores_active, &xcp->mc_nthreads);
    3.36 +	xcp->mc_cpuid_level = c->cpuid_level;
    3.37 +	xcp->mc_family = c->x86;
    3.38 +	xcp->mc_vendor = c->x86_vendor;
    3.39 +	xcp->mc_model = c->x86_model;
    3.40 +	xcp->mc_step = c->x86_mask;
    3.41 +	xcp->mc_cache_size = c->x86_cache_size;
    3.42 +	xcp->mc_cache_alignment = c->x86_cache_alignment;
    3.43 +	memcpy(xcp->mc_vendorid, c->x86_vendor_id, sizeof xcp->mc_vendorid);
    3.44 +	memcpy(xcp->mc_brandid, c->x86_model_id, sizeof xcp->mc_brandid);
    3.45 +	memcpy(xcp->mc_cpu_caps, c->x86_capability, sizeof xcp->mc_cpu_caps);
    3.46 +
    3.47 +	/*
    3.48 +	 * This part needs to run on the CPU itself.
    3.49 +	 */
    3.50 +	xcp->mc_nmsrvals = __MC_NMSRS;
    3.51 +	xcp->mc_msrvalues[0].reg = MSR_IA32_MCG_CAP;
    3.52 +	rdmsrl(MSR_IA32_MCG_CAP, xcp->mc_msrvalues[0].value);
    3.53 +
    3.54 +	if (c->cpuid_level >= 1) {
    3.55 +		cpuid(1, &junk, &ebx, &junk, &junk);
    3.56 +		xcp->mc_clusterid = (ebx >> 24) & 0xff;
    3.57 +	} else
    3.58 +		xcp->mc_clusterid = hard_smp_processor_id();
    3.59 +}
    3.60 +
    3.61 +
    3.62 +void x86_mc_get_cpu_info(unsigned cpu, uint32_t *chipid, uint16_t *coreid,
    3.63 +			 uint16_t *threadid, uint32_t *apicid,
    3.64 +			 unsigned *ncores, unsigned *ncores_active,
    3.65 +			 unsigned *nthreads)
    3.66 +{
    3.67 +	struct cpuinfo_x86 *c;
    3.68 +
    3.69 +	*apicid = cpu_physical_id(cpu);
    3.70 +	c = &cpu_data[cpu];
    3.71 +	if (c->apicid == BAD_APICID) {
    3.72 +		*chipid = cpu;
    3.73 +		*coreid = 0;
    3.74 +		*threadid = 0;
    3.75 +		if (ncores != NULL)
    3.76 +			*ncores = 1;
    3.77 +		if (ncores_active != NULL)
    3.78 +			*ncores_active = 1;
    3.79 +		if (nthreads != NULL)
    3.80 +			*nthreads = 1;
    3.81 +	} else {
    3.82 +		*chipid = phys_proc_id[cpu];
    3.83 +		if (c->x86_max_cores > 1)
    3.84 +			*coreid = cpu_core_id[cpu];
    3.85 +		else
    3.86 +			*coreid = 0;
    3.87 +		*threadid = c->apicid & ((1 << (c->x86_num_siblings - 1)) - 1);
    3.88 +		if (ncores != NULL)
    3.89 +			*ncores = c->x86_max_cores;
    3.90 +		if (ncores_active != NULL)
    3.91 +			*ncores_active = c->booted_cores;
    3.92 +		if (nthreads != NULL)
    3.93 +			*nthreads = c->x86_num_siblings;
    3.94 +	}
    3.95 +}
    3.96 +
    3.97  /* Machine Check Architecture Hypercall */
    3.98  long do_mca(XEN_GUEST_HANDLE(xen_mc_t) u_xen_mc)
    3.99  {
   3.100 @@ -452,6 +542,7 @@ long do_mca(XEN_GUEST_HANDLE(xen_mc_t) u
   3.101  	struct domain *domU;
   3.102  	struct xen_mc_fetch *mc_fetch;
   3.103  	struct xen_mc_notifydomain *mc_notifydomain;
   3.104 +	struct xen_mc_physcpuinfo *mc_physcpuinfo;
   3.105  	struct mc_info *mi;
   3.106  	uint32_t flags;
   3.107  	uint32_t fetch_idx;
   3.108 @@ -460,6 +551,8 @@ long do_mca(XEN_GUEST_HANDLE(xen_mc_t) u
   3.109  	 * a DomU to fetch mc data while Dom0 notifies another DomU. */
   3.110  	static DEFINE_SPINLOCK(mc_lock);
   3.111  	static DEFINE_SPINLOCK(mc_notify_lock);
   3.112 +	int nlcpu;
   3.113 +	xen_mc_logical_cpu_t *log_cpus = NULL;
   3.114  
   3.115  	if ( copy_from_guest(op, u_xen_mc, 1) )
   3.116  		return -EFAULT;
   3.117 @@ -580,6 +673,43 @@ long do_mca(XEN_GUEST_HANDLE(xen_mc_t) u
   3.118  
   3.119  		spin_unlock(&mc_notify_lock);
   3.120  		break;
   3.121 +
   3.122 +       case XEN_MC_physcpuinfo:
   3.123 +	       if ( !IS_PRIV(v->domain) )
   3.124 +		       return -EPERM;
   3.125 + 
   3.126 +	       mc_physcpuinfo = &op->u.mc_physcpuinfo;
   3.127 +	       nlcpu = num_online_cpus();
   3.128 + 
   3.129 +	       if (!guest_handle_is_null(mc_physcpuinfo->info)) {
   3.130 +		       if (mc_physcpuinfo->ncpus <= 0)
   3.131 +			       return -EINVAL;
   3.132 +		       nlcpu = min(nlcpu, (int)mc_physcpuinfo->ncpus);
   3.133 +		       log_cpus = xmalloc_array(xen_mc_logical_cpu_t, nlcpu);
   3.134 +		       if (log_cpus == NULL)
   3.135 +			       return -ENOMEM;
   3.136 + 
   3.137 +		       if (on_each_cpu(do_mc_get_cpu_info, log_cpus,
   3.138 +			   1, 1) != 0) {
   3.139 +			       xfree(log_cpus);
   3.140 +			       return -EIO;
   3.141 +		       }
   3.142 +	       }
   3.143 + 
   3.144 +	       mc_physcpuinfo->ncpus = nlcpu;
   3.145 + 
   3.146 +	       if (copy_to_guest(u_xen_mc, op, 1)) {
   3.147 +		       if (log_cpus != NULL)
   3.148 +			       xfree(log_cpus);
   3.149 +		       return -EFAULT;
   3.150 +	       }
   3.151 + 
   3.152 +	       if (!guest_handle_is_null(mc_physcpuinfo->info)) {
   3.153 +		       if (copy_to_guest(mc_physcpuinfo->info,
   3.154 +			   log_cpus, nlcpu))
   3.155 +			       ret = -EFAULT;
   3.156 +		       xfree(log_cpus);
   3.157 +	       }
   3.158  	}
   3.159  
   3.160  	return ret;
     4.1 --- a/xen/arch/x86/cpu/mcheck/mce.h	Tue Feb 10 05:47:00 2009 +0000
     4.2 +++ b/xen/arch/x86/cpu/mcheck/mce.h	Tue Feb 10 05:51:00 2009 +0000
     4.3 @@ -34,4 +34,5 @@ void x86_mcinfo_clear(struct mc_info *mi
     4.4  int x86_mcinfo_add(struct mc_info *mi, void *mcinfo);
     4.5  void x86_mcinfo_dump(struct mc_info *mi);
     4.6  void mc_panic(char *s);
     4.7 -
     4.8 +void x86_mc_get_cpu_info(unsigned, uint32_t *, uint16_t *, uint16_t *,
     4.9 +			 uint32_t *, uint32_t *, uint32_t *, uint32_t *);
     5.1 --- a/xen/arch/x86/cpu/mcheck/mce_intel.c	Tue Feb 10 05:47:00 2009 +0000
     5.2 +++ b/xen/arch/x86/cpu/mcheck/mce_intel.c	Tue Feb 10 05:51:00 2009 +0000
     5.3 @@ -182,11 +182,9 @@ static struct mc_info *machine_check_pol
     5.4          mcg.mc_flags = MC_FLAG_POLLED;
     5.5      else if (calltype == MC_FLAG_CMCI)
     5.6          mcg.mc_flags = MC_FLAG_CMCI;
     5.7 -    mcg.mc_socketid = phys_proc_id[cpu];
     5.8 -    mcg.mc_coreid = cpu_core_id[cpu];
     5.9 -    mcg.mc_apicid = cpu_physical_id(cpu);
    5.10 -    mcg.mc_core_threadid =
    5.11 -        mcg.mc_apicid & ( 1 << (cpu_data[cpu].x86_num_siblings - 1)); 
    5.12 +    x86_mc_get_cpu_info(
    5.13 +        cpu, &mcg.mc_socketid, &mcg.mc_coreid,
    5.14 +        &mcg.mc_core_threadid, &mcg.mc_apicid, NULL, NULL, NULL);
    5.15      rdmsrl(MSR_IA32_MCG_STATUS, mcg.mc_gstatus);
    5.16  
    5.17      for ( i = 0; i < nr_mce_banks; i++ ) {
     6.1 --- a/xen/include/public/arch-x86/xen-mca.h	Tue Feb 10 05:47:00 2009 +0000
     6.2 +++ b/xen/include/public/arch-x86/xen-mca.h	Tue Feb 10 05:51:00 2009 +0000
     6.3 @@ -56,7 +56,7 @@
     6.4  /* Hypercall */
     6.5  #define __HYPERVISOR_mca __HYPERVISOR_arch_0
     6.6  
     6.7 -#define XEN_MCA_INTERFACE_VERSION 0x03000001
     6.8 +#define XEN_MCA_INTERFACE_VERSION 0x03000002
     6.9  
    6.10  /* IN: Dom0 calls hypercall from MC event handler. */
    6.11  #define XEN_MC_CORRECTABLE  0x0
    6.12 @@ -118,7 +118,7 @@ struct mcinfo_global {
    6.13      uint16_t mc_domid;
    6.14      uint32_t mc_socketid; /* physical socket of the physical core */
    6.15      uint16_t mc_coreid; /* physical impacted core */
    6.16 -    uint8_t  mc_apicid;
    6.17 +    uint32_t mc_apicid;
    6.18      uint16_t mc_core_threadid; /* core thread of physical core */
    6.19      uint16_t mc_vcpuid; /* virtual cpu scheduled for mc_domid */
    6.20      uint64_t mc_gstatus; /* global status */
    6.21 @@ -175,6 +175,41 @@ struct mc_info {
    6.22  };
    6.23  typedef struct mc_info mc_info_t;
    6.24  
    6.25 +#define __MC_MSR_ARRAYSIZE 8
    6.26 +#define __MC_NMSRS 1
    6.27 +#define MC_NCAPS	7	/* 7 CPU feature flag words */
    6.28 +#define MC_CAPS_STD_EDX	0	/* cpuid level 0x00000001 (%edx) */
    6.29 +#define MC_CAPS_AMD_EDX	1	/* cpuid level 0x80000001 (%edx) */
    6.30 +#define MC_CAPS_TM	2	/* cpuid level 0x80860001 (TransMeta) */
    6.31 +#define MC_CAPS_LINUX	3	/* Linux-defined */
    6.32 +#define MC_CAPS_STD_ECX	4	/* cpuid level 0x00000001 (%ecx) */
    6.33 +#define MC_CAPS_VIA	5	/* cpuid level 0xc0000001 */
    6.34 +#define MC_CAPS_AMD_ECX	6	/* cpuid level 0x80000001 (%ecx) */
    6.35 +
    6.36 +typedef struct mcinfo_logical_cpu {
    6.37 +    uint32_t mc_cpunr;          
    6.38 +    uint32_t mc_chipid; 
    6.39 +    uint16_t mc_coreid;
    6.40 +    uint16_t mc_threadid;
    6.41 +    uint32_t mc_apicid;
    6.42 +    uint32_t mc_clusterid;
    6.43 +    uint32_t mc_ncores;
    6.44 +    uint32_t mc_ncores_active;
    6.45 +    uint32_t mc_nthreads;
    6.46 +    int32_t mc_cpuid_level;
    6.47 +    uint32_t mc_family;
    6.48 +    uint32_t mc_vendor;
    6.49 +    uint32_t mc_model;
    6.50 +    uint32_t mc_step;
    6.51 +    char mc_vendorid[16];
    6.52 +    char mc_brandid[64];
    6.53 +    uint32_t mc_cpu_caps[MC_NCAPS];
    6.54 +    uint32_t mc_cache_size;
    6.55 +    uint32_t mc_cache_alignment;
    6.56 +    int32_t mc_nmsrvals;
    6.57 +    struct mcinfo_msr mc_msrvalues[__MC_MSR_ARRAYSIZE];
    6.58 +} xen_mc_logical_cpu_t;
    6.59 +DEFINE_XEN_GUEST_HANDLE(xen_mc_logical_cpu_t);
    6.60  
    6.61  
    6.62  /* 
    6.63 @@ -272,6 +307,14 @@ struct xen_mc_notifydomain {
    6.64  typedef struct xen_mc_notifydomain xen_mc_notifydomain_t;
    6.65  DEFINE_XEN_GUEST_HANDLE(xen_mc_notifydomain_t);
    6.66  
    6.67 +#define XEN_MC_physcpuinfo 3
    6.68 +struct xen_mc_physcpuinfo {
    6.69 +	/* IN/OUT */
    6.70 +	uint32_t ncpus;
    6.71 +	uint32_t pad0;
    6.72 +	/* OUT */
    6.73 +	XEN_GUEST_HANDLE(xen_mc_logical_cpu_t) info;
    6.74 +};
    6.75  
    6.76  struct xen_mc {
    6.77      uint32_t cmd;
    6.78 @@ -279,6 +322,7 @@ struct xen_mc {
    6.79      union {
    6.80          struct xen_mc_fetch        mc_fetch;
    6.81          struct xen_mc_notifydomain mc_notifydomain;
    6.82 +        struct xen_mc_physcpuinfo  mc_physcpuinfo;
    6.83          uint8_t pad[MCINFO_HYPERCALLSIZE];
    6.84      } u;
    6.85  };