From: "Kristina Martšenko" <kristina.martsenko@arm.com>
To: linux-arm-kernel@lists.infradead.org, linux-acpi@vger.kernel.org,
kvmarm@lists.linux.dev, linux-efi@vger.kernel.org
Cc: Catalin Marinas <catalin.marinas@arm.com>,
Will Deacon <will@kernel.org>,
Mark Rutland <mark.rutland@arm.com>,
Ryan Roberts <ryan.roberts@arm.com>,
David Hildenbrand <david@kernel.org>,
Lorenzo Stoakes <ljs@kernel.org>,
Linu Cherian <linu.cherian@arm.com>,
Anshuman Khandual <anshuman.khandual@arm.com>,
Lorenzo Pieralisi <lpieralisi@kernel.org>,
Hanjun Guo <guohanjun@huawei.com>,
Sudeep Holla <sudeep.holla@kernel.org>,
Marc Zyngier <maz@kernel.org>, Oliver Upton <oupton@kernel.org>,
Fuad Tabba <fuad.tabba@linux.dev>,
Joey Gouly <joey.gouly@arm.com>,
Steffen Eiden <seiden@linux.ibm.com>,
Suzuki K Poulose <suzuki.poulose@arm.com>,
Zenghui Yu <yuzenghui@huawei.com>,
Ard Biesheuvel <ardb@kernel.org>,
Ilias Apalodimas <ilias.apalodimas@linaro.org>
Subject: [RFC 09/12] arm64: tlbid: Track the TLBI domain of a task
Date: Thu, 1 Oct 2026 12:06:52 +0100 [thread overview]
Message-ID: <20261001110655.461473-10-kristina.martsenko@arm.com> (raw)
In-Reply-To: <20261001110655.461473-1-kristina.martsenko@arm.com>
Maintain a bitmap of valid TLBI domains for each mm. A later patch will
issue TLBIs for an mm to one of the domains in its bitmap.
As a performance optimization, we want to avoid sending TLB
invalidations to CPUs that have never installed a particular mm, since
their TLBs can't contain the mm's PTEs. To achieve this, have each mm
contain a bitmap of valid TLBI domains. A domain is valid if it contains
all the CPUs that the mm has been installed on. Initially all domains
are valid. Whenever an mm is installed on a new CPU, its set of domains
is reduced (using a bitwise AND) to only include those domains that
contain the new CPU.
Use atomic operations to reduce the bitmap. In case two threads update
the bitmap concurrently, the result will be the same.
efi_mm is initialized very early, before TLBI domains are initialized,
so e.g. system_supports_tlbid() will return false. Just configure efi_mm
to use the largest domain in the system (containing all CPUs).
Note: The initial bitmap is all ones. If a TLBI were issued before the
mm is installed, then any domain could be selected, regardless of which
CPUs are in it. (The bits above the last valid domain will be ignored.)
This is fine, since at this point no TLBs actually need to be
invalidated, since the mm hasn't been installed anywhere yet.
Note: destroy_tlbid_context() doesn't need to check mm_is_efi() since
efi_mm is never freed.
Signed-off-by: Kristina Martšenko <kristina.martsenko@arm.com>
---
arch/arm64/include/asm/mmu.h | 11 ++++++
arch/arm64/include/asm/mmu_context.h | 9 ++++-
arch/arm64/mm/context.c | 6 ++--
arch/arm64/mm/tlbid.c | 52 ++++++++++++++++++++++++++++
4 files changed, 75 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h
index 5e1211c540ab..fc4e759f9f64 100644
--- a/arch/arm64/include/asm/mmu.h
+++ b/arch/arm64/include/asm/mmu.h
@@ -25,6 +25,7 @@ typedef struct {
void *vdso;
unsigned long flags;
u8 pkey_allocation_map;
+ atomic64_t *tlbid_domains;
} mm_context_t;
/*
@@ -106,5 +107,15 @@ static inline void kpti_install_ng_mappings(void) {}
extern bool page_alloc_available;
+#ifdef CONFIG_ARM64_TLBID
+int init_tlbid_context(struct mm_struct *mm);
+void destroy_tlbid_context(struct mm_struct *mm);
+void update_tlbid_domains(struct mm_struct *mm, unsigned int cpu);
+#else
+static inline int init_tlbid_context(struct mm_struct *mm) { return 0; }
+static inline void destroy_tlbid_context(struct mm_struct *mm) {}
+static inline void update_tlbid_domains(struct mm_struct *mm, unsigned int cpu) {}
+#endif
+
#endif /* !__ASSEMBLER__ */
#endif
diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h
index 803b68758152..5bf2d3f73e1c 100644
--- a/arch/arm64/include/asm/mmu_context.h
+++ b/arch/arm64/include/asm/mmu_context.h
@@ -21,6 +21,7 @@
#include <asm/cpufeature.h>
#include <asm/daifflags.h>
#include <asm/gcs.h>
+#include <asm/mmu.h>
#include <asm/proc-fns.h>
#include <asm/cputype.h>
#include <asm/sysreg.h>
@@ -172,7 +173,13 @@ init_new_context(struct task_struct *tsk, struct mm_struct *mm)
/* pkey 0 is the default, so always reserve it. */
mm->context.pkey_allocation_map = BIT(0);
- return 0;
+ return init_tlbid_context(mm);
+}
+
+#define destroy_context(mm) destroy_context(mm)
+static inline void destroy_context(struct mm_struct *mm)
+{
+ destroy_tlbid_context(mm);
}
static inline void arch_dup_pkeys(struct mm_struct *oldmm,
diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c
index 0f4a28b87469..21146d57e8b7 100644
--- a/arch/arm64/mm/context.c
+++ b/arch/arm64/mm/context.c
@@ -13,6 +13,7 @@
#include <linux/mm.h>
#include <asm/cpufeature.h>
+#include <asm/mmu.h>
#include <asm/mmu_context.h>
#include <asm/smp.h>
#include <asm/tlbflush.h>
@@ -215,7 +216,7 @@ static u64 new_context(struct mm_struct *mm)
void check_and_switch_context(struct mm_struct *mm)
{
unsigned long flags;
- unsigned int cpu;
+ unsigned int cpu = smp_processor_id();
u64 asid, old_active_asid;
if (system_supports_cnp())
@@ -251,7 +252,6 @@ void check_and_switch_context(struct mm_struct *mm)
atomic64_set(&mm->context.id, asid);
}
- cpu = smp_processor_id();
if (cpumask_test_and_clear_cpu(cpu, &tlb_flush_pending))
local_flush_tlb_all();
@@ -262,6 +262,8 @@ void check_and_switch_context(struct mm_struct *mm)
arm64_apply_bp_hardening();
+ update_tlbid_domains(mm, cpu);
+
/*
* Defer TTBR0_EL1 setting for user threads to uaccess_enable() when
* emulating PAN.
diff --git a/arch/arm64/mm/tlbid.c b/arch/arm64/mm/tlbid.c
index 0c26ace39592..b44fab2dca20 100644
--- a/arch/arm64/mm/tlbid.c
+++ b/arch/arm64/mm/tlbid.c
@@ -7,18 +7,70 @@
*/
#include <linux/acpi.h>
+#include <linux/atomic.h>
#include <linux/bitops.h>
#include <linux/bitmap.h>
+#include <linux/efi.h>
#include <linux/jump_label.h>
+#include <linux/mm_types.h>
#include <linux/slab.h>
#include <linux/sort.h>
+#include <asm/mmu.h>
+
DEFINE_STATIC_KEY_FALSE(tlbid_enabled);
static u16 *domain_ids;
static unsigned long **cpu_domains;
static int domain_count;
+void update_tlbid_domains(struct mm_struct *mm, unsigned int cpu)
+{
+ if (!system_supports_tlbid())
+ return;
+
+ for (int i = 0; i < BITS_TO_U64(domain_count); i++)
+ atomic64_and(cpu_domains[cpu][i], &mm->context.tlbid_domains[i]);
+}
+
+int init_tlbid_context(struct mm_struct *mm)
+{
+ bool is_efi = mm_is_efi(mm);
+ atomic64_t *domains;
+ int ndomains, nwords;
+
+ /* TLBI domain support not yet known at EFI init time */
+ if (!system_supports_tlbid() && !is_efi)
+ return 0;
+
+ ndomains = is_efi ? MAX_TLBI_DOMAINS : domain_count;
+ nwords = BITS_TO_U64(ndomains);
+ domains = kcalloc(nwords, sizeof(*domains), GFP_KERNEL);
+ if (!domains)
+ return -ENOMEM;
+
+ if (is_efi) {
+ /*
+ * Use a safe domain since updates to domains would be lost if
+ * efi_mm were installed before TLBID is enabled.
+ */
+ atomic64_set(domains, 1);
+ } else {
+ for (int i = 0; i < nwords; i++)
+ atomic64_set(&domains[i], -1);
+ }
+
+ mm->context.tlbid_domains = domains;
+
+ return 0;
+}
+
+void destroy_tlbid_context(struct mm_struct *mm)
+{
+ if (system_supports_tlbid())
+ kfree(mm->context.tlbid_domains);
+}
+
static int __init init_cpu_domain_bitmaps(struct tlbi_domain *domains)
{
int cpu;
--
2.43.0
next prev parent reply other threads:[~2026-10-01 11:08 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-01 11:06 [RFC 00/12] arm64: Add support for TLBI domains Kristina Martšenko
2026-10-01 11:06 ` [RFC 01/12] arm64: sysreg: Add definitions for FEAT_TLBID Kristina Martšenko
2026-10-01 11:06 ` [RFC 02/12] arm64: Detect FEAT_TLBID Kristina Martšenko
2026-10-01 11:06 ` [RFC 03/12] KVM: arm64: Hide TLBID from guest sysregs Kristina Martšenko
2026-10-01 11:06 ` [RFC 04/12] KVM: arm64: Hide TLBID from guest instructions Kristina Martšenko
2026-10-01 11:06 ` [RFC 05/12] ACPICA: Add TLBI table definition Kristina Martšenko
2026-10-01 11:06 ` [RFC 06/12] ACPI: TLBI: Parse domains from table Kristina Martšenko
2026-10-01 11:06 ` [RFC 07/12] arm64: tlbid: Set up CPU domain bitmaps Kristina Martšenko
2026-10-01 11:06 ` [RFC 08/12] efi/arm: Check return value of init_new_context() Kristina Martšenko
2026-10-04 8:00 ` Ard Biesheuvel
2026-10-01 11:06 ` Kristina Martšenko [this message]
2026-10-01 11:06 ` [RFC 10/12] arm64: Support TLBIP instructions Kristina Martšenko
2026-10-01 11:06 ` [RFC 11/12] arm64: tlbid: Pass domain to TLBI instructions Kristina Martšenko
2026-10-01 11:06 ` [RFC 12/12] arm64: tlbid: Add documentation Kristina Martšenko
2026-10-03 16:12 ` [RFC 00/12] arm64: Add support for TLBI domains Marc Zyngier
2026-10-05 8:40 ` Oliver Upton
2026-10-04 18:06 ` Zi Yan
2026-10-05 6:29 ` Will Deacon
2026-10-05 18:13 ` Zi Yan
2026-10-05 11:07 ` Catalin Marinas
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=20261001110655.461473-10-kristina.martsenko@arm.com \
--to=kristina.martsenko@arm.com \
--cc=anshuman.khandual@arm.com \
--cc=ardb@kernel.org \
--cc=catalin.marinas@arm.com \
--cc=david@kernel.org \
--cc=fuad.tabba@linux.dev \
--cc=guohanjun@huawei.com \
--cc=ilias.apalodimas@linaro.org \
--cc=joey.gouly@arm.com \
--cc=kvmarm@lists.linux.dev \
--cc=linu.cherian@arm.com \
--cc=linux-acpi@vger.kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-efi@vger.kernel.org \
--cc=ljs@kernel.org \
--cc=lpieralisi@kernel.org \
--cc=mark.rutland@arm.com \
--cc=maz@kernel.org \
--cc=oupton@kernel.org \
--cc=ryan.roberts@arm.com \
--cc=seiden@linux.ibm.com \
--cc=sudeep.holla@kernel.org \
--cc=suzuki.poulose@arm.com \
--cc=will@kernel.org \
--cc=yuzenghui@huawei.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox