Skip to content

Commit c910f2b

Browse files
ryanhrobMarc Zyngier
authored andcommitted
arm64/mm: Update tlb invalidation routines for FEAT_LPA2
FEAT_LPA2 impacts tlb invalidation in 2 ways; Firstly, the TTL field in the non-range tlbi instructions can now validly take a 0 value as a level hint for the 4KB granule (this is due to the extra level of translation) - previously TTL=0b0100 meant no hint and was treated as 0b0000. Secondly, The BADDR field of the range-based tlbi instructions is specified in 64KB units when LPA2 is in use (TCR.DS=1), whereas it is in page units otherwise. Changes are required for tlbi to continue to operate correctly when LPA2 is in use. Solve the first problem by always adding the level hint if the level is between [0, 3] (previously anything other than 0 was hinted, which breaks in the new level -1 case from kvm). When running on non-LPA2 HW, 0 is still safe to hint as the HW will fall back to non-hinted. While we are at it, we replace the notion of 0 being the non-hinted sentinel with a macro, TLBI_TTL_UNKNOWN. This means callers won't need updating if/when translation depth increases in future. The second issue is more complex: When LPA2 is in use, use the non-range tlbi instructions to forward align to a 64KB boundary first, then use range-based tlbi from there on, until we have either invalidated all pages or we have a single page remaining. If the latter, that is done with non-range tlbi. We determine whether LPA2 is in use based on lpa2_is_enabled() (for kernel calls) or kvm_lpa2_is_enabled() (for kvm calls). Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> Reviewed-by: Oliver Upton <oliver.upton@linux.dev> Signed-off-by: Ryan Roberts <ryan.roberts@arm.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20231127111737.1897081-4-ryan.roberts@arm.com
1 parent 936a4ec commit c910f2b

2 files changed

Lines changed: 68 additions & 37 deletions

File tree

arch/arm64/include/asm/tlb.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@ static void tlb_flush(struct mmu_gather *tlb);
2222
#include <asm-generic/tlb.h>
2323

2424
/*
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.
25+
* get the tlbi levels in arm64. Default value is TLBI_TTL_UNKNOWN if more than
26+
* one of cleared_* is set or neither is set - this elides the level hinting to
27+
* the hardware.
2828
*/
2929
static inline int tlb_get_level(struct mmu_gather *tlb)
3030
{
3131
/* The TTL field is only valid for the leaf entry. */
3232
if (tlb->freed_tables)
33-
return 0;
33+
return TLBI_TTL_UNKNOWN;
3434

3535
if (tlb->cleared_ptes && !(tlb->cleared_pmds ||
3636
tlb->cleared_puds ||
@@ -47,7 +47,12 @@ static inline int tlb_get_level(struct mmu_gather *tlb)
4747
tlb->cleared_p4ds))
4848
return 1;
4949

50-
return 0;
50+
if (tlb->cleared_p4ds && !(tlb->cleared_ptes ||
51+
tlb->cleared_pmds ||
52+
tlb->cleared_puds))
53+
return 0;
54+
55+
return TLBI_TTL_UNKNOWN;
5156
}
5257

5358
static inline void tlb_flush(struct mmu_gather *tlb)

arch/arm64/include/asm/tlbflush.h

Lines changed: 58 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -94,19 +94,22 @@ static inline unsigned long get_trans_granule(void)
9494
* When ARMv8.4-TTL exists, TLBI operations take an additional hint for
9595
* the level at which the invalidation must take place. If the level is
9696
* wrong, no invalidation may take place. In the case where the level
97-
* cannot be easily determined, a 0 value for the level parameter will
98-
* perform a non-hinted invalidation.
97+
* cannot be easily determined, the value TLBI_TTL_UNKNOWN will perform
98+
* a non-hinted invalidation. Any provided level outside the hint range
99+
* will also cause fall-back to non-hinted invalidation.
99100
*
100101
* For Stage-2 invalidation, use the level values provided to that effect
101102
* in asm/stage2_pgtable.h.
102103
*/
103104
#define TLBI_TTL_MASK GENMASK_ULL(47, 44)
104105

106+
#define TLBI_TTL_UNKNOWN INT_MAX
107+
105108
#define __tlbi_level(op, addr, level) do { \
106109
u64 arg = addr; \
107110
\
108111
if (alternative_has_cap_unlikely(ARM64_HAS_ARMv8_4_TTL) && \
109-
level) { \
112+
level >= 0 && level <= 3) { \
110113
u64 ttl = level & 3; \
111114
ttl |= get_trans_granule() << 2; \
112115
arg &= ~TLBI_TTL_MASK; \
@@ -122,28 +125,34 @@ static inline unsigned long get_trans_granule(void)
122125
} while (0)
123126

124127
/*
125-
* This macro creates a properly formatted VA operand for the TLB RANGE.
126-
* The value bit assignments are:
128+
* This macro creates a properly formatted VA operand for the TLB RANGE. The
129+
* value bit assignments are:
127130
*
128131
* +----------+------+-------+-------+-------+----------------------+
129132
* | ASID | TG | SCALE | NUM | TTL | BADDR |
130133
* +-----------------+-------+-------+-------+----------------------+
131134
* |63 48|47 46|45 44|43 39|38 37|36 0|
132135
*
133-
* The address range is determined by below formula:
134-
* [BADDR, BADDR + (NUM + 1) * 2^(5*SCALE + 1) * PAGESIZE)
136+
* The address range is determined by below formula: [BADDR, BADDR + (NUM + 1) *
137+
* 2^(5*SCALE + 1) * PAGESIZE)
138+
*
139+
* Note that the first argument, baddr, is pre-shifted; If LPA2 is in use, BADDR
140+
* holds addr[52:16]. Else BADDR holds page number. See for example ARM DDI
141+
* 0487J.a section C5.5.60 "TLBI VAE1IS, TLBI VAE1ISNXS, TLB Invalidate by VA,
142+
* EL1, Inner Shareable".
135143
*
136144
*/
137-
#define __TLBI_VADDR_RANGE(addr, asid, scale, num, ttl) \
138-
({ \
139-
unsigned long __ta = (addr) >> PAGE_SHIFT; \
140-
__ta &= GENMASK_ULL(36, 0); \
141-
__ta |= (unsigned long)(ttl) << 37; \
142-
__ta |= (unsigned long)(num) << 39; \
143-
__ta |= (unsigned long)(scale) << 44; \
144-
__ta |= get_trans_granule() << 46; \
145-
__ta |= (unsigned long)(asid) << 48; \
146-
__ta; \
145+
#define __TLBI_VADDR_RANGE(baddr, asid, scale, num, ttl) \
146+
({ \
147+
unsigned long __ta = (baddr); \
148+
unsigned long __ttl = (ttl >= 1 && ttl <= 3) ? ttl : 0; \
149+
__ta &= GENMASK_ULL(36, 0); \
150+
__ta |= __ttl << 37; \
151+
__ta |= (unsigned long)(num) << 39; \
152+
__ta |= (unsigned long)(scale) << 44; \
153+
__ta |= get_trans_granule() << 46; \
154+
__ta |= (unsigned long)(asid) << 48; \
155+
__ta; \
147156
})
148157

149158
/* These macros are used by the TLBI RANGE feature. */
@@ -216,12 +225,16 @@ static inline unsigned long get_trans_granule(void)
216225
* CPUs, ensuring that any walk-cache entries associated with the
217226
* translation are also invalidated.
218227
*
219-
* __flush_tlb_range(vma, start, end, stride, last_level)
228+
* __flush_tlb_range(vma, start, end, stride, last_level, tlb_level)
220229
* Invalidate the virtual-address range '[start, end)' on all
221230
* CPUs for the user address space corresponding to 'vma->mm'.
222231
* The invalidation operations are issued at a granularity
223232
* determined by 'stride' and only affect any walk-cache entries
224-
* if 'last_level' is equal to false.
233+
* if 'last_level' is equal to false. tlb_level is the level at
234+
* which the invalidation must take place. If the level is wrong,
235+
* no invalidation may take place. In the case where the level
236+
* cannot be easily determined, the value TLBI_TTL_UNKNOWN will
237+
* perform a non-hinted invalidation.
225238
*
226239
*
227240
* Finally, take a look at asm/tlb.h to see how tlb_flush() is implemented
@@ -345,34 +358,44 @@ static inline void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch)
345358
* @tlb_level: Translation Table level hint, if known
346359
* @tlbi_user: If 'true', call an additional __tlbi_user()
347360
* (typically for user ASIDs). 'flase' for IPA instructions
361+
* @lpa2: If 'true', the lpa2 scheme is used as set out below
348362
*
349363
* When the CPU does not support TLB range operations, flush the TLB
350364
* entries one by one at the granularity of 'stride'. If the TLB
351365
* range ops are supported, then:
352366
*
353-
* 1. The minimum range granularity is decided by 'scale', so multiple range
367+
* 1. If FEAT_LPA2 is in use, the start address of a range operation must be
368+
* 64KB aligned, so flush pages one by one until the alignment is reached
369+
* using the non-range operations. This step is skipped if LPA2 is not in
370+
* use.
371+
*
372+
* 2. The minimum range granularity is decided by 'scale', so multiple range
354373
* TLBI operations may be required. Start from scale = 3, flush the largest
355374
* possible number of pages ((num+1)*2^(5*scale+1)) that fit into the
356375
* requested range, then decrement scale and continue until one or zero pages
357-
* are left.
376+
* are left. We must start from highest scale to ensure 64KB start alignment
377+
* is maintained in the LPA2 case.
358378
*
359-
* 2. If there is 1 page remaining, flush it through non-range operations. Range
360-
* operations can only span an even number of pages.
379+
* 3. If there is 1 page remaining, flush it through non-range operations. Range
380+
* operations can only span an even number of pages. We save this for last to
381+
* ensure 64KB start alignment is maintained for the LPA2 case.
361382
*
362383
* Note that certain ranges can be represented by either num = 31 and
363384
* scale or num = 0 and scale + 1. The loop below favours the latter
364385
* since num is limited to 30 by the __TLBI_RANGE_NUM() macro.
365386
*/
366387
#define __flush_tlb_range_op(op, start, pages, stride, \
367-
asid, tlb_level, tlbi_user) \
388+
asid, tlb_level, tlbi_user, lpa2) \
368389
do { \
369390
int num = 0; \
370391
int scale = 3; \
392+
int shift = lpa2 ? 16 : PAGE_SHIFT; \
371393
unsigned long addr; \
372394
\
373395
while (pages > 0) { \
374396
if (!system_supports_tlb_range() || \
375-
pages == 1) { \
397+
pages == 1 || \
398+
(lpa2 && start != ALIGN(start, SZ_64K))) { \
376399
addr = __TLBI_VADDR(start, asid); \
377400
__tlbi_level(op, addr, tlb_level); \
378401
if (tlbi_user) \
@@ -384,8 +407,8 @@ do { \
384407
\
385408
num = __TLBI_RANGE_NUM(pages, scale); \
386409
if (num >= 0) { \
387-
addr = __TLBI_VADDR_RANGE(start, asid, scale, \
388-
num, tlb_level); \
410+
addr = __TLBI_VADDR_RANGE(start >> shift, asid, \
411+
scale, num, tlb_level); \
389412
__tlbi(r##op, addr); \
390413
if (tlbi_user) \
391414
__tlbi_user(r##op, addr); \
@@ -397,7 +420,7 @@ do { \
397420
} while (0)
398421

399422
#define __flush_s2_tlb_range_op(op, start, pages, stride, tlb_level) \
400-
__flush_tlb_range_op(op, start, pages, stride, 0, tlb_level, false)
423+
__flush_tlb_range_op(op, start, pages, stride, 0, tlb_level, false, kvm_lpa2_is_enabled());
401424

402425
static inline void __flush_tlb_range(struct vm_area_struct *vma,
403426
unsigned long start, unsigned long end,
@@ -427,9 +450,11 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma,
427450
asid = ASID(vma->vm_mm);
428451

429452
if (last_level)
430-
__flush_tlb_range_op(vale1is, start, pages, stride, asid, tlb_level, true);
453+
__flush_tlb_range_op(vale1is, start, pages, stride, asid,
454+
tlb_level, true, lpa2_is_enabled());
431455
else
432-
__flush_tlb_range_op(vae1is, start, pages, stride, asid, tlb_level, true);
456+
__flush_tlb_range_op(vae1is, start, pages, stride, asid,
457+
tlb_level, true, lpa2_is_enabled());
433458

434459
dsb(ish);
435460
mmu_notifier_arch_invalidate_secondary_tlbs(vma->vm_mm, start, end);
@@ -441,9 +466,10 @@ static inline void flush_tlb_range(struct vm_area_struct *vma,
441466
/*
442467
* We cannot use leaf-only invalidation here, since we may be invalidating
443468
* table entries as part of collapsing hugepages or moving page tables.
444-
* Set the tlb_level to 0 because we can not get enough information here.
469+
* Set the tlb_level to TLBI_TTL_UNKNOWN because we can not get enough
470+
* information here.
445471
*/
446-
__flush_tlb_range(vma, start, end, PAGE_SIZE, false, 0);
472+
__flush_tlb_range(vma, start, end, PAGE_SIZE, false, TLBI_TTL_UNKNOWN);
447473
}
448474

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

0 commit comments

Comments
 (0)