|
60 | 60 | __ta; \
|
61 | 61 | })
|
62 | 62 |
|
| 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 | + |
63 | 88 | /*
|
64 | 89 | * Level-based TLBI operations.
|
65 | 90 | *
|
|
73 | 98 | * in asm/stage2_pgtable.h.
|
74 | 99 | */
|
75 | 100 | #define TLBI_TTL_MASK GENMASK_ULL(47, 44)
|
76 |
| -#define TLBI_TTL_TG_4K 1 |
77 |
| -#define TLBI_TTL_TG_16K 2 |
78 |
| -#define TLBI_TTL_TG_64K 3 |
79 | 101 |
|
80 | 102 | #define __tlbi_level(op, addr, level) do { \
|
81 | 103 | u64 arg = addr; \
|
82 | 104 | \
|
83 | 105 | if (cpus_have_const_cap(ARM64_HAS_ARMv8_4_TTL) && \
|
84 | 106 | level) { \
|
85 | 107 | u64 ttl = level & 3; \
|
86 |
| - \ |
87 |
| - switch (PAGE_SIZE) { \ |
88 |
| - case SZ_4K: \ |
89 |
| - ttl |= TLBI_TTL_TG_4K << 2; \ |
90 |
| - break; \ |
91 |
| - case SZ_16K: \ |
92 |
| - ttl |= TLBI_TTL_TG_16K << 2; \ |
93 |
| - break; \ |
94 |
| - case SZ_64K: \ |
95 |
| - ttl |= TLBI_TTL_TG_64K << 2; \ |
96 |
| - break; \ |
97 |
| - } \ |
98 |
| - \ |
| 108 | + ttl |= get_trans_granule() << 2; \ |
99 | 109 | arg &= ~TLBI_TTL_MASK; \
|
100 | 110 | arg |= FIELD_PREP(TLBI_TTL_MASK, ttl); \
|
101 | 111 | } \
|
|
108 | 118 | __tlbi_level(op, (arg | USER_ASID_FLAG), level); \
|
109 | 119 | } while (0)
|
110 | 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 | + |
111 | 159 | /*
|
112 | 160 | * TLB Invalidation
|
113 | 161 | * ================
|
@@ -231,32 +279,80 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma,
|
231 | 279 | unsigned long stride, bool last_level,
|
232 | 280 | int tlb_level)
|
233 | 281 | {
|
| 282 | + int num = 0; |
| 283 | + int scale = 0; |
234 | 284 | unsigned long asid = ASID(vma->vm_mm);
|
235 | 285 | unsigned long addr;
|
| 286 | + unsigned long pages; |
236 | 287 |
|
237 | 288 | start = round_down(start, stride);
|
238 | 289 | end = round_up(end, stride);
|
| 290 | + pages = (end - start) >> PAGE_SHIFT; |
239 | 291 |
|
240 |
| - 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) { |
241 | 301 | flush_tlb_mm(vma->vm_mm);
|
242 | 302 | return;
|
243 | 303 | }
|
244 | 304 |
|
245 |
| - /* Convert the stride into units of 4k */ |
246 |
| - stride >>= 12; |
| 305 | + dsb(ishst); |
247 | 306 |
|
248 |
| - start = __TLBI_VADDR(start, asid); |
249 |
| - 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 | + } |
250 | 340 |
|
251 |
| - dsb(ishst); |
252 |
| - for (addr = start; addr < end; addr += stride) { |
253 |
| - if (last_level) { |
254 |
| - __tlbi_level(vale1is, addr, tlb_level); |
255 |
| - __tlbi_user_level(vale1is, addr, tlb_level); |
256 |
| - } else { |
257 |
| - __tlbi_level(vae1is, addr, tlb_level); |
258 |
| - __tlbi_user_level(vae1is, addr, tlb_level); |
| 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); |
259 | 354 | }
|
| 355 | + scale++; |
260 | 356 | }
|
261 | 357 | dsb(ish);
|
262 | 358 | }
|
|
0 commit comments