18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Based on arch/arm/include/asm/tlbflush.h 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1999-2003 Russell King 68c2ecf20Sopenharmony_ci * Copyright (C) 2012 ARM Ltd. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#ifndef __ASM_TLBFLUSH_H 98c2ecf20Sopenharmony_ci#define __ASM_TLBFLUSH_H 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#ifndef __ASSEMBLY__ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 148c2ecf20Sopenharmony_ci#include <linux/mm_types.h> 158c2ecf20Sopenharmony_ci#include <linux/sched.h> 168c2ecf20Sopenharmony_ci#include <asm/cputype.h> 178c2ecf20Sopenharmony_ci#include <asm/mmu.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* 208c2ecf20Sopenharmony_ci * Raw TLBI operations. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Where necessary, use the __tlbi() macro to avoid asm() 238c2ecf20Sopenharmony_ci * boilerplate. Drivers and most kernel code should use the TLB 248c2ecf20Sopenharmony_ci * management routines in preference to the macro below. 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * The macro can be used as __tlbi(op) or __tlbi(op, arg), depending 278c2ecf20Sopenharmony_ci * on whether a particular TLBI operation takes an argument or 288c2ecf20Sopenharmony_ci * not. The macros handles invoking the asm with or without the 298c2ecf20Sopenharmony_ci * register argument as appropriate. 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_ci#define __TLBI_0(op, arg) asm (ARM64_ASM_PREAMBLE \ 328c2ecf20Sopenharmony_ci "tlbi " #op "\n" \ 338c2ecf20Sopenharmony_ci ALTERNATIVE("nop\n nop", \ 348c2ecf20Sopenharmony_ci "dsb ish\n tlbi " #op, \ 358c2ecf20Sopenharmony_ci ARM64_WORKAROUND_REPEAT_TLBI, \ 368c2ecf20Sopenharmony_ci CONFIG_ARM64_WORKAROUND_REPEAT_TLBI) \ 378c2ecf20Sopenharmony_ci : : ) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define __TLBI_1(op, arg) asm (ARM64_ASM_PREAMBLE \ 408c2ecf20Sopenharmony_ci "tlbi " #op ", %0\n" \ 418c2ecf20Sopenharmony_ci ALTERNATIVE("nop\n nop", \ 428c2ecf20Sopenharmony_ci "dsb ish\n tlbi " #op ", %0", \ 438c2ecf20Sopenharmony_ci ARM64_WORKAROUND_REPEAT_TLBI, \ 448c2ecf20Sopenharmony_ci CONFIG_ARM64_WORKAROUND_REPEAT_TLBI) \ 458c2ecf20Sopenharmony_ci : : "r" (arg)) 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define __TLBI_N(op, arg, n, ...) __TLBI_##n(op, arg) 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define __tlbi(op, ...) __TLBI_N(op, ##__VA_ARGS__, 1, 0) 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define __tlbi_user(op, arg) do { \ 528c2ecf20Sopenharmony_ci if (arm64_kernel_unmapped_at_el0()) \ 538c2ecf20Sopenharmony_ci __tlbi(op, (arg) | USER_ASID_FLAG); \ 548c2ecf20Sopenharmony_ci} while (0) 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* This macro creates a properly formatted VA operand for the TLBI */ 578c2ecf20Sopenharmony_ci#define __TLBI_VADDR(addr, asid) \ 588c2ecf20Sopenharmony_ci ({ \ 598c2ecf20Sopenharmony_ci unsigned long __ta = (addr) >> 12; \ 608c2ecf20Sopenharmony_ci __ta &= GENMASK_ULL(43, 0); \ 618c2ecf20Sopenharmony_ci __ta |= (unsigned long)(asid) << 48; \ 628c2ecf20Sopenharmony_ci __ta; \ 638c2ecf20Sopenharmony_ci }) 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* 668c2ecf20Sopenharmony_ci * Get translation granule of the system, which is decided by 678c2ecf20Sopenharmony_ci * PAGE_SIZE. Used by TTL. 688c2ecf20Sopenharmony_ci * - 4KB : 1 698c2ecf20Sopenharmony_ci * - 16KB : 2 708c2ecf20Sopenharmony_ci * - 64KB : 3 718c2ecf20Sopenharmony_ci */ 728c2ecf20Sopenharmony_ci#define TLBI_TTL_TG_4K 1 738c2ecf20Sopenharmony_ci#define TLBI_TTL_TG_16K 2 748c2ecf20Sopenharmony_ci#define TLBI_TTL_TG_64K 3 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic inline unsigned long get_trans_granule(void) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci switch (PAGE_SIZE) { 798c2ecf20Sopenharmony_ci case SZ_4K: 808c2ecf20Sopenharmony_ci return TLBI_TTL_TG_4K; 818c2ecf20Sopenharmony_ci case SZ_16K: 828c2ecf20Sopenharmony_ci return TLBI_TTL_TG_16K; 838c2ecf20Sopenharmony_ci case SZ_64K: 848c2ecf20Sopenharmony_ci return TLBI_TTL_TG_64K; 858c2ecf20Sopenharmony_ci default: 868c2ecf20Sopenharmony_ci return 0; 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/* 918c2ecf20Sopenharmony_ci * Level-based TLBI operations. 928c2ecf20Sopenharmony_ci * 938c2ecf20Sopenharmony_ci * When ARMv8.4-TTL exists, TLBI operations take an additional hint for 948c2ecf20Sopenharmony_ci * the level at which the invalidation must take place. If the level is 958c2ecf20Sopenharmony_ci * wrong, no invalidation may take place. In the case where the level 968c2ecf20Sopenharmony_ci * cannot be easily determined, a 0 value for the level parameter will 978c2ecf20Sopenharmony_ci * perform a non-hinted invalidation. 988c2ecf20Sopenharmony_ci * 998c2ecf20Sopenharmony_ci * For Stage-2 invalidation, use the level values provided to that effect 1008c2ecf20Sopenharmony_ci * in asm/stage2_pgtable.h. 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_ci#define TLBI_TTL_MASK GENMASK_ULL(47, 44) 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci#define __tlbi_level(op, addr, level) do { \ 1058c2ecf20Sopenharmony_ci u64 arg = addr; \ 1068c2ecf20Sopenharmony_ci \ 1078c2ecf20Sopenharmony_ci if (cpus_have_const_cap(ARM64_HAS_ARMv8_4_TTL) && \ 1088c2ecf20Sopenharmony_ci level) { \ 1098c2ecf20Sopenharmony_ci u64 ttl = level & 3; \ 1108c2ecf20Sopenharmony_ci ttl |= get_trans_granule() << 2; \ 1118c2ecf20Sopenharmony_ci arg &= ~TLBI_TTL_MASK; \ 1128c2ecf20Sopenharmony_ci arg |= FIELD_PREP(TLBI_TTL_MASK, ttl); \ 1138c2ecf20Sopenharmony_ci } \ 1148c2ecf20Sopenharmony_ci \ 1158c2ecf20Sopenharmony_ci __tlbi(op, arg); \ 1168c2ecf20Sopenharmony_ci} while(0) 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci#define __tlbi_user_level(op, arg, level) do { \ 1198c2ecf20Sopenharmony_ci if (arm64_kernel_unmapped_at_el0()) \ 1208c2ecf20Sopenharmony_ci __tlbi_level(op, (arg | USER_ASID_FLAG), level); \ 1218c2ecf20Sopenharmony_ci} while (0) 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/* 1248c2ecf20Sopenharmony_ci * This macro creates a properly formatted VA operand for the TLB RANGE. 1258c2ecf20Sopenharmony_ci * The value bit assignments are: 1268c2ecf20Sopenharmony_ci * 1278c2ecf20Sopenharmony_ci * +----------+------+-------+-------+-------+----------------------+ 1288c2ecf20Sopenharmony_ci * | ASID | TG | SCALE | NUM | TTL | BADDR | 1298c2ecf20Sopenharmony_ci * +-----------------+-------+-------+-------+----------------------+ 1308c2ecf20Sopenharmony_ci * |63 48|47 46|45 44|43 39|38 37|36 0| 1318c2ecf20Sopenharmony_ci * 1328c2ecf20Sopenharmony_ci * The address range is determined by below formula: 1338c2ecf20Sopenharmony_ci * [BADDR, BADDR + (NUM + 1) * 2^(5*SCALE + 1) * PAGESIZE) 1348c2ecf20Sopenharmony_ci * 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_ci#define __TLBI_VADDR_RANGE(addr, asid, scale, num, ttl) \ 1378c2ecf20Sopenharmony_ci ({ \ 1388c2ecf20Sopenharmony_ci unsigned long __ta = (addr) >> PAGE_SHIFT; \ 1398c2ecf20Sopenharmony_ci __ta &= GENMASK_ULL(36, 0); \ 1408c2ecf20Sopenharmony_ci __ta |= (unsigned long)(ttl) << 37; \ 1418c2ecf20Sopenharmony_ci __ta |= (unsigned long)(num) << 39; \ 1428c2ecf20Sopenharmony_ci __ta |= (unsigned long)(scale) << 44; \ 1438c2ecf20Sopenharmony_ci __ta |= get_trans_granule() << 46; \ 1448c2ecf20Sopenharmony_ci __ta |= (unsigned long)(asid) << 48; \ 1458c2ecf20Sopenharmony_ci __ta; \ 1468c2ecf20Sopenharmony_ci }) 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci/* These macros are used by the TLBI RANGE feature. */ 1498c2ecf20Sopenharmony_ci#define __TLBI_RANGE_PAGES(num, scale) \ 1508c2ecf20Sopenharmony_ci ((unsigned long)((num) + 1) << (5 * (scale) + 1)) 1518c2ecf20Sopenharmony_ci#define MAX_TLBI_RANGE_PAGES __TLBI_RANGE_PAGES(31, 3) 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci/* 1548c2ecf20Sopenharmony_ci * Generate 'num' values from -1 to 30 with -1 rejected by the 1558c2ecf20Sopenharmony_ci * __flush_tlb_range() loop below. 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_ci#define TLBI_RANGE_MASK GENMASK_ULL(4, 0) 1588c2ecf20Sopenharmony_ci#define __TLBI_RANGE_NUM(pages, scale) \ 1598c2ecf20Sopenharmony_ci ((((pages) >> (5 * (scale) + 1)) & TLBI_RANGE_MASK) - 1) 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci/* 1628c2ecf20Sopenharmony_ci * TLB Invalidation 1638c2ecf20Sopenharmony_ci * ================ 1648c2ecf20Sopenharmony_ci * 1658c2ecf20Sopenharmony_ci * This header file implements the low-level TLB invalidation routines 1668c2ecf20Sopenharmony_ci * (sometimes referred to as "flushing" in the kernel) for arm64. 1678c2ecf20Sopenharmony_ci * 1688c2ecf20Sopenharmony_ci * Every invalidation operation uses the following template: 1698c2ecf20Sopenharmony_ci * 1708c2ecf20Sopenharmony_ci * DSB ISHST // Ensure prior page-table updates have completed 1718c2ecf20Sopenharmony_ci * TLBI ... // Invalidate the TLB 1728c2ecf20Sopenharmony_ci * DSB ISH // Ensure the TLB invalidation has completed 1738c2ecf20Sopenharmony_ci * if (invalidated kernel mappings) 1748c2ecf20Sopenharmony_ci * ISB // Discard any instructions fetched from the old mapping 1758c2ecf20Sopenharmony_ci * 1768c2ecf20Sopenharmony_ci * 1778c2ecf20Sopenharmony_ci * The following functions form part of the "core" TLB invalidation API, 1788c2ecf20Sopenharmony_ci * as documented in Documentation/core-api/cachetlb.rst: 1798c2ecf20Sopenharmony_ci * 1808c2ecf20Sopenharmony_ci * flush_tlb_all() 1818c2ecf20Sopenharmony_ci * Invalidate the entire TLB (kernel + user) on all CPUs 1828c2ecf20Sopenharmony_ci * 1838c2ecf20Sopenharmony_ci * flush_tlb_mm(mm) 1848c2ecf20Sopenharmony_ci * Invalidate an entire user address space on all CPUs. 1858c2ecf20Sopenharmony_ci * The 'mm' argument identifies the ASID to invalidate. 1868c2ecf20Sopenharmony_ci * 1878c2ecf20Sopenharmony_ci * flush_tlb_range(vma, start, end) 1888c2ecf20Sopenharmony_ci * Invalidate the virtual-address range '[start, end)' on all 1898c2ecf20Sopenharmony_ci * CPUs for the user address space corresponding to 'vma->mm'. 1908c2ecf20Sopenharmony_ci * Note that this operation also invalidates any walk-cache 1918c2ecf20Sopenharmony_ci * entries associated with translations for the specified address 1928c2ecf20Sopenharmony_ci * range. 1938c2ecf20Sopenharmony_ci * 1948c2ecf20Sopenharmony_ci * flush_tlb_kernel_range(start, end) 1958c2ecf20Sopenharmony_ci * Same as flush_tlb_range(..., start, end), but applies to 1968c2ecf20Sopenharmony_ci * kernel mappings rather than a particular user address space. 1978c2ecf20Sopenharmony_ci * Whilst not explicitly documented, this function is used when 1988c2ecf20Sopenharmony_ci * unmapping pages from vmalloc/io space. 1998c2ecf20Sopenharmony_ci * 2008c2ecf20Sopenharmony_ci * flush_tlb_page(vma, addr) 2018c2ecf20Sopenharmony_ci * Invalidate a single user mapping for address 'addr' in the 2028c2ecf20Sopenharmony_ci * address space corresponding to 'vma->mm'. Note that this 2038c2ecf20Sopenharmony_ci * operation only invalidates a single, last-level page-table 2048c2ecf20Sopenharmony_ci * entry and therefore does not affect any walk-caches. 2058c2ecf20Sopenharmony_ci * 2068c2ecf20Sopenharmony_ci * 2078c2ecf20Sopenharmony_ci * Next, we have some undocumented invalidation routines that you probably 2088c2ecf20Sopenharmony_ci * don't want to call unless you know what you're doing: 2098c2ecf20Sopenharmony_ci * 2108c2ecf20Sopenharmony_ci * local_flush_tlb_all() 2118c2ecf20Sopenharmony_ci * Same as flush_tlb_all(), but only applies to the calling CPU. 2128c2ecf20Sopenharmony_ci * 2138c2ecf20Sopenharmony_ci * __flush_tlb_kernel_pgtable(addr) 2148c2ecf20Sopenharmony_ci * Invalidate a single kernel mapping for address 'addr' on all 2158c2ecf20Sopenharmony_ci * CPUs, ensuring that any walk-cache entries associated with the 2168c2ecf20Sopenharmony_ci * translation are also invalidated. 2178c2ecf20Sopenharmony_ci * 2188c2ecf20Sopenharmony_ci * __flush_tlb_range(vma, start, end, stride, last_level) 2198c2ecf20Sopenharmony_ci * Invalidate the virtual-address range '[start, end)' on all 2208c2ecf20Sopenharmony_ci * CPUs for the user address space corresponding to 'vma->mm'. 2218c2ecf20Sopenharmony_ci * The invalidation operations are issued at a granularity 2228c2ecf20Sopenharmony_ci * determined by 'stride' and only affect any walk-cache entries 2238c2ecf20Sopenharmony_ci * if 'last_level' is equal to false. 2248c2ecf20Sopenharmony_ci * 2258c2ecf20Sopenharmony_ci * 2268c2ecf20Sopenharmony_ci * Finally, take a look at asm/tlb.h to see how tlb_flush() is implemented 2278c2ecf20Sopenharmony_ci * on top of these routines, since that is our interface to the mmu_gather 2288c2ecf20Sopenharmony_ci * API as used by munmap() and friends. 2298c2ecf20Sopenharmony_ci */ 2308c2ecf20Sopenharmony_cistatic inline void local_flush_tlb_all(void) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci dsb(nshst); 2338c2ecf20Sopenharmony_ci __tlbi(vmalle1); 2348c2ecf20Sopenharmony_ci dsb(nsh); 2358c2ecf20Sopenharmony_ci isb(); 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic inline void flush_tlb_all(void) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci dsb(ishst); 2418c2ecf20Sopenharmony_ci __tlbi(vmalle1is); 2428c2ecf20Sopenharmony_ci dsb(ish); 2438c2ecf20Sopenharmony_ci isb(); 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic inline void flush_tlb_mm(struct mm_struct *mm) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci unsigned long asid; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci dsb(ishst); 2518c2ecf20Sopenharmony_ci asid = __TLBI_VADDR(0, ASID(mm)); 2528c2ecf20Sopenharmony_ci __tlbi(aside1is, asid); 2538c2ecf20Sopenharmony_ci __tlbi_user(aside1is, asid); 2548c2ecf20Sopenharmony_ci dsb(ish); 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic inline void flush_tlb_page_nosync(struct vm_area_struct *vma, 2588c2ecf20Sopenharmony_ci unsigned long uaddr) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci unsigned long addr; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci dsb(ishst); 2638c2ecf20Sopenharmony_ci addr = __TLBI_VADDR(uaddr, ASID(vma->vm_mm)); 2648c2ecf20Sopenharmony_ci __tlbi(vale1is, addr); 2658c2ecf20Sopenharmony_ci __tlbi_user(vale1is, addr); 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic inline void flush_tlb_page(struct vm_area_struct *vma, 2698c2ecf20Sopenharmony_ci unsigned long uaddr) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci flush_tlb_page_nosync(vma, uaddr); 2728c2ecf20Sopenharmony_ci dsb(ish); 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci/* 2768c2ecf20Sopenharmony_ci * This is meant to avoid soft lock-ups on large TLB flushing ranges and not 2778c2ecf20Sopenharmony_ci * necessarily a performance improvement. 2788c2ecf20Sopenharmony_ci */ 2798c2ecf20Sopenharmony_ci#define MAX_TLBI_OPS PTRS_PER_PTE 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic inline void __flush_tlb_range(struct vm_area_struct *vma, 2828c2ecf20Sopenharmony_ci unsigned long start, unsigned long end, 2838c2ecf20Sopenharmony_ci unsigned long stride, bool last_level, 2848c2ecf20Sopenharmony_ci int tlb_level) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci int num = 0; 2878c2ecf20Sopenharmony_ci int scale = 0; 2888c2ecf20Sopenharmony_ci unsigned long asid, addr, pages; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci start = round_down(start, stride); 2918c2ecf20Sopenharmony_ci end = round_up(end, stride); 2928c2ecf20Sopenharmony_ci pages = (end - start) >> PAGE_SHIFT; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* 2958c2ecf20Sopenharmony_ci * When not uses TLB range ops, we can handle up to 2968c2ecf20Sopenharmony_ci * (MAX_TLBI_OPS - 1) pages; 2978c2ecf20Sopenharmony_ci * When uses TLB range ops, we can handle up to 2988c2ecf20Sopenharmony_ci * (MAX_TLBI_RANGE_PAGES - 1) pages. 2998c2ecf20Sopenharmony_ci */ 3008c2ecf20Sopenharmony_ci if ((!system_supports_tlb_range() && 3018c2ecf20Sopenharmony_ci (end - start) >= (MAX_TLBI_OPS * stride)) || 3028c2ecf20Sopenharmony_ci pages >= MAX_TLBI_RANGE_PAGES) { 3038c2ecf20Sopenharmony_ci flush_tlb_mm(vma->vm_mm); 3048c2ecf20Sopenharmony_ci return; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci dsb(ishst); 3088c2ecf20Sopenharmony_ci asid = ASID(vma->vm_mm); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* 3118c2ecf20Sopenharmony_ci * When the CPU does not support TLB range operations, flush the TLB 3128c2ecf20Sopenharmony_ci * entries one by one at the granularity of 'stride'. If the the TLB 3138c2ecf20Sopenharmony_ci * range ops are supported, then: 3148c2ecf20Sopenharmony_ci * 3158c2ecf20Sopenharmony_ci * 1. If 'pages' is odd, flush the first page through non-range 3168c2ecf20Sopenharmony_ci * operations; 3178c2ecf20Sopenharmony_ci * 3188c2ecf20Sopenharmony_ci * 2. For remaining pages: the minimum range granularity is decided 3198c2ecf20Sopenharmony_ci * by 'scale', so multiple range TLBI operations may be required. 3208c2ecf20Sopenharmony_ci * Start from scale = 0, flush the corresponding number of pages 3218c2ecf20Sopenharmony_ci * ((num+1)*2^(5*scale+1) starting from 'addr'), then increase it 3228c2ecf20Sopenharmony_ci * until no pages left. 3238c2ecf20Sopenharmony_ci * 3248c2ecf20Sopenharmony_ci * Note that certain ranges can be represented by either num = 31 and 3258c2ecf20Sopenharmony_ci * scale or num = 0 and scale + 1. The loop below favours the latter 3268c2ecf20Sopenharmony_ci * since num is limited to 30 by the __TLBI_RANGE_NUM() macro. 3278c2ecf20Sopenharmony_ci */ 3288c2ecf20Sopenharmony_ci while (pages > 0) { 3298c2ecf20Sopenharmony_ci if (!system_supports_tlb_range() || 3308c2ecf20Sopenharmony_ci pages % 2 == 1) { 3318c2ecf20Sopenharmony_ci addr = __TLBI_VADDR(start, asid); 3328c2ecf20Sopenharmony_ci if (last_level) { 3338c2ecf20Sopenharmony_ci __tlbi_level(vale1is, addr, tlb_level); 3348c2ecf20Sopenharmony_ci __tlbi_user_level(vale1is, addr, tlb_level); 3358c2ecf20Sopenharmony_ci } else { 3368c2ecf20Sopenharmony_ci __tlbi_level(vae1is, addr, tlb_level); 3378c2ecf20Sopenharmony_ci __tlbi_user_level(vae1is, addr, tlb_level); 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci start += stride; 3408c2ecf20Sopenharmony_ci pages -= stride >> PAGE_SHIFT; 3418c2ecf20Sopenharmony_ci continue; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci num = __TLBI_RANGE_NUM(pages, scale); 3458c2ecf20Sopenharmony_ci if (num >= 0) { 3468c2ecf20Sopenharmony_ci addr = __TLBI_VADDR_RANGE(start, asid, scale, 3478c2ecf20Sopenharmony_ci num, tlb_level); 3488c2ecf20Sopenharmony_ci if (last_level) { 3498c2ecf20Sopenharmony_ci __tlbi(rvale1is, addr); 3508c2ecf20Sopenharmony_ci __tlbi_user(rvale1is, addr); 3518c2ecf20Sopenharmony_ci } else { 3528c2ecf20Sopenharmony_ci __tlbi(rvae1is, addr); 3538c2ecf20Sopenharmony_ci __tlbi_user(rvae1is, addr); 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci start += __TLBI_RANGE_PAGES(num, scale) << PAGE_SHIFT; 3568c2ecf20Sopenharmony_ci pages -= __TLBI_RANGE_PAGES(num, scale); 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci scale++; 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci dsb(ish); 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic inline void flush_tlb_range(struct vm_area_struct *vma, 3648c2ecf20Sopenharmony_ci unsigned long start, unsigned long end) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci /* 3678c2ecf20Sopenharmony_ci * We cannot use leaf-only invalidation here, since we may be invalidating 3688c2ecf20Sopenharmony_ci * table entries as part of collapsing hugepages or moving page tables. 3698c2ecf20Sopenharmony_ci * Set the tlb_level to 0 because we can not get enough information here. 3708c2ecf20Sopenharmony_ci */ 3718c2ecf20Sopenharmony_ci __flush_tlb_range(vma, start, end, PAGE_SIZE, false, 0); 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistatic inline void flush_tlb_kernel_range(unsigned long start, unsigned long end) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci unsigned long addr; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci if ((end - start) > (MAX_TLBI_OPS * PAGE_SIZE)) { 3798c2ecf20Sopenharmony_ci flush_tlb_all(); 3808c2ecf20Sopenharmony_ci return; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci start = __TLBI_VADDR(start, 0); 3848c2ecf20Sopenharmony_ci end = __TLBI_VADDR(end, 0); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci dsb(ishst); 3878c2ecf20Sopenharmony_ci for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12)) 3888c2ecf20Sopenharmony_ci __tlbi(vaale1is, addr); 3898c2ecf20Sopenharmony_ci dsb(ish); 3908c2ecf20Sopenharmony_ci isb(); 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci/* 3948c2ecf20Sopenharmony_ci * Used to invalidate the TLB (walk caches) corresponding to intermediate page 3958c2ecf20Sopenharmony_ci * table levels (pgd/pud/pmd). 3968c2ecf20Sopenharmony_ci */ 3978c2ecf20Sopenharmony_cistatic inline void __flush_tlb_kernel_pgtable(unsigned long kaddr) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci unsigned long addr = __TLBI_VADDR(kaddr, 0); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci dsb(ishst); 4028c2ecf20Sopenharmony_ci __tlbi(vaae1is, addr); 4038c2ecf20Sopenharmony_ci dsb(ish); 4048c2ecf20Sopenharmony_ci isb(); 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci#endif 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci#endif 409