[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH RFC 27/31] xen/x86: Rework Intel masking/faulting setup
This patch is best reviewed as its end result rather than as a diff, as it rewrites almost all of the setup. On the BSP, cpuid information is used to evaluate the potential available set of masking MSRs, and they are unconditionally probed, filling in the availability information and hardware defaults. A side effect of this is that probe_intel_cpuid_faulting() can move to being __init. The command line parameters are then combined with the hardware defaults to further restrict the Xen default masking level. Each cpu is then context switched into the default levelling state. Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> --- CC: Jan Beulich <JBeulich@xxxxxxxx> --- xen/arch/x86/cpu/intel.c | 219 ++++++++++++++++++++++++++++------------------- 1 file changed, 132 insertions(+), 87 deletions(-) diff --git a/xen/arch/x86/cpu/intel.c b/xen/arch/x86/cpu/intel.c index d251b53..f1bb222 100644 --- a/xen/arch/x86/cpu/intel.c +++ b/xen/arch/x86/cpu/intel.c @@ -18,11 +18,18 @@ #define select_idle_routine(x) ((void)0) -static unsigned int probe_intel_cpuid_faulting(void) +static bool_t __init probe_intel_cpuid_faulting(void) { uint64_t x; - return !rdmsr_safe(MSR_INTEL_PLATFORM_INFO, x) && - (x & MSR_PLATFORM_INFO_CPUID_FAULTING); + + if ( rdmsr_safe(MSR_INTEL_PLATFORM_INFO, x) || + !(x & MSR_PLATFORM_INFO_CPUID_FAULTING) ) + return 0; + + expected_levelling_cap |= LCAP_faulting; + levelling_caps |= LCAP_faulting; + __set_bit(X86_FEATURE_CPUID_FAULTING, boot_cpu_data.x86_capability); + return 1; } static DEFINE_PER_CPU(bool_t, cpuid_faulting_enabled); @@ -44,41 +51,45 @@ void set_cpuid_faulting(bool_t enable) } /* - * opt_cpuid_mask_ecx/edx: cpuid.1[ecx, edx] feature mask. - * For example, E8400[Intel Core 2 Duo Processor series] ecx = 0x0008E3FD, - * edx = 0xBFEBFBFF when executing CPUID.EAX = 1 normally. If you want to - * 'rev down' to E8400, you can set these values in these Xen boot parameters. + * Set caps in expected_levelling_cap, probe a specific masking MSR, and set + * caps in levelling_caps if it is found, or clobber the MSR index if missing. + * If preset, reads the default value into msr_val. */ -static void __devinit set_cpuidmask(const struct cpuinfo_x86 *c) +static void __init __probe_mask_msr(unsigned int *msr, uint64_t caps, + uint64_t *msr_val) { - static unsigned int msr_basic, msr_ext, msr_xsave; - static enum { not_parsed, no_mask, set_mask } status; - u64 msr_val; + uint64_t val; - if (status == no_mask) - return; + expected_levelling_cap |= caps; - if (status == set_mask) - goto setmask; + if (rdmsr_safe(*msr, val) || wrmsr_safe(*msr, val)) + *msr = 0; + else + { + levelling_caps |= caps; + *msr_val = val; + } +} - ASSERT((status == not_parsed) && (c == &boot_cpu_data)); - status = no_mask; +static unsigned int __read_mostly msr_basic, msr_ext, msr_xsave; - if (!~(opt_cpuid_mask_ecx & opt_cpuid_mask_edx & - opt_cpuid_mask_ext_ecx & opt_cpuid_mask_ext_edx & - opt_cpuid_mask_xsave_eax)) - return; +/* + * Probe for the existance of the expected masking MSRs. They might easily + * not be available if Xen is running virtualised. + */ +static void __init probe_masking_msrs(void) +{ + const struct cpuinfo_x86 *c = &boot_cpu_data; + unsigned int exp_msr_basic = 0, exp_msr_ext = 0, exp_msr_xsave = 0; /* Only family 6 supports this feature. */ - if (c->x86 != 6) { - printk("No CPUID feature masking support available\n"); + if (c->x86 != 6) return; - } switch (c->x86_model) { case 0x17: /* Yorkfield, Wolfdale, Penryn, Harpertown(DP) */ case 0x1d: /* Dunnington(MP) */ - msr_basic = MSR_INTEL_MASK_V1_CPUID1; + exp_msr_basic = msr_basic = MSR_INTEL_MASK_V1_CPUID1; break; case 0x1a: /* Bloomfield, Nehalem-EP(Gainestown) */ @@ -88,72 +99,115 @@ static void __devinit set_cpuidmask(const struct cpuinfo_x86 *c) case 0x2c: /* Gulftown, Westmere-EP */ case 0x2e: /* Nehalem-EX(Beckton) */ case 0x2f: /* Westmere-EX */ - msr_basic = MSR_INTEL_MASK_V2_CPUID1; - msr_ext = MSR_INTEL_MASK_V2_CPUID80000001; + exp_msr_basic = msr_basic = MSR_INTEL_MASK_V2_CPUID1; + exp_msr_ext = msr_ext = MSR_INTEL_MASK_V2_CPUID80000001; break; case 0x2a: /* SandyBridge */ case 0x2d: /* SandyBridge-E, SandyBridge-EN, SandyBridge-EP */ - msr_basic = MSR_INTEL_MASK_V3_CPUID1; - msr_ext = MSR_INTEL_MASK_V3_CPUID80000001; - msr_xsave = MSR_INTEL_MASK_V3_CPUIDD_01; + exp_msr_basic = msr_basic = MSR_INTEL_MASK_V3_CPUID1; + exp_msr_ext = msr_ext = MSR_INTEL_MASK_V3_CPUID80000001; + exp_msr_xsave = msr_xsave = MSR_INTEL_MASK_V3_CPUIDD_01; break; } - status = set_mask; + if (msr_basic) + __probe_mask_msr(&msr_basic, LCAP_1cd, &cpumask_defaults._1cd); + + if (msr_ext) + __probe_mask_msr(&msr_ext, LCAP_e1cd, &cpumask_defaults.e1cd); + + if (msr_xsave) + __probe_mask_msr(&msr_xsave, LCAP_Da1, &cpumask_defaults.Da1); + + /* + * Don't bother warning about a mismatch if virtualised. These MSRs + * are not architectural and almost never virtualised. + */ + if ((expected_levelling_cap == levelling_caps) || + cpu_has_hypervisor) + return; + + printk(XENLOG_WARNING "Mismatch between expected (%#x" + ") and real (%#x) levelling caps: missing %#x\n", + expected_levelling_cap, levelling_caps, + (expected_levelling_cap ^ levelling_caps) & levelling_caps); + printk(XENLOG_WARNING "Fam %#x, model %#x expected (%#x/%#x/%#x), " + "got (%#x/%#x/%#x)\n", c->x86, c->x86_model, + exp_msr_basic, exp_msr_ext, exp_msr_xsave, + msr_basic, msr_ext, msr_xsave); + printk(XENLOG_WARNING + "If not running virtualised, please report a bug\n"); +} + +void intel_ctxt_switch_levelling(const struct domain *nextd) +{ + struct cpumasks *these_masks = &this_cpu(cpumasks); + const struct cpumasks *masks = &cpumask_defaults; + +#define LAZY(msr, field) \ + ({ \ + if ( msr && (these_masks->field != masks->field) ) \ + { \ + wrmsrl(msr, masks->field); \ + these_masks->field = masks->field; \ + } \ + }) + + LAZY(msr_basic, _1cd); + LAZY(msr_ext, e1cd); + LAZY(msr_xsave, Da1); + +#undef LAZY +} - if (~(opt_cpuid_mask_ecx & opt_cpuid_mask_edx)) { - if (msr_basic) +/* + * opt_cpuid_mask_ecx/edx: cpuid.1[ecx, edx] feature mask. + * For example, E8400[Intel Core 2 Duo Processor series] ecx = 0x0008E3FD, + * edx = 0xBFEBFBFF when executing CPUID.EAX = 1 normally. If you want to + * 'rev down' to E8400, you can set these values in these Xen boot parameters. + */ +static void __init noinline intel_init_levelling(void) +{ + if ( !probe_intel_cpuid_faulting() ) + probe_masking_msrs(); + + if ( msr_basic ) + { + cpumask_defaults._1cd = + ((u64)opt_cpuid_mask_edx << 32) | opt_cpuid_mask_ecx; + + if ( !~(opt_cpuid_mask_ecx & opt_cpuid_mask_edx) ) printk("Writing CPUID feature mask ecx:edx -> %08x:%08x\n", opt_cpuid_mask_ecx, opt_cpuid_mask_edx); - else - printk("No CPUID feature mask available\n"); } - else - msr_basic = 0; + else if ( !~(opt_cpuid_mask_ecx & opt_cpuid_mask_edx) ) + printk("No CPUID feature mask available\n"); + + if ( msr_ext ) + { + cpumask_defaults.e1cd = + ((u64)opt_cpuid_mask_ext_edx << 32) | + opt_cpuid_mask_ext_ecx; - if (~(opt_cpuid_mask_ext_ecx & opt_cpuid_mask_ext_edx)) { - if (msr_ext) + if ( !~(opt_cpuid_mask_ext_ecx & opt_cpuid_mask_ext_edx) ) printk("Writing CPUID extended feature mask ecx:edx -> %08x:%08x\n", opt_cpuid_mask_ext_ecx, opt_cpuid_mask_ext_edx); - else - printk("No CPUID extended feature mask available\n"); } - else - msr_ext = 0; + else if ( !~(opt_cpuid_mask_ext_ecx & opt_cpuid_mask_ext_edx) ) + printk("No CPUID extended feature mask available\n"); + + if ( msr_xsave ) + { + cpumask_defaults.Da1 &= (~0ULL << 32); + cpumask_defaults.Da1 |= opt_cpuid_mask_xsave_eax; - if (~opt_cpuid_mask_xsave_eax) { - if (msr_xsave) + if ( !~opt_cpuid_mask_xsave_eax ) printk("Writing CPUID xsave feature mask eax -> %08x\n", opt_cpuid_mask_xsave_eax); - else - printk("No CPUID xsave feature mask available\n"); - } - else - msr_xsave = 0; - - setmask: - if (msr_basic && - wrmsr_safe(msr_basic, - ((u64)opt_cpuid_mask_edx << 32) | opt_cpuid_mask_ecx)){ - msr_basic = 0; - printk("Failed to set CPUID feature mask\n"); - } - - if (msr_ext && - wrmsr_safe(msr_ext, - ((u64)opt_cpuid_mask_ext_edx << 32) | opt_cpuid_mask_ext_ecx)){ - msr_ext = 0; - printk("Failed to set CPUID extended feature mask\n"); - } - - if (msr_xsave && - (rdmsr_safe(msr_xsave, msr_val) || - wrmsr_safe(msr_xsave, - (msr_val & (~0ULL << 32)) | opt_cpuid_mask_xsave_eax))){ - msr_xsave = 0; - printk("Failed to set CPUID xsave feature mask\n"); } + else if ( !~opt_cpuid_mask_xsave_eax ) + printk("No CPUID xsave feature mask available\n"); } static void early_init_intel(struct cpuinfo_x86 *c) @@ -183,22 +237,13 @@ static void early_init_intel(struct cpuinfo_x86 *c) (boot_cpu_data.x86_mask == 3 || boot_cpu_data.x86_mask == 4)) paddr_bits = 36; - if (c == &boot_cpu_data && c->x86 == 6) { - if (probe_intel_cpuid_faulting()) - __set_bit(X86_FEATURE_CPUID_FAULTING, - c->x86_capability); - } else if (boot_cpu_has(X86_FEATURE_CPUID_FAULTING)) { - BUG_ON(!probe_intel_cpuid_faulting()); - __set_bit(X86_FEATURE_CPUID_FAULTING, c->x86_capability); - } + if (c == &boot_cpu_data) + intel_init_levelling(); + + if (test_bit(X86_FEATURE_CPUID_FAULTING, boot_cpu_data.x86_capability)) + __set_bit(X86_FEATURE_CPUID_FAULTING, c->x86_capability); - if (!cpu_has_cpuid_faulting) - set_cpuidmask(c); - else if ((c == &boot_cpu_data) && - (~(opt_cpuid_mask_ecx & opt_cpuid_mask_edx & - opt_cpuid_mask_ext_ecx & opt_cpuid_mask_ext_edx & - opt_cpuid_mask_xsave_eax))) - printk("No CPUID feature masking support available\n"); + intel_ctxt_switch_levelling(NULL); } /* -- 2.1.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |