All of lore.kernel.org
 help / color / mirror / Atom feed
From: Borislav Petkov <bp@alien8.de>
To: Ashish Kalra <Ashish.Kalra@amd.com>
Cc: tglx@kernel.org, mingo@redhat.com, dave.hansen@linux.intel.com,
	x86@kernel.org, hpa@zytor.com, seanjc@google.com,
	peterz@infradead.org, thomas.lendacky@amd.com,
	herbert@gondor.apana.org.au, davem@davemloft.net,
	ardb@kernel.org, pbonzini@redhat.com, aik@amd.com,
	Michael.Roth@amd.com, KPrateek.Nayak@amd.com,
	Tycho.Andersen@amd.com, Nathan.Fontenot@amd.com,
	ackerleytng@google.com, jackyli@google.com, pgonda@google.com,
	rientjes@google.com, jacobhxu@google.com, xin@zytor.com,
	pawan.kumar.gupta@linux.intel.com, babu.moger@amd.com,
	dyoung@redhat.com, nikunj@amd.com, john.allen@amd.com,
	darwi@linutronix.de, linux-kernel@vger.kernel.org,
	linux-crypto@vger.kernel.org, kvm@vger.kernel.org,
	linux-coco@lists.linux.dev
Subject: Re: [PATCH v12 4/5] x86/sev: Add support to perform RMP optimizations asynchronously
Date: Sat, 29 Aug 2026 13:52:08 -0700	[thread overview]
Message-ID: <20260829205208.GDapNGeGMOs02IrkGS@fat_crate.local> (raw)
In-Reply-To: <9c9502278f68af9da19f0dd583ba303d0e6d66d2.1786389115.git.ashish.kalra@amd.com>

On Mon, Aug 10, 2026 at 07:22:10PM +0000, Ashish Kalra wrote:
> +/*
> + * RMPOPT optimizations skip RMP checks at 1GB granularity if this range of
> + * memory does not contain any SNP guest memory.
> + *
> + * @pa is a system physical address; RMPOPT operates on the containing 1GB.
> + */
> +static void rmpopt(u64 pa)
> +{
> +	u64 pa_start = ALIGN_DOWN(pa, SZ_1G);
> +	enum rmpopt_op_type op = RMPOPT_OP_VERIFY_AND_REPORT_STATUS;
> +
> +	/*
> +	 * RMPOPT (F2 0F 01 FC): RAX = 1GB-aligned SPA, RCX = op type, CF set if
> +	 * the range was optimized (result unused on this path).
> +	 *
> +	 * Binutils does not support the RMPOPT mnemonic yet, so the instruction
> +	 * is encoded with .byte.
> +	 */

I don't know whether you've checked the binutils sources but this should have
the version of binutils which supports it and I think there is no such version
yet - I've pinged binutils team to see what their plans are.

> +	asm volatile(".byte 0xf2, 0x0f, 0x01, 0xfc"
> +		     :: "a" (pa_start), "c" (op)
> +		     : "memory", "cc");
> +}
> +
> +/* on_each_cpu() callback: optimize the whole RMPOPT range on this CPU. */
> +static void rmpopt_scan_range(void *arg)
> +{
> +	u64 pa;
> +
> +	for (pa = rmpopt_pa_start; pa < rmpopt_pa_end; pa += SZ_1G)
> +		rmpopt(pa);
> +}
> +
> +static void rmpopt_work_handler(struct work_struct *work)
> +{
> +	int this_cpu;
> +
> +	/*
> +	 * RMPOPT scans the RMP table, stores the result of the scan in the
> +	 * reserved processor memory. The RMP scan is the most expensive
> +	 * part. If a second RMPOPT occurs, it can skip the expensive scan
> +	 * if they can see a cached result in the reserved processor memory.
> +	 *
> +	 * Run RMPOPT on one CPU first (the leader), then on every other primary
> +	 * thread (the followers).  A follower skips the expensive RMP scan by
> +	 * reusing the cached scan results the leader produced.
> +	 *
> +	 * migrate_disable() pins this work to the current CPU so it stays the
> +	 * leader for the whole leader loop: this_cpu remains valid and the
> +	 * RMPOPT instruction runs on it.
> +	 */
> +	migrate_disable();
> +	this_cpu = smp_processor_id();
> +
> +	cpumask_andnot(rmpopt_follower_mask, rmpopt_cpumask,
> +		       topology_sibling_cpumask(this_cpu));
> +
> +	rmpopt_scan_range(NULL);
> +
> +	migrate_enable();
> +
> +	/*
> +	 * Followers: one IPI per remaining core, each optimizing the whole
> +	 * range.  Each runs with interrupts disabled, but only issues cache-hit
> +	 * RMPOPTs (the leader populated the scan cache above), so the window is
> +	 * short.  cpus_read_lock() is intentionally not held: CPU hotplug is
> +	 * disabled the entire time SNP is active (see snp_prepare()), and this
> +	 * work only runs while SNP is active, so the follower set stays valid.
> +	 */
> +	on_each_cpu_mask(rmpopt_follower_mask, rmpopt_scan_range, NULL, true);

If the leader ran once and the results are cached, then does it matter if
I run RMPOPT on it again? IOW, what's stopping me from doing

	on_each_cpu_mask(rmpopt_cpumask, rmpopt_scan_range, NULL, true);

and don't care about leaders and followers at all?

Also, rmpopt_mask is cpu_primary_thread_mask and you don't need any of those
gymnastics.

IOW, this is how my cleanup ontop looks like so far:

diff --git a/arch/x86/virt/svm/sev.c b/arch/x86/virt/svm/sev.c
index 55a6e2319899..a1f6f3111517 100644
--- a/arch/x86/virt/svm/sev.c
+++ b/arch/x86/virt/svm/sev.c
@@ -125,7 +125,6 @@ static void *rmp_bookkeeping __ro_after_init;
 
 static u64 probed_rmp_base, probed_rmp_size;
 
-static cpumask_var_t rmpopt_cpumask, rmpopt_follower_mask;
 static u64 rmpopt_pa_start, rmpopt_pa_end;
 
 enum rmpopt_op_type {
@@ -587,11 +586,9 @@ static void rmpopt_disable(void)
 	cancel_delayed_work_sync(&rmpopt_delayed_work);
 	destroy_workqueue(rmpopt_wq);
 
-	for_each_cpu(cpu, rmpopt_cpumask)
+	for_each_cpu(cpu, cpu_primary_thread_mask)
 		wrmsrq_on_cpu(cpu, MSR_AMD64_RMPOPT_BASE, 0);
 
-	free_cpumask_var(rmpopt_cpumask);
-	free_cpumask_var(rmpopt_follower_mask);
 	rmpopt_pa_start = rmpopt_pa_end = 0;
 	rmpopt_wq = NULL;
 }
@@ -632,16 +629,9 @@ static bool rmpopt_capable(void)
  */
 static void rmpopt(u64 pa)
 {
-	u64 pa_start = ALIGN_DOWN(pa, SZ_1G);
 	enum rmpopt_op_type op = RMPOPT_OP_VERIFY_AND_REPORT_STATUS;
+	u64 pa_start = ALIGN_DOWN(pa, SZ_1G);
 
-	/*
-	 * RMPOPT (F2 0F 01 FC): RAX = 1GB-aligned SPA, RCX = op type, CF set if
-	 * the range was optimized (result unused on this path).
-	 *
-	 * Binutils does not support the RMPOPT mnemonic yet, so the instruction
-	 * is encoded with .byte.
-	 */
 	asm volatile(".byte 0xf2, 0x0f, 0x01, 0xfc"
 		     :: "a" (pa_start), "c" (op)
 		     : "memory", "cc");
@@ -656,43 +646,22 @@ static void rmpopt_scan_range(void *arg)
 		rmpopt(pa);
 }
 
-static void rmpopt_work_handler(struct work_struct *work)
+static void do_rmpopt_work(struct work_struct *work)
 {
 	int this_cpu;
 
 	/*
-	 * RMPOPT scans the RMP table, stores the result of the scan in the
-	 * reserved processor memory. The RMP scan is the most expensive
-	 * part. If a second RMPOPT occurs, it can skip the expensive scan
-	 * if they can see a cached result in the reserved processor memory.
-	 *
-	 * Run RMPOPT on one CPU first (the leader), then on every other primary
-	 * thread (the followers).  A follower skips the expensive RMP scan by
-	 * reusing the cached scan results the leader produced.
-	 *
-	 * migrate_disable() pins this work to the current CPU so it stays the
-	 * leader for the whole leader loop: this_cpu remains valid and the
-	 * RMPOPT instruction runs on it.
+	 * RMPOPT caches the results of a RMP table scan in reserved processor
+	 * memory, allowing future invocations to skip such costly operations.
 	 */
 	migrate_disable();
 	this_cpu = smp_processor_id();
 
-	cpumask_andnot(rmpopt_follower_mask, rmpopt_cpumask,
-		       topology_sibling_cpumask(this_cpu));
-
 	rmpopt_scan_range(NULL);
 
 	migrate_enable();
 
-	/*
-	 * Followers: one IPI per remaining core, each optimizing the whole
-	 * range.  Each runs with interrupts disabled, but only issues cache-hit
-	 * RMPOPTs (the leader populated the scan cache above), so the window is
-	 * short.  cpus_read_lock() is intentionally not held: CPU hotplug is
-	 * disabled the entire time SNP is active (see snp_prepare()), and this
-	 * work only runs while SNP is active, so the follower set stays valid.
-	 */
-	on_each_cpu_mask(rmpopt_follower_mask, rmpopt_scan_range, NULL, true);
+	on_each_cpu_mask(cpu_primary_thread_mask, rmpopt_scan_range, NULL, true);
 }
 
 void snp_setup_rmpopt(void)
@@ -729,30 +698,7 @@ void snp_setup_rmpopt(void)
 		return;
 	}
 
-	INIT_DELAYED_WORK(&rmpopt_delayed_work, rmpopt_work_handler);
-
-	if (!zalloc_cpumask_var(&rmpopt_cpumask, GFP_KERNEL)) {
-		pr_err("Failed to allocate RMPOPT cpumask\n");
-		destroy_workqueue(rmpopt_wq);
-		rmpopt_wq = NULL;
-		return;
-	}
-
-	if (!zalloc_cpumask_var(&rmpopt_follower_mask, GFP_KERNEL)) {
-		pr_err("Failed to allocate RMPOPT follower cpumask\n");
-		free_cpumask_var(rmpopt_cpumask);
-		destroy_workqueue(rmpopt_wq);
-		rmpopt_wq = NULL;
-		return;
-	}
-
-	/*
-	 * The RMPOPT_BASE MSR has core scope. All primary threads are online,
-	 * otherwise SNP would not have been enabled.
-	 */
-	for_each_online_cpu(cpu)
-		if (topology_is_primary_thread(cpu))
-			cpumask_set_cpu(cpu, rmpopt_cpumask);
+	INIT_DELAYED_WORK(&rmpopt_delayed_work, do_rmpopt_work);
 
 	rmpopt_pa_start = ALIGN_DOWN(PFN_PHYS(min_low_pfn), SZ_1G);
 	rmpopt_base = rmpopt_pa_start | MSR_AMD64_RMPOPT_ENABLE;
@@ -761,7 +707,7 @@ void snp_setup_rmpopt(void)
 	 * Per-CPU RMPOPT tables cover at most 2 TB.  Program each core's
 	 * RMPOPT_BASE with the start of RAM to optimize up to 2 TB.
 	 */
-	for_each_cpu(cpu, rmpopt_cpumask)
+	for_each_cpu(cpu, cpu_primary_thread_mask)
 		wrmsrq_on_cpu(cpu, MSR_AMD64_RMPOPT_BASE, rmpopt_base);
 
 	rmpopt_pa_end = ALIGN(PFN_PHYS(max_pfn), SZ_1G);

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette

  reply	other threads:[~2026-08-29 20:52 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-10 19:20 [PATCH v12 0/5] Add RMPOPT support Ashish Kalra
2026-08-10 19:21 ` [PATCH v12 1/5] x86/cpufeatures: Add X86_FEATURE_RMPOPT feature flag Ashish Kalra
2026-08-10 19:21 ` [PATCH v12 2/5] x86/sev: Disable CPU hotplug while SNP is active Ashish Kalra
2026-08-10 19:21 ` [PATCH v12 3/5] x86/sev: Initialize RMPOPT configuration MSRs Ashish Kalra
2026-08-27  2:06   ` Borislav Petkov
2026-08-10 19:22 ` [PATCH v12 4/5] x86/sev: Add support to perform RMP optimizations asynchronously Ashish Kalra
2026-08-29 20:52   ` Borislav Petkov [this message]
2026-08-31 20:00     ` Kalra, Ashish
2026-09-01 19:20       ` Borislav Petkov
2026-08-10 19:22 ` [PATCH v12 5/5] x86/sev: Re-enable RMP optimizations on SNP guest shutdown Ashish Kalra
2026-08-27 16:29 ` [PATCH v12 0/5] Add RMPOPT support Tom Lendacky

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=20260829205208.GDapNGeGMOs02IrkGS@fat_crate.local \
    --to=bp@alien8.de \
    --cc=Ashish.Kalra@amd.com \
    --cc=KPrateek.Nayak@amd.com \
    --cc=Michael.Roth@amd.com \
    --cc=Nathan.Fontenot@amd.com \
    --cc=Tycho.Andersen@amd.com \
    --cc=ackerleytng@google.com \
    --cc=aik@amd.com \
    --cc=ardb@kernel.org \
    --cc=babu.moger@amd.com \
    --cc=darwi@linutronix.de \
    --cc=dave.hansen@linux.intel.com \
    --cc=davem@davemloft.net \
    --cc=dyoung@redhat.com \
    --cc=herbert@gondor.apana.org.au \
    --cc=hpa@zytor.com \
    --cc=jackyli@google.com \
    --cc=jacobhxu@google.com \
    --cc=john.allen@amd.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-coco@lists.linux.dev \
    --cc=linux-crypto@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=nikunj@amd.com \
    --cc=pawan.kumar.gupta@linux.intel.com \
    --cc=pbonzini@redhat.com \
    --cc=peterz@infradead.org \
    --cc=pgonda@google.com \
    --cc=rientjes@google.com \
    --cc=seanjc@google.com \
    --cc=tglx@kernel.org \
    --cc=thomas.lendacky@amd.com \
    --cc=x86@kernel.org \
    --cc=xin@zytor.com \
    /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.