Skip to content

Commit 18aa3bd

Browse files
committed
Merge branch 'for-next/tlbi' into for-next/core
* for-next/tlbi: : Support for TTL (translation table level) hint in the TLB operations arm64: tlb: Use the TLBI RANGE feature in arm64 arm64: enable tlbi range instructions arm64: tlb: Detect the ARMv8.4 TLBI RANGE feature arm64: tlb: don't set the ttl value in flush_tlb_page_nosync arm64: Shift the __tlbi_level() indentation left arm64: tlb: Set the TTL field in flush_*_tlb_range arm64: tlb: Set the TTL field in flush_tlb_range tlb: mmu_gather: add tlb_flush_*_range APIs arm64: Add tlbi_user_level TLB invalidation helper arm64: Add level-hinted TLB invalidation helper arm64: Document SW reserved PTE/PMD bits in Stage-2 descriptors arm64: Detect the ARMv8.4 TTL feature
2 parents 4557062 + d1d3aa9 commit 18aa3bd

File tree

12 files changed

+304
-32
lines changed

12 files changed

+304
-32
lines changed

arch/arm64/Kconfig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1601,6 +1601,20 @@ config ARM64_AMU_EXTN
16011601
correctly reflect reality. Most commonly, the value read will be 0,
16021602
indicating that the counter is not enabled.
16031603

1604+
config AS_HAS_ARMV8_4
1605+
def_bool $(cc-option,-Wa$(comma)-march=armv8.4-a)
1606+
1607+
config ARM64_TLB_RANGE
1608+
bool "Enable support for tlbi range feature"
1609+
default y
1610+
depends on AS_HAS_ARMV8_4
1611+
help
1612+
ARMv8.4-TLBI provides TLBI invalidation instruction that apply to a
1613+
range of input addresses.
1614+
1615+
The feature introduces new assembly instructions, and they were
1616+
support when binutils >= 2.30.
1617+
16041618
endmenu
16051619

16061620
menu "ARMv8.5 architectural features"

arch/arm64/Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,11 +82,18 @@ endif
8282
# compiler to generate them and consequently to break the single image contract
8383
# we pass it only to the assembler. This option is utilized only in case of non
8484
# integrated assemblers.
85+
ifneq ($(CONFIG_AS_HAS_ARMV8_4), y)
8586
branch-prot-flags-$(CONFIG_AS_HAS_PAC) += -Wa,-march=armv8.3-a
8687
endif
88+
endif
8789

8890
KBUILD_CFLAGS += $(branch-prot-flags-y)
8991

92+
ifeq ($(CONFIG_AS_HAS_ARMV8_4), y)
93+
# make sure to pass the newest target architecture to -march.
94+
KBUILD_CFLAGS += -Wa,-march=armv8.4-a
95+
endif
96+
9097
ifeq ($(CONFIG_SHADOW_CALL_STACK), y)
9198
KBUILD_CFLAGS += -ffixed-x18
9299
endif

arch/arm64/include/asm/cpucaps.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@
6262
#define ARM64_HAS_GENERIC_AUTH 52
6363
#define ARM64_HAS_32BIT_EL1 53
6464
#define ARM64_BTI 54
65+
#define ARM64_HAS_ARMv8_4_TTL 55
66+
#define ARM64_HAS_TLB_RANGE 56
6567

66-
#define ARM64_NCAPS 55
68+
#define ARM64_NCAPS 57
6769

6870
#endif /* __ASM_CPUCAPS_H */

arch/arm64/include/asm/cpufeature.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,12 @@ static inline bool system_supports_bti(void)
692692
return IS_ENABLED(CONFIG_ARM64_BTI) && cpus_have_const_cap(ARM64_BTI);
693693
}
694694

695+
static inline bool system_supports_tlb_range(void)
696+
{
697+
return IS_ENABLED(CONFIG_ARM64_TLB_RANGE) &&
698+
cpus_have_const_cap(ARM64_HAS_TLB_RANGE);
699+
}
700+
695701
#define ARM64_BP_HARDEN_UNKNOWN -1
696702
#define ARM64_BP_HARDEN_WA_NEEDED 0
697703
#define ARM64_BP_HARDEN_NOT_REQUIRED 1

arch/arm64/include/asm/pgtable-hwdef.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,10 +178,12 @@
178178
#define PTE_S2_RDONLY (_AT(pteval_t, 1) << 6) /* HAP[2:1] */
179179
#define PTE_S2_RDWR (_AT(pteval_t, 3) << 6) /* HAP[2:1] */
180180
#define PTE_S2_XN (_AT(pteval_t, 2) << 53) /* XN[1:0] */
181+
#define PTE_S2_SW_RESVD (_AT(pteval_t, 15) << 55) /* Reserved for SW */
181182

182183
#define PMD_S2_RDONLY (_AT(pmdval_t, 1) << 6) /* HAP[2:1] */
183184
#define PMD_S2_RDWR (_AT(pmdval_t, 3) << 6) /* HAP[2:1] */
184185
#define PMD_S2_XN (_AT(pmdval_t, 2) << 53) /* XN[1:0] */
186+
#define PMD_S2_SW_RESVD (_AT(pmdval_t, 15) << 55) /* Reserved for SW */
185187

186188
#define PUD_S2_RDONLY (_AT(pudval_t, 1) << 6) /* HAP[2:1] */
187189
#define PUD_S2_RDWR (_AT(pudval_t, 3) << 6) /* HAP[2:1] */

arch/arm64/include/asm/pgtable.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ extern void __pmd_error(const char *file, int line, unsigned long val);
4040
extern void __pud_error(const char *file, int line, unsigned long val);
4141
extern void __pgd_error(const char *file, int line, unsigned long val);
4242

43+
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
44+
#define __HAVE_ARCH_FLUSH_PMD_TLB_RANGE
45+
46+
/* Set stride and tlb_level in flush_*_tlb_range */
47+
#define flush_pmd_tlb_range(vma, addr, end) \
48+
__flush_tlb_range(vma, addr, end, PMD_SIZE, false, 2)
49+
#define flush_pud_tlb_range(vma, addr, end) \
50+
__flush_tlb_range(vma, addr, end, PUD_SIZE, false, 1)
51+
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
52+
4353
/*
4454
* ZERO_PAGE is a global shared page that is always zero: used
4555
* for zero-mapped memory areas etc..

arch/arm64/include/asm/stage2_pgtable.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,4 +256,13 @@ stage2_pgd_addr_end(struct kvm *kvm, phys_addr_t addr, phys_addr_t end)
256256
return (boundary - 1 < end - 1) ? boundary : end;
257257
}
258258

259+
/*
260+
* Level values for the ARMv8.4-TTL extension, mapping PUD/PMD/PTE and
261+
* the architectural page-table level.
262+
*/
263+
#define S2_NO_LEVEL_HINT 0
264+
#define S2_PUD_LEVEL 1
265+
#define S2_PMD_LEVEL 2
266+
#define S2_PTE_LEVEL 3
267+
259268
#endif /* __ARM64_S2_PGTABLE_H_ */

arch/arm64/include/asm/sysreg.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,9 @@
617617
#define ID_AA64ISAR0_SHA1_SHIFT 8
618618
#define ID_AA64ISAR0_AES_SHIFT 4
619619

620+
#define ID_AA64ISAR0_TLB_RANGE_NI 0x0
621+
#define ID_AA64ISAR0_TLB_RANGE 0x2
622+
620623
/* id_aa64isar1 */
621624
#define ID_AA64ISAR1_I8MM_SHIFT 52
622625
#define ID_AA64ISAR1_DGH_SHIFT 48

arch/arm64/include/asm/tlb.h

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,37 @@ static void tlb_flush(struct mmu_gather *tlb);
2121

2222
#include <asm-generic/tlb.h>
2323

24+
/*
25+
* get the tlbi levels in arm64. Default value is 0 if more than one
26+
* of cleared_* is set or neither is set.
27+
* Arm64 doesn't support p4ds now.
28+
*/
29+
static inline int tlb_get_level(struct mmu_gather *tlb)
30+
{
31+
if (tlb->cleared_ptes && !(tlb->cleared_pmds ||
32+
tlb->cleared_puds ||
33+
tlb->cleared_p4ds))
34+
return 3;
35+
36+
if (tlb->cleared_pmds && !(tlb->cleared_ptes ||
37+
tlb->cleared_puds ||
38+
tlb->cleared_p4ds))
39+
return 2;
40+
41+
if (tlb->cleared_puds && !(tlb->cleared_ptes ||
42+
tlb->cleared_pmds ||
43+
tlb->cleared_p4ds))
44+
return 1;
45+
46+
return 0;
47+
}
48+
2449
static inline void tlb_flush(struct mmu_gather *tlb)
2550
{
2651
struct vm_area_struct vma = TLB_FLUSH_VMA(tlb->mm, 0);
2752
bool last_level = !tlb->freed_tables;
2853
unsigned long stride = tlb_get_unmap_size(tlb);
54+
int tlb_level = tlb_get_level(tlb);
2955

3056
/*
3157
* If we're tearing down the address space then we only care about
@@ -38,7 +64,8 @@ static inline void tlb_flush(struct mmu_gather *tlb)
3864
return;
3965
}
4066

41-
__flush_tlb_range(&vma, tlb->start, tlb->end, stride, last_level);
67+
__flush_tlb_range(&vma, tlb->start, tlb->end, stride,
68+
last_level, tlb_level);
4269
}
4370

4471
static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,

arch/arm64/include/asm/tlbflush.h

Lines changed: 162 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#ifndef __ASSEMBLY__
1212

13+
#include <linux/bitfield.h>
1314
#include <linux/mm_types.h>
1415
#include <linux/sched.h>
1516
#include <asm/cputype.h>
@@ -59,6 +60,102 @@
5960
__ta; \
6061
})
6162

63+
/*
64+
* Get translation granule of the system, which is decided by
65+
* PAGE_SIZE. Used by TTL.
66+
* - 4KB : 1
67+
* - 16KB : 2
68+
* - 64KB : 3
69+
*/
70+
#define TLBI_TTL_TG_4K 1
71+
#define TLBI_TTL_TG_16K 2
72+
#define TLBI_TTL_TG_64K 3
73+
74+
static inline unsigned long get_trans_granule(void)
75+
{
76+
switch (PAGE_SIZE) {
77+
case SZ_4K:
78+
return TLBI_TTL_TG_4K;
79+
case SZ_16K:
80+
return TLBI_TTL_TG_16K;
81+
case SZ_64K:
82+
return TLBI_TTL_TG_64K;
83+
default:
84+
return 0;
85+
}
86+
}
87+
88+
/*
89+
* Level-based TLBI operations.
90+
*
91+
* When ARMv8.4-TTL exists, TLBI operations take an additional hint for
92+
* the level at which the invalidation must take place. If the level is
93+
* wrong, no invalidation may take place. In the case where the level
94+
* cannot be easily determined, a 0 value for the level parameter will
95+
* perform a non-hinted invalidation.
96+
*
97+
* For Stage-2 invalidation, use the level values provided to that effect
98+
* in asm/stage2_pgtable.h.
99+
*/
100+
#define TLBI_TTL_MASK GENMASK_ULL(47, 44)
101+
102+
#define __tlbi_level(op, addr, level) do { \
103+
u64 arg = addr; \
104+
\
105+
if (cpus_have_const_cap(ARM64_HAS_ARMv8_4_TTL) && \
106+
level) { \
107+
u64 ttl = level & 3; \
108+
ttl |= get_trans_granule() << 2; \
109+
arg &= ~TLBI_TTL_MASK; \
110+
arg |= FIELD_PREP(TLBI_TTL_MASK, ttl); \
111+
} \
112+
\
113+
__tlbi(op, arg); \
114+
} while(0)
115+
116+
#define __tlbi_user_level(op, arg, level) do { \
117+
if (arm64_kernel_unmapped_at_el0()) \
118+
__tlbi_level(op, (arg | USER_ASID_FLAG), level); \
119+
} while (0)
120+
121+
/*
122+
* This macro creates a properly formatted VA operand for the TLB RANGE.
123+
* The value bit assignments are:
124+
*
125+
* +----------+------+-------+-------+-------+----------------------+
126+
* | ASID | TG | SCALE | NUM | TTL | BADDR |
127+
* +-----------------+-------+-------+-------+----------------------+
128+
* |63 48|47 46|45 44|43 39|38 37|36 0|
129+
*
130+
* The address range is determined by below formula:
131+
* [BADDR, BADDR + (NUM + 1) * 2^(5*SCALE + 1) * PAGESIZE)
132+
*
133+
*/
134+
#define __TLBI_VADDR_RANGE(addr, asid, scale, num, ttl) \
135+
({ \
136+
unsigned long __ta = (addr) >> PAGE_SHIFT; \
137+
__ta &= GENMASK_ULL(36, 0); \
138+
__ta |= (unsigned long)(ttl) << 37; \
139+
__ta |= (unsigned long)(num) << 39; \
140+
__ta |= (unsigned long)(scale) << 44; \
141+
__ta |= get_trans_granule() << 46; \
142+
__ta |= (unsigned long)(asid) << 48; \
143+
__ta; \
144+
})
145+
146+
/* These macros are used by the TLBI RANGE feature. */
147+
#define __TLBI_RANGE_PAGES(num, scale) \
148+
((unsigned long)((num) + 1) << (5 * (scale) + 1))
149+
#define MAX_TLBI_RANGE_PAGES __TLBI_RANGE_PAGES(31, 3)
150+
151+
/*
152+
* Generate 'num' values from -1 to 30 with -1 rejected by the
153+
* __flush_tlb_range() loop below.
154+
*/
155+
#define TLBI_RANGE_MASK GENMASK_ULL(4, 0)
156+
#define __TLBI_RANGE_NUM(pages, scale) \
157+
((((pages) >> (5 * (scale) + 1)) & TLBI_RANGE_MASK) - 1)
158+
62159
/*
63160
* TLB Invalidation
64161
* ================
@@ -179,34 +276,83 @@ static inline void flush_tlb_page(struct vm_area_struct *vma,
179276

180277
static inline void __flush_tlb_range(struct vm_area_struct *vma,
181278
unsigned long start, unsigned long end,
182-
unsigned long stride, bool last_level)
279+
unsigned long stride, bool last_level,
280+
int tlb_level)
183281
{
282+
int num = 0;
283+
int scale = 0;
184284
unsigned long asid = ASID(vma->vm_mm);
185285
unsigned long addr;
286+
unsigned long pages;
186287

187288
start = round_down(start, stride);
188289
end = round_up(end, stride);
290+
pages = (end - start) >> PAGE_SHIFT;
189291

190-
if ((end - start) >= (MAX_TLBI_OPS * stride)) {
292+
/*
293+
* When not uses TLB range ops, we can handle up to
294+
* (MAX_TLBI_OPS - 1) pages;
295+
* When uses TLB range ops, we can handle up to
296+
* (MAX_TLBI_RANGE_PAGES - 1) pages.
297+
*/
298+
if ((!system_supports_tlb_range() &&
299+
(end - start) >= (MAX_TLBI_OPS * stride)) ||
300+
pages >= MAX_TLBI_RANGE_PAGES) {
191301
flush_tlb_mm(vma->vm_mm);
192302
return;
193303
}
194304

195-
/* Convert the stride into units of 4k */
196-
stride >>= 12;
305+
dsb(ishst);
197306

198-
start = __TLBI_VADDR(start, asid);
199-
end = __TLBI_VADDR(end, asid);
307+
/*
308+
* When the CPU does not support TLB range operations, flush the TLB
309+
* entries one by one at the granularity of 'stride'. If the the TLB
310+
* range ops are supported, then:
311+
*
312+
* 1. If 'pages' is odd, flush the first page through non-range
313+
* operations;
314+
*
315+
* 2. For remaining pages: the minimum range granularity is decided
316+
* by 'scale', so multiple range TLBI operations may be required.
317+
* Start from scale = 0, flush the corresponding number of pages
318+
* ((num+1)*2^(5*scale+1) starting from 'addr'), then increase it
319+
* until no pages left.
320+
*
321+
* Note that certain ranges can be represented by either num = 31 and
322+
* scale or num = 0 and scale + 1. The loop below favours the latter
323+
* since num is limited to 30 by the __TLBI_RANGE_NUM() macro.
324+
*/
325+
while (pages > 0) {
326+
if (!system_supports_tlb_range() ||
327+
pages % 2 == 1) {
328+
addr = __TLBI_VADDR(start, asid);
329+
if (last_level) {
330+
__tlbi_level(vale1is, addr, tlb_level);
331+
__tlbi_user_level(vale1is, addr, tlb_level);
332+
} else {
333+
__tlbi_level(vae1is, addr, tlb_level);
334+
__tlbi_user_level(vae1is, addr, tlb_level);
335+
}
336+
start += stride;
337+
pages -= stride >> PAGE_SHIFT;
338+
continue;
339+
}
200340

201-
dsb(ishst);
202-
for (addr = start; addr < end; addr += stride) {
203-
if (last_level) {
204-
__tlbi(vale1is, addr);
205-
__tlbi_user(vale1is, addr);
206-
} else {
207-
__tlbi(vae1is, addr);
208-
__tlbi_user(vae1is, addr);
341+
num = __TLBI_RANGE_NUM(pages, scale);
342+
if (num >= 0) {
343+
addr = __TLBI_VADDR_RANGE(start, asid, scale,
344+
num, tlb_level);
345+
if (last_level) {
346+
__tlbi(rvale1is, addr);
347+
__tlbi_user(rvale1is, addr);
348+
} else {
349+
__tlbi(rvae1is, addr);
350+
__tlbi_user(rvae1is, addr);
351+
}
352+
start += __TLBI_RANGE_PAGES(num, scale) << PAGE_SHIFT;
353+
pages -= __TLBI_RANGE_PAGES(num, scale);
209354
}
355+
scale++;
210356
}
211357
dsb(ish);
212358
}
@@ -217,8 +363,9 @@ static inline void flush_tlb_range(struct vm_area_struct *vma,
217363
/*
218364
* We cannot use leaf-only invalidation here, since we may be invalidating
219365
* table entries as part of collapsing hugepages or moving page tables.
366+
* Set the tlb_level to 0 because we can not get enough information here.
220367
*/
221-
__flush_tlb_range(vma, start, end, PAGE_SIZE, false);
368+
__flush_tlb_range(vma, start, end, PAGE_SIZE, false, 0);
222369
}
223370

224371
static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end)

0 commit comments

Comments
 (0)