]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
arm64: mm: Re-implement the __tlbi_level macro as a C function
authorRyan Roberts <ryan.roberts@arm.com>
Mon, 2 Mar 2026 13:55:48 +0000 (13:55 +0000)
committerCatalin Marinas <catalin.marinas@arm.com>
Fri, 13 Mar 2026 17:23:03 +0000 (17:23 +0000)
As part of efforts to reduce our reliance on complex preprocessor macros
for TLB invalidation routines, convert the __tlbi_level macro to a C
function for by-level TLB invalidation.

Each specific tlbi level op is implemented as a C function and the
appropriate function pointer is passed to __tlbi_level(). Since
everything is declared inline and is statically resolvable, the compiler
will convert the indirect function call to a direct inline execution.

Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
arch/arm64/include/asm/tlbflush.h

index 1416e652612b764653bb4e5a8d45f0e25eb1440a..a0e3ebe2998647b5f994e3bccb2983364fbdaa75 100644 (file)
@@ -97,19 +97,60 @@ static inline unsigned long get_trans_granule(void)
 
 #define TLBI_TTL_UNKNOWN       INT_MAX
 
-#define __tlbi_level(op, addr, level) do {                             \
-       u64 arg = addr;                                                 \
-                                                                       \
-       if (alternative_has_cap_unlikely(ARM64_HAS_ARMv8_4_TTL) &&      \
-           level >= 0 && level <= 3) {                                 \
-               u64 ttl = level & 3;                                    \
-               ttl |= get_trans_granule() << 2;                        \
-               arg &= ~TLBI_TTL_MASK;                                  \
-               arg |= FIELD_PREP(TLBI_TTL_MASK, ttl);                  \
-       }                                                               \
-                                                                       \
-       __tlbi(op, arg);                                                \
-} while(0)
+typedef void (*tlbi_op)(u64 arg);
+
+static __always_inline void vae1is(u64 arg)
+{
+       __tlbi(vae1is, arg);
+}
+
+static __always_inline void vae2is(u64 arg)
+{
+       __tlbi(vae2is, arg);
+}
+
+static __always_inline void vale1(u64 arg)
+{
+       __tlbi(vale1, arg);
+}
+
+static __always_inline void vale1is(u64 arg)
+{
+       __tlbi(vale1is, arg);
+}
+
+static __always_inline void vale2is(u64 arg)
+{
+       __tlbi(vale2is, arg);
+}
+
+static __always_inline void vaale1is(u64 arg)
+{
+       __tlbi(vaale1is, arg);
+}
+
+static __always_inline void ipas2e1(u64 arg)
+{
+       __tlbi(ipas2e1, arg);
+}
+
+static __always_inline void ipas2e1is(u64 arg)
+{
+       __tlbi(ipas2e1is, arg);
+}
+
+static __always_inline void __tlbi_level(tlbi_op op, u64 addr, u32 level)
+{
+       u64 arg = addr;
+
+       if (alternative_has_cap_unlikely(ARM64_HAS_ARMv8_4_TTL) && level <= 3) {
+               u64 ttl = level | (get_trans_granule() << 2);
+
+               FIELD_MODIFY(TLBI_TTL_MASK, &arg, ttl);
+       }
+
+       op(arg);
+}
 
 #define __tlbi_user_level(op, arg, level) do {                         \
        if (arm64_kernel_unmapped_at_el0())                             \