All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andrew Cooper <andrew.cooper3@citrix.com>
To: Xen-devel <xen-devel@lists.xen.org>
Cc: Andrew Cooper <andrew.cooper3@citrix.com>,
	Jan Beulich <JBeulich@suse.com>
Subject: [PATCH RFC 26/31] xen/x86: Rework AMD masking MSR setup
Date: Wed, 16 Dec 2015 21:24:28 +0000	[thread overview]
Message-ID: <1450301073-28191-27-git-send-email-andrew.cooper3@citrix.com> (raw)
In-Reply-To: <1450301073-28191-1-git-send-email-andrew.cooper3@citrix.com>

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.

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@citrix.com>
---
CC: Jan Beulich <JBeulich@suse.com>
---
 xen/arch/x86/cpu/amd.c | 250 ++++++++++++++++++++++++++++++-------------------
 1 file changed, 153 insertions(+), 97 deletions(-)

diff --git a/xen/arch/x86/cpu/amd.c b/xen/arch/x86/cpu/amd.c
index 265fbc0..6b95ab6 100644
--- a/xen/arch/x86/cpu/amd.c
+++ b/xen/arch/x86/cpu/amd.c
@@ -80,6 +80,13 @@ static inline int wrmsr_amd_safe(unsigned int msr, unsigned int lo,
 	return err;
 }
 
+static void wrmsr_amd(unsigned int msr, uint64_t val)
+{
+	asm volatile("wrmsr" ::
+		     "c" (msr), "a" ((uint32_t)val),
+		     "d" (val >> 32), "D" (0x9c5a203a));
+}
+
 static const struct cpuidmask {
 	uint16_t fam;
 	char rev[2];
@@ -126,126 +133,172 @@ static const struct cpuidmask *__init noinline get_cpuidmask(const char *opt)
 }
 
 /*
- * Mask the features and extended features returned by CPUID.  Parameters are
- * set from the boot line via two methods:
- *
- *   1) Specific processor revision string
- *   2) User-defined masks
- *
- * The processor revision string parameter has precedene.
+ * Sets caps in expected_levelling_cap, probes for the specified mask MSR, and
+ * set caps in levelling_caps if it is found.  Processors prior to Fam 10h
+ * required a 32-bit password for masking MSRs.  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 feat_ecx, feat_edx;
-	static unsigned int extfeat_ecx, extfeat_edx;
-	static unsigned int l7s0_eax, l7s0_ebx;
-	static unsigned int thermal_ecx;
-	static bool_t skip_feat, skip_extfeat;
-	static bool_t skip_l7s0_eax_ebx, skip_thermal_ecx;
-	static enum { not_parsed, no_mask, set_mask } status;
-	unsigned int eax, ebx, ecx, edx;
-
-	if (status == no_mask)
-		return;
+	unsigned int hi, lo;
+
+        expected_levelling_cap |= caps;
+
+	if ((rdmsr_amd_safe(msr, &lo, &hi) == 0) &&
+	    (wrmsr_amd_safe(msr, lo, hi) == 0))
+		levelling_caps |= caps;
+
+	*msr_val = ((uint64_t)hi << 32) | lo;
+}
 
-	if (status == set_mask)
-		goto setmask;
+/*
+ * Probe for the existance of the expected masking MSRs.  They might easily
+ * not be available if Xen is running virtualised.
+ */
+static void __init noinline probe_masking_msrs(void)
+{
+	const struct cpuinfo_x86 *c = &boot_cpu_data;
 
-	ASSERT((status == not_parsed) && (c == &boot_cpu_data));
-	status = no_mask;
+	/*
+	 * First, work out which masking MSRs we should have, based on
+	 * revision and cpuid.
+	 */
 
 	/* Fam11 doesn't support masking at all. */
 	if (c->x86 == 0x11)
 		return;
 
-	if (~(opt_cpuid_mask_ecx & opt_cpuid_mask_edx &
-	      opt_cpuid_mask_ext_ecx & opt_cpuid_mask_ext_edx &
-	      opt_cpuid_mask_l7s0_eax & opt_cpuid_mask_l7s0_ebx &
-	      opt_cpuid_mask_thermal_ecx)) {
-		feat_ecx = opt_cpuid_mask_ecx;
-		feat_edx = opt_cpuid_mask_edx;
-		extfeat_ecx = opt_cpuid_mask_ext_ecx;
-		extfeat_edx = opt_cpuid_mask_ext_edx;
-		l7s0_eax = opt_cpuid_mask_l7s0_eax;
-		l7s0_ebx = opt_cpuid_mask_l7s0_ebx;
-		thermal_ecx = opt_cpuid_mask_thermal_ecx;
-	} else if (*opt_famrev == '\0') {
+	__probe_mask_msr(MSR_K8_FEATURE_MASK, LCAP_1cd,
+			 &cpumask_defaults._1cd);
+	__probe_mask_msr(MSR_K8_EXT_FEATURE_MASK, LCAP_e1cd,
+			 &cpumask_defaults.e1cd);
+
+	if (c->cpuid_level >= 7)
+		__probe_mask_msr(MSR_AMD_L7S0_FEATURE_MASK, LCAP_7ab0,
+				 &cpumask_defaults._7ab0);
+
+	if (c->x86 == 0x15 && c->cpuid_level >= 6 && cpuid_ecx(6))
+		__probe_mask_msr(MSR_AMD_THRM_FEATURE_MASK, LCAP_6c,
+				 &cpumask_defaults._6c);
+
+	/*
+	 * 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;
-	} else {
-		const struct cpuidmask *m = get_cpuidmask(opt_famrev);
+
+	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 level %#x\n",
+	       c->x86, c->x86_model, c->cpuid_level);
+	printk(XENLOG_WARNING
+	       "If not running virtualised, please report a bug\n");
+}
+
+void amd_ctxt_switch_levelling(const struct domain *nextd)
+{
+	struct cpumasks *these_masks = &this_cpu(cpumasks);
+	const struct cpumasks *masks = &cpumask_defaults;
+
+#define LAZY(cap, msr, field)						\
+	({								\
+		if ( ((levelling_caps & cap) == cap) &&			\
+		     (these_masks->field != masks->field) )		\
+		{							\
+			wrmsr_amd(msr, masks->field);			\
+			these_masks->field = masks->field;		\
+		}							\
+	})
+
+	LAZY(LCAP_1cd,  MSR_K8_FEATURE_MASK,       _1cd);
+	LAZY(LCAP_e1cd, MSR_K8_EXT_FEATURE_MASK,   e1cd);
+	LAZY(LCAP_7ab0, MSR_AMD_L7S0_FEATURE_MASK, _7ab0);
+	LAZY(LCAP_6c,   MSR_AMD_THRM_FEATURE_MASK, _6c);
+
+#undef LAZY
+}
+
+/*
+ * Mask the features and extended features returned by CPUID.  Parameters are
+ * set from the boot line via two methods:
+ *
+ *   1) Specific processor revision string
+ *   2) User-defined masks
+ *
+ * The processor revision string parameter has precedence.
+ */
+static void __init noinline amd_init_levelling(void)
+{
+	const struct cpuidmask *m = NULL;
+
+	probe_masking_msrs();
+
+	if (*opt_famrev != '\0') {
+		m = get_cpuidmask(opt_famrev);
 
 		if (!m) {
 			printk("Invalid processor string: %s\n", opt_famrev);
-			printk("CPUID will not be masked\n");
-			return;
 		}
-		feat_ecx = m->ecx;
-		feat_edx = m->edx;
-		extfeat_ecx = m->ext_ecx;
-		extfeat_edx = m->ext_edx;
 	}
 
-        /* Setting bits in the CPUID mask MSR that are not set in the
-         * unmasked CPUID response can cause those bits to be set in the
-         * masked response.  Avoid that by explicitly masking in software. */
-        feat_ecx &= cpuid_ecx(0x00000001);
-        feat_edx &= cpuid_edx(0x00000001);
-        extfeat_ecx &= cpuid_ecx(0x80000001);
-        extfeat_edx &= cpuid_edx(0x80000001);
+	if ((levelling_caps & LCAP_1cd) == LCAP_1cd) {
+		uint32_t ecx, edx, tmp;
 
-	status = set_mask;
-	printk("Writing CPUID feature mask ECX:EDX -> %08Xh:%08Xh\n", 
-	       feat_ecx, feat_edx);
-	printk("Writing CPUID extended feature mask ECX:EDX -> %08Xh:%08Xh\n", 
-	       extfeat_ecx, extfeat_edx);
+		cpuid(0x00000001, &tmp, &tmp, &ecx, &edx);
 
-	if (c->cpuid_level >= 7)
-		cpuid_count(7, 0, &eax, &ebx, &ecx, &edx);
-	else
-		ebx = eax = 0;
-	if ((eax | ebx) && ~(l7s0_eax & l7s0_ebx)) {
-		if (l7s0_eax > eax)
-			l7s0_eax = eax;
-		l7s0_ebx &= ebx;
-		printk("Writing CPUID leaf 7 subleaf 0 feature mask EAX:EBX -> %08Xh:%08Xh\n",
-		       l7s0_eax, l7s0_ebx);
-	} else
-		skip_l7s0_eax_ebx = 1;
-
-	/* Only Fam15 has the respective MSR. */
-	ecx = c->x86 == 0x15 && c->cpuid_level >= 6 ? cpuid_ecx(6) : 0;
-	if (ecx && ~thermal_ecx) {
-		thermal_ecx &= ecx;
-		printk("Writing CPUID thermal/power feature mask ECX -> %08Xh\n",
-		       thermal_ecx);
-	} else
-		skip_thermal_ecx = 1;
-
- setmask:
-	/* AMD processors prior to family 10h required a 32-bit password */
-	if (!skip_feat &&
-	    wrmsr_amd_safe(MSR_K8_FEATURE_MASK, feat_edx, feat_ecx)) {
-		skip_feat = 1;
-		printk("Failed to set CPUID feature mask\n");
+		if(~(opt_cpuid_mask_ecx & opt_cpuid_mask_edx)) {
+			ecx &= opt_cpuid_mask_ecx;
+			edx &= opt_cpuid_mask_edx;
+		} else if ( m ) {
+			ecx &= m->ecx;
+			edx &= m->edx;
+		}
+
+		cpumask_defaults._1cd = ((uint64_t)ecx << 32) | edx;
 	}
 
-	if (!skip_extfeat &&
-	    wrmsr_amd_safe(MSR_K8_EXT_FEATURE_MASK, extfeat_edx, extfeat_ecx)) {
-		skip_extfeat = 1;
-		printk("Failed to set CPUID extended feature mask\n");
+	if ((levelling_caps & LCAP_e1cd) == LCAP_e1cd) {
+		uint32_t ecx, edx, tmp;
+
+		cpuid(0x80000001, &tmp, &tmp, &ecx, &edx);
+
+		if(~(opt_cpuid_mask_ext_ecx & opt_cpuid_mask_ext_edx)) {
+			ecx &= opt_cpuid_mask_ext_ecx;
+			edx &= opt_cpuid_mask_ext_edx;
+		} else if ( m ) {
+			ecx &= m->ext_ecx;
+			edx &= m->ext_edx;
+		}
+
+		cpumask_defaults.e1cd = ((uint64_t)ecx << 32) | edx;
 	}
 
-	if (!skip_l7s0_eax_ebx &&
-	    wrmsr_amd_safe(MSR_AMD_L7S0_FEATURE_MASK, l7s0_ebx, l7s0_eax)) {
-		skip_l7s0_eax_ebx = 1;
-		printk("Failed to set CPUID leaf 7 subleaf 0 feature mask\n");
+	if ((levelling_caps & LCAP_7ab0) == LCAP_7ab0) {
+		uint32_t eax, ebx, tmp;
+
+		cpuid(0x00000007, &eax, &ebx, &tmp, &tmp);
+
+		if(~(opt_cpuid_mask_l7s0_eax & opt_cpuid_mask_l7s0_ebx)) {
+			eax &= opt_cpuid_mask_l7s0_eax;
+			ebx &= opt_cpuid_mask_l7s0_ebx;
+		}
+
+		cpumask_defaults._7ab0 = ((uint64_t)eax << 32) | ebx;
 	}
 
-	if (!skip_thermal_ecx &&
-	    (rdmsr_amd_safe(MSR_AMD_THRM_FEATURE_MASK, &eax, &edx) ||
-	     wrmsr_amd_safe(MSR_AMD_THRM_FEATURE_MASK, thermal_ecx, edx))){
-		skip_thermal_ecx = 1;
-		printk("Failed to set CPUID thermal/power feature mask\n");
+	if ((levelling_caps & LCAP_6c) == LCAP_6c) {
+		uint32_t ecx = cpuid_ecx(6);
+
+		if (~opt_cpuid_mask_thermal_ecx)
+			ecx &= opt_cpuid_mask_thermal_ecx;
+
+		cpumask_defaults._6c &= (~0ULL << 32);
+		cpumask_defaults._6c |= ecx;
 	}
 }
 
@@ -426,7 +479,10 @@ static void __devinit amd_get_topology(struct cpuinfo_x86 *c)
 
 static void __devinit early_init_amd(struct cpuinfo_x86 *c)
 {
-	set_cpuidmask(c);
+	if (c == &boot_cpu_data)
+		amd_init_levelling();
+
+	amd_ctxt_switch_levelling(NULL);
 }
 
 static void __devinit init_amd(struct cpuinfo_x86 *c)
-- 
2.1.4

  parent reply	other threads:[~2015-12-16 21:24 UTC|newest]

Thread overview: 123+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-12-16 21:24 [PATCH RFC 00/31] x86: Improvements to cpuid handling for guests Andrew Cooper
2015-12-16 21:24 ` [PATCH RFC 01/31] xen/public: Export featureset information in the public API Andrew Cooper
2015-12-22 16:28   ` Jan Beulich
2015-12-22 16:42     ` Andrew Cooper
2015-12-22 16:59       ` Jan Beulich
2015-12-23 10:05         ` Andrew Cooper
2015-12-23 10:24           ` Jan Beulich
2015-12-23 11:26             ` Andrew Cooper
2016-01-06  7:43               ` Jan Beulich
2015-12-16 21:24 ` [PATCH RFC 02/31] tools/libxc: Use public/featureset.h for cpuid policy generation Andrew Cooper
2015-12-22 16:29   ` Jan Beulich
2016-01-05 14:13     ` Ian Campbell
2016-01-05 14:17       ` Andrew Cooper
2016-01-05 14:18         ` Ian Campbell
2016-01-05 14:23           ` Andrew Cooper
2016-01-05 15:02             ` Ian Campbell
2016-01-05 15:42               ` Andrew Cooper
2016-01-05 16:09                 ` Ian Campbell
2015-12-16 21:24 ` [PATCH RFC 03/31] xen/x86: Store antifeatures inverted in a featureset Andrew Cooper
2015-12-22 16:32   ` Jan Beulich
2015-12-22 17:03     ` Andrew Cooper
2016-01-05 14:19       ` Ian Campbell
2016-01-05 14:24         ` Andrew Cooper
2015-12-16 21:24 ` [PATCH RFC 04/31] xen/x86: Mask out unknown features from Xen's capabilities Andrew Cooper
2015-12-22 16:42   ` Jan Beulich
2015-12-22 17:01     ` Andrew Cooper
2015-12-16 21:24 ` [PATCH RFC 05/31] xen/x86: Collect more CPUID feature words Andrew Cooper
2015-12-22 16:46   ` Jan Beulich
2015-12-22 17:17     ` Andrew Cooper
2015-12-16 21:24 ` [PATCH RFC 06/31] xen/x86: Infrastructure to calculate guest featuresets Andrew Cooper
2015-12-22 16:50   ` Jan Beulich
2015-12-16 21:24 ` [PATCH RFC 07/31] xen/x86: Export host featureset via SYSCTL Andrew Cooper
2015-12-22 16:57   ` Jan Beulich
2015-12-16 21:24 ` [PATCH RFC 08/31] tools/stubs: Expose host featureset to userspace Andrew Cooper
2016-01-05 15:36   ` Ian Campbell
2016-01-05 15:59     ` Andrew Cooper
2016-01-05 16:09       ` Ian Campbell
2016-01-05 16:19         ` Andrew Cooper
2016-01-05 16:38           ` Ian Campbell
2015-12-16 21:24 ` [PATCH RFC 09/31] xen/x86: Calculate PV featureset Andrew Cooper
2015-12-22 17:07   ` Jan Beulich
2015-12-22 17:13     ` Andrew Cooper
2015-12-22 17:18       ` Jan Beulich
2015-12-16 21:24 ` [PATCH RFC 10/31] xen/x86: Calculate HVM featureset Andrew Cooper
2015-12-22 17:11   ` Jan Beulich
2015-12-22 17:21     ` Andrew Cooper
2015-12-16 21:24 ` [PATCH RFC 11/31] xen/x86: Calculate Raw featureset Andrew Cooper
2015-12-22 17:14   ` Jan Beulich
2015-12-22 17:27     ` Andrew Cooper
2015-12-16 21:24 ` [PATCH RFC 12/31] tools: Utility for dealing with featuresets Andrew Cooper
2016-01-05 15:17   ` Ian Campbell
2016-01-05 16:14     ` Andrew Cooper
2016-01-05 16:34       ` Ian Campbell
2016-01-05 17:13         ` Andrew Cooper
2016-01-05 17:37           ` Ian Campbell
2016-01-05 18:04             ` Andrew Cooper
2016-01-06 10:38               ` Ian Campbell
2016-01-06 10:40   ` Ian Campbell
2016-01-06 10:42     ` Ian Campbell
2015-12-16 21:24 ` [PATCH RFC 13/31] tools/libxc: Wire a featureset through to cpuid policy logic Andrew Cooper
2016-01-05 15:42   ` Ian Campbell
2016-01-05 16:20     ` Andrew Cooper
2015-12-16 21:24 ` [PATCH RFC 14/31] tools/libxc: Use featureset rather than guesswork Andrew Cooper
2016-01-05 15:54   ` Ian Campbell
2016-01-05 16:22     ` Andrew Cooper
2015-12-16 21:24 ` [PATCH RFC 15/31] x86: Generate deep dependencies of x86 features Andrew Cooper
2016-01-05 16:03   ` Ian Campbell
2016-01-05 16:42     ` Andrew Cooper
2016-01-05 16:54       ` Ian Campbell
2016-01-05 17:09         ` Andrew Cooper
2016-01-05 17:19           ` Ian Campbell
2015-12-16 21:24 ` [PATCH RFC 16/31] x86: Automatically generate known_features Andrew Cooper
2015-12-16 21:24 ` [PATCH RFC 17/31] xen/x86: Clear dependent features when clearing a cpu cap Andrew Cooper
2015-12-16 21:24 ` [PATCH RFC 18/31] xen/x86: Improve disabling of features which have dependencies Andrew Cooper
2016-01-21 16:48   ` Jan Beulich
2015-12-16 21:24 ` [PATCH RFC 19/31] tools/libxc: Sanitise guest featuresets Andrew Cooper
2016-01-05 16:05   ` Ian Campbell
2015-12-16 21:24 ` [PATCH RFC 20/31] x86: Improvements to in-hypervisor cpuid sanity checks Andrew Cooper
2016-01-21 17:02   ` Jan Beulich
2016-01-21 17:21     ` Andrew Cooper
2016-01-21 18:15       ` Andrew Cooper
2016-01-22  7:47         ` Jan Beulich
2016-01-22  7:45       ` Jan Beulich
2015-12-16 21:24 ` [PATCH RFC 21/31] x86/domctl: Break out logic to update domain state from cpuid information Andrew Cooper
2016-01-21 17:05   ` Jan Beulich
2016-01-21 17:08     ` Andrew Cooper
2015-12-16 21:24 ` [PATCH RFC 22/31] x86/cpu: Move set_cpumask() calls into c_early_init() Andrew Cooper
2016-01-21 17:08   ` Jan Beulich
2015-12-16 21:24 ` [PATCH RFC 23/31] xen/x86: Export cpuid levelling capabilities via SYSCTL Andrew Cooper
2016-01-21 17:23   ` Jan Beulich
2015-12-16 21:24 ` [PATCH RFC 24/31] tools/stubs: Expose host levelling capabilities to userspace Andrew Cooper
2015-12-16 21:24 ` [PATCH RFC 25/31] xen/x86: Common infrastructure for levelling context switching Andrew Cooper
2016-01-22  8:56   ` Jan Beulich
2016-01-22 10:05     ` Andrew Cooper
2015-12-16 21:24 ` Andrew Cooper [this message]
2016-01-22  9:27   ` [PATCH RFC 26/31] xen/x86: Rework AMD masking MSR setup Jan Beulich
2016-01-22 11:01     ` Andrew Cooper
2016-01-22 11:13       ` Jan Beulich
2016-01-22 13:59         ` Andrew Cooper
2016-01-22 14:12           ` Jan Beulich
2016-01-22 17:03             ` Andrew Cooper
2016-01-25 11:25               ` Jan Beulich
2015-12-16 21:24 ` [PATCH RFC 27/31] xen/x86: Rework Intel masking/faulting setup Andrew Cooper
2016-01-22  9:40   ` Jan Beulich
2016-01-22 14:09     ` Andrew Cooper
2016-01-22 14:29       ` Jan Beulich
2016-01-22 14:46         ` Andrew Cooper
2016-01-22 14:53           ` Jan Beulich
2015-12-16 21:24 ` [PATCH RFC 28/31] xen/x86: Context switch all levelling state in context_switch() Andrew Cooper
2016-01-22  9:52   ` Jan Beulich
2016-01-22 14:19     ` Andrew Cooper
2016-01-22 14:31       ` Jan Beulich
2016-01-22 14:39         ` Andrew Cooper
2015-12-16 21:24 ` [PATCH RFC 29/31] x86/pv: Provide custom cpumasks for PV domains Andrew Cooper
2016-01-22  9:56   ` Jan Beulich
2016-01-22 14:24     ` Andrew Cooper
2016-01-22 14:33       ` Jan Beulich
2016-01-22 14:42         ` Andrew Cooper
2016-01-22 14:48           ` Jan Beulich
2016-01-22 14:56             ` Andrew Cooper
2015-12-16 21:24 ` [PATCH RFC 30/31] x86/domctl: Update PV domain cpumasks when setting cpuid policy Andrew Cooper
2016-01-22 10:02   ` Jan Beulich
2015-12-16 21:24 ` [PATCH RFC 31/31] tools/libxc: Calculate xstate cpuid leaf from guest information Andrew Cooper

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1450301073-28191-27-git-send-email-andrew.cooper3@citrix.com \
    --to=andrew.cooper3@citrix.com \
    --cc=JBeulich@suse.com \
    --cc=xen-devel@lists.xen.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.