18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * TLB flush routines for radix kernels. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2015-2016, Aneesh Kumar K.V, IBM Corporation. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/mm.h> 98c2ecf20Sopenharmony_ci#include <linux/hugetlb.h> 108c2ecf20Sopenharmony_ci#include <linux/memblock.h> 118c2ecf20Sopenharmony_ci#include <linux/mmu_context.h> 128c2ecf20Sopenharmony_ci#include <linux/sched/mm.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <asm/ppc-opcode.h> 158c2ecf20Sopenharmony_ci#include <asm/tlb.h> 168c2ecf20Sopenharmony_ci#include <asm/tlbflush.h> 178c2ecf20Sopenharmony_ci#include <asm/trace.h> 188c2ecf20Sopenharmony_ci#include <asm/cputhreads.h> 198c2ecf20Sopenharmony_ci#include <asm/plpar_wrappers.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define RIC_FLUSH_TLB 0 228c2ecf20Sopenharmony_ci#define RIC_FLUSH_PWC 1 238c2ecf20Sopenharmony_ci#define RIC_FLUSH_ALL 2 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* 268c2ecf20Sopenharmony_ci * tlbiel instruction for radix, set invalidation 278c2ecf20Sopenharmony_ci * i.e., r=1 and is=01 or is=10 or is=11 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_cistatic __always_inline void tlbiel_radix_set_isa300(unsigned int set, unsigned int is, 308c2ecf20Sopenharmony_ci unsigned int pid, 318c2ecf20Sopenharmony_ci unsigned int ric, unsigned int prs) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci unsigned long rb; 348c2ecf20Sopenharmony_ci unsigned long rs; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci rb = (set << PPC_BITLSHIFT(51)) | (is << PPC_BITLSHIFT(53)); 378c2ecf20Sopenharmony_ci rs = ((unsigned long)pid << PPC_BITLSHIFT(31)); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci asm volatile(PPC_TLBIEL(%0, %1, %2, %3, 1) 408c2ecf20Sopenharmony_ci : : "r"(rb), "r"(rs), "i"(ric), "i"(prs) 418c2ecf20Sopenharmony_ci : "memory"); 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic void tlbiel_all_isa300(unsigned int num_sets, unsigned int is) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci unsigned int set; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci asm volatile("ptesync": : :"memory"); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci /* 518c2ecf20Sopenharmony_ci * Flush the first set of the TLB, and the entire Page Walk Cache 528c2ecf20Sopenharmony_ci * and partition table entries. Then flush the remaining sets of the 538c2ecf20Sopenharmony_ci * TLB. 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if (early_cpu_has_feature(CPU_FTR_HVMODE)) { 578c2ecf20Sopenharmony_ci /* MSR[HV] should flush partition scope translations first. */ 588c2ecf20Sopenharmony_ci tlbiel_radix_set_isa300(0, is, 0, RIC_FLUSH_ALL, 0); 598c2ecf20Sopenharmony_ci for (set = 1; set < num_sets; set++) 608c2ecf20Sopenharmony_ci tlbiel_radix_set_isa300(set, is, 0, RIC_FLUSH_TLB, 0); 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci /* Flush process scoped entries. */ 648c2ecf20Sopenharmony_ci tlbiel_radix_set_isa300(0, is, 0, RIC_FLUSH_ALL, 1); 658c2ecf20Sopenharmony_ci for (set = 1; set < num_sets; set++) 668c2ecf20Sopenharmony_ci tlbiel_radix_set_isa300(set, is, 0, RIC_FLUSH_TLB, 1); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci ppc_after_tlbiel_barrier(); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_civoid radix__tlbiel_all(unsigned int action) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci unsigned int is; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci switch (action) { 768c2ecf20Sopenharmony_ci case TLB_INVAL_SCOPE_GLOBAL: 778c2ecf20Sopenharmony_ci is = 3; 788c2ecf20Sopenharmony_ci break; 798c2ecf20Sopenharmony_ci case TLB_INVAL_SCOPE_LPID: 808c2ecf20Sopenharmony_ci is = 2; 818c2ecf20Sopenharmony_ci break; 828c2ecf20Sopenharmony_ci default: 838c2ecf20Sopenharmony_ci BUG(); 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (early_cpu_has_feature(CPU_FTR_ARCH_300)) 878c2ecf20Sopenharmony_ci tlbiel_all_isa300(POWER9_TLB_SETS_RADIX, is); 888c2ecf20Sopenharmony_ci else 898c2ecf20Sopenharmony_ci WARN(1, "%s called on pre-POWER9 CPU\n", __func__); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci asm volatile(PPC_ISA_3_0_INVALIDATE_ERAT "; isync" : : :"memory"); 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic __always_inline void __tlbiel_pid(unsigned long pid, int set, 958c2ecf20Sopenharmony_ci unsigned long ric) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci unsigned long rb,rs,prs,r; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci rb = PPC_BIT(53); /* IS = 1 */ 1008c2ecf20Sopenharmony_ci rb |= set << PPC_BITLSHIFT(51); 1018c2ecf20Sopenharmony_ci rs = ((unsigned long)pid) << PPC_BITLSHIFT(31); 1028c2ecf20Sopenharmony_ci prs = 1; /* process scoped */ 1038c2ecf20Sopenharmony_ci r = 1; /* radix format */ 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci asm volatile(PPC_TLBIEL(%0, %4, %3, %2, %1) 1068c2ecf20Sopenharmony_ci : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory"); 1078c2ecf20Sopenharmony_ci trace_tlbie(0, 1, rb, rs, ric, prs, r); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic __always_inline void __tlbie_pid(unsigned long pid, unsigned long ric) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci unsigned long rb,rs,prs,r; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci rb = PPC_BIT(53); /* IS = 1 */ 1158c2ecf20Sopenharmony_ci rs = pid << PPC_BITLSHIFT(31); 1168c2ecf20Sopenharmony_ci prs = 1; /* process scoped */ 1178c2ecf20Sopenharmony_ci r = 1; /* radix format */ 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1) 1208c2ecf20Sopenharmony_ci : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory"); 1218c2ecf20Sopenharmony_ci trace_tlbie(0, 0, rb, rs, ric, prs, r); 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic __always_inline void __tlbie_lpid(unsigned long lpid, unsigned long ric) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci unsigned long rb,rs,prs,r; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci rb = PPC_BIT(52); /* IS = 2 */ 1298c2ecf20Sopenharmony_ci rs = lpid; 1308c2ecf20Sopenharmony_ci prs = 0; /* partition scoped */ 1318c2ecf20Sopenharmony_ci r = 1; /* radix format */ 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1) 1348c2ecf20Sopenharmony_ci : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory"); 1358c2ecf20Sopenharmony_ci trace_tlbie(lpid, 0, rb, rs, ric, prs, r); 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic __always_inline void __tlbie_lpid_guest(unsigned long lpid, unsigned long ric) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci unsigned long rb,rs,prs,r; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci rb = PPC_BIT(52); /* IS = 2 */ 1438c2ecf20Sopenharmony_ci rs = lpid; 1448c2ecf20Sopenharmony_ci prs = 1; /* process scoped */ 1458c2ecf20Sopenharmony_ci r = 1; /* radix format */ 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1) 1488c2ecf20Sopenharmony_ci : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory"); 1498c2ecf20Sopenharmony_ci trace_tlbie(lpid, 0, rb, rs, ric, prs, r); 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic __always_inline void __tlbiel_va(unsigned long va, unsigned long pid, 1538c2ecf20Sopenharmony_ci unsigned long ap, unsigned long ric) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci unsigned long rb,rs,prs,r; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci rb = va & ~(PPC_BITMASK(52, 63)); 1588c2ecf20Sopenharmony_ci rb |= ap << PPC_BITLSHIFT(58); 1598c2ecf20Sopenharmony_ci rs = pid << PPC_BITLSHIFT(31); 1608c2ecf20Sopenharmony_ci prs = 1; /* process scoped */ 1618c2ecf20Sopenharmony_ci r = 1; /* radix format */ 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci asm volatile(PPC_TLBIEL(%0, %4, %3, %2, %1) 1648c2ecf20Sopenharmony_ci : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory"); 1658c2ecf20Sopenharmony_ci trace_tlbie(0, 1, rb, rs, ric, prs, r); 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic __always_inline void __tlbie_va(unsigned long va, unsigned long pid, 1698c2ecf20Sopenharmony_ci unsigned long ap, unsigned long ric) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci unsigned long rb,rs,prs,r; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci rb = va & ~(PPC_BITMASK(52, 63)); 1748c2ecf20Sopenharmony_ci rb |= ap << PPC_BITLSHIFT(58); 1758c2ecf20Sopenharmony_ci rs = pid << PPC_BITLSHIFT(31); 1768c2ecf20Sopenharmony_ci prs = 1; /* process scoped */ 1778c2ecf20Sopenharmony_ci r = 1; /* radix format */ 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1) 1808c2ecf20Sopenharmony_ci : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory"); 1818c2ecf20Sopenharmony_ci trace_tlbie(0, 0, rb, rs, ric, prs, r); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic __always_inline void __tlbie_lpid_va(unsigned long va, unsigned long lpid, 1858c2ecf20Sopenharmony_ci unsigned long ap, unsigned long ric) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci unsigned long rb,rs,prs,r; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci rb = va & ~(PPC_BITMASK(52, 63)); 1908c2ecf20Sopenharmony_ci rb |= ap << PPC_BITLSHIFT(58); 1918c2ecf20Sopenharmony_ci rs = lpid; 1928c2ecf20Sopenharmony_ci prs = 0; /* partition scoped */ 1938c2ecf20Sopenharmony_ci r = 1; /* radix format */ 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1) 1968c2ecf20Sopenharmony_ci : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory"); 1978c2ecf20Sopenharmony_ci trace_tlbie(lpid, 0, rb, rs, ric, prs, r); 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic inline void fixup_tlbie_va(unsigned long va, unsigned long pid, 2028c2ecf20Sopenharmony_ci unsigned long ap) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci if (cpu_has_feature(CPU_FTR_P9_TLBIE_ERAT_BUG)) { 2058c2ecf20Sopenharmony_ci asm volatile("ptesync": : :"memory"); 2068c2ecf20Sopenharmony_ci __tlbie_va(va, 0, ap, RIC_FLUSH_TLB); 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (cpu_has_feature(CPU_FTR_P9_TLBIE_STQ_BUG)) { 2108c2ecf20Sopenharmony_ci asm volatile("ptesync": : :"memory"); 2118c2ecf20Sopenharmony_ci __tlbie_va(va, pid, ap, RIC_FLUSH_TLB); 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic inline void fixup_tlbie_va_range(unsigned long va, unsigned long pid, 2168c2ecf20Sopenharmony_ci unsigned long ap) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci if (cpu_has_feature(CPU_FTR_P9_TLBIE_ERAT_BUG)) { 2198c2ecf20Sopenharmony_ci asm volatile("ptesync": : :"memory"); 2208c2ecf20Sopenharmony_ci __tlbie_pid(0, RIC_FLUSH_TLB); 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci if (cpu_has_feature(CPU_FTR_P9_TLBIE_STQ_BUG)) { 2248c2ecf20Sopenharmony_ci asm volatile("ptesync": : :"memory"); 2258c2ecf20Sopenharmony_ci __tlbie_va(va, pid, ap, RIC_FLUSH_TLB); 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic inline void fixup_tlbie_pid(unsigned long pid) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci /* 2328c2ecf20Sopenharmony_ci * We can use any address for the invalidation, pick one which is 2338c2ecf20Sopenharmony_ci * probably unused as an optimisation. 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci unsigned long va = ((1UL << 52) - 1); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (cpu_has_feature(CPU_FTR_P9_TLBIE_ERAT_BUG)) { 2388c2ecf20Sopenharmony_ci asm volatile("ptesync": : :"memory"); 2398c2ecf20Sopenharmony_ci __tlbie_pid(0, RIC_FLUSH_TLB); 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (cpu_has_feature(CPU_FTR_P9_TLBIE_STQ_BUG)) { 2438c2ecf20Sopenharmony_ci asm volatile("ptesync": : :"memory"); 2448c2ecf20Sopenharmony_ci __tlbie_va(va, pid, mmu_get_ap(MMU_PAGE_64K), RIC_FLUSH_TLB); 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic inline void fixup_tlbie_lpid_va(unsigned long va, unsigned long lpid, 2508c2ecf20Sopenharmony_ci unsigned long ap) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci if (cpu_has_feature(CPU_FTR_P9_TLBIE_ERAT_BUG)) { 2538c2ecf20Sopenharmony_ci asm volatile("ptesync": : :"memory"); 2548c2ecf20Sopenharmony_ci __tlbie_lpid_va(va, 0, ap, RIC_FLUSH_TLB); 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci if (cpu_has_feature(CPU_FTR_P9_TLBIE_STQ_BUG)) { 2588c2ecf20Sopenharmony_ci asm volatile("ptesync": : :"memory"); 2598c2ecf20Sopenharmony_ci __tlbie_lpid_va(va, lpid, ap, RIC_FLUSH_TLB); 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic inline void fixup_tlbie_lpid(unsigned long lpid) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci /* 2668c2ecf20Sopenharmony_ci * We can use any address for the invalidation, pick one which is 2678c2ecf20Sopenharmony_ci * probably unused as an optimisation. 2688c2ecf20Sopenharmony_ci */ 2698c2ecf20Sopenharmony_ci unsigned long va = ((1UL << 52) - 1); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (cpu_has_feature(CPU_FTR_P9_TLBIE_ERAT_BUG)) { 2728c2ecf20Sopenharmony_ci asm volatile("ptesync": : :"memory"); 2738c2ecf20Sopenharmony_ci __tlbie_lpid(0, RIC_FLUSH_TLB); 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (cpu_has_feature(CPU_FTR_P9_TLBIE_STQ_BUG)) { 2778c2ecf20Sopenharmony_ci asm volatile("ptesync": : :"memory"); 2788c2ecf20Sopenharmony_ci __tlbie_lpid_va(va, lpid, mmu_get_ap(MMU_PAGE_64K), RIC_FLUSH_TLB); 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci/* 2838c2ecf20Sopenharmony_ci * We use 128 set in radix mode and 256 set in hpt mode. 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_cistatic inline void _tlbiel_pid(unsigned long pid, unsigned long ric) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci int set; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci asm volatile("ptesync": : :"memory"); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci switch (ric) { 2928c2ecf20Sopenharmony_ci case RIC_FLUSH_PWC: 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* For PWC, only one flush is needed */ 2958c2ecf20Sopenharmony_ci __tlbiel_pid(pid, 0, RIC_FLUSH_PWC); 2968c2ecf20Sopenharmony_ci ppc_after_tlbiel_barrier(); 2978c2ecf20Sopenharmony_ci return; 2988c2ecf20Sopenharmony_ci case RIC_FLUSH_TLB: 2998c2ecf20Sopenharmony_ci __tlbiel_pid(pid, 0, RIC_FLUSH_TLB); 3008c2ecf20Sopenharmony_ci break; 3018c2ecf20Sopenharmony_ci case RIC_FLUSH_ALL: 3028c2ecf20Sopenharmony_ci default: 3038c2ecf20Sopenharmony_ci /* 3048c2ecf20Sopenharmony_ci * Flush the first set of the TLB, and if 3058c2ecf20Sopenharmony_ci * we're doing a RIC_FLUSH_ALL, also flush 3068c2ecf20Sopenharmony_ci * the entire Page Walk Cache. 3078c2ecf20Sopenharmony_ci */ 3088c2ecf20Sopenharmony_ci __tlbiel_pid(pid, 0, RIC_FLUSH_ALL); 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* For the remaining sets, just flush the TLB */ 3128c2ecf20Sopenharmony_ci for (set = 1; set < POWER9_TLB_SETS_RADIX ; set++) 3138c2ecf20Sopenharmony_ci __tlbiel_pid(pid, set, RIC_FLUSH_TLB); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci ppc_after_tlbiel_barrier(); 3168c2ecf20Sopenharmony_ci asm volatile(PPC_RADIX_INVALIDATE_ERAT_USER "; isync" : : :"memory"); 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic inline void _tlbie_pid(unsigned long pid, unsigned long ric) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci asm volatile("ptesync": : :"memory"); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci /* 3248c2ecf20Sopenharmony_ci * Workaround the fact that the "ric" argument to __tlbie_pid 3258c2ecf20Sopenharmony_ci * must be a compile-time contraint to match the "i" constraint 3268c2ecf20Sopenharmony_ci * in the asm statement. 3278c2ecf20Sopenharmony_ci */ 3288c2ecf20Sopenharmony_ci switch (ric) { 3298c2ecf20Sopenharmony_ci case RIC_FLUSH_TLB: 3308c2ecf20Sopenharmony_ci __tlbie_pid(pid, RIC_FLUSH_TLB); 3318c2ecf20Sopenharmony_ci fixup_tlbie_pid(pid); 3328c2ecf20Sopenharmony_ci break; 3338c2ecf20Sopenharmony_ci case RIC_FLUSH_PWC: 3348c2ecf20Sopenharmony_ci __tlbie_pid(pid, RIC_FLUSH_PWC); 3358c2ecf20Sopenharmony_ci break; 3368c2ecf20Sopenharmony_ci case RIC_FLUSH_ALL: 3378c2ecf20Sopenharmony_ci default: 3388c2ecf20Sopenharmony_ci __tlbie_pid(pid, RIC_FLUSH_ALL); 3398c2ecf20Sopenharmony_ci fixup_tlbie_pid(pid); 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci asm volatile("eieio; tlbsync; ptesync": : :"memory"); 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistruct tlbiel_pid { 3458c2ecf20Sopenharmony_ci unsigned long pid; 3468c2ecf20Sopenharmony_ci unsigned long ric; 3478c2ecf20Sopenharmony_ci}; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic void do_tlbiel_pid(void *info) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci struct tlbiel_pid *t = info; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci if (t->ric == RIC_FLUSH_TLB) 3548c2ecf20Sopenharmony_ci _tlbiel_pid(t->pid, RIC_FLUSH_TLB); 3558c2ecf20Sopenharmony_ci else if (t->ric == RIC_FLUSH_PWC) 3568c2ecf20Sopenharmony_ci _tlbiel_pid(t->pid, RIC_FLUSH_PWC); 3578c2ecf20Sopenharmony_ci else 3588c2ecf20Sopenharmony_ci _tlbiel_pid(t->pid, RIC_FLUSH_ALL); 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic inline void _tlbiel_pid_multicast(struct mm_struct *mm, 3628c2ecf20Sopenharmony_ci unsigned long pid, unsigned long ric) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci struct cpumask *cpus = mm_cpumask(mm); 3658c2ecf20Sopenharmony_ci struct tlbiel_pid t = { .pid = pid, .ric = ric }; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci on_each_cpu_mask(cpus, do_tlbiel_pid, &t, 1); 3688c2ecf20Sopenharmony_ci /* 3698c2ecf20Sopenharmony_ci * Always want the CPU translations to be invalidated with tlbiel in 3708c2ecf20Sopenharmony_ci * these paths, so while coprocessors must use tlbie, we can not 3718c2ecf20Sopenharmony_ci * optimise away the tlbiel component. 3728c2ecf20Sopenharmony_ci */ 3738c2ecf20Sopenharmony_ci if (atomic_read(&mm->context.copros) > 0) 3748c2ecf20Sopenharmony_ci _tlbie_pid(pid, RIC_FLUSH_ALL); 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic inline void _tlbie_lpid(unsigned long lpid, unsigned long ric) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci asm volatile("ptesync": : :"memory"); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* 3828c2ecf20Sopenharmony_ci * Workaround the fact that the "ric" argument to __tlbie_pid 3838c2ecf20Sopenharmony_ci * must be a compile-time contraint to match the "i" constraint 3848c2ecf20Sopenharmony_ci * in the asm statement. 3858c2ecf20Sopenharmony_ci */ 3868c2ecf20Sopenharmony_ci switch (ric) { 3878c2ecf20Sopenharmony_ci case RIC_FLUSH_TLB: 3888c2ecf20Sopenharmony_ci __tlbie_lpid(lpid, RIC_FLUSH_TLB); 3898c2ecf20Sopenharmony_ci fixup_tlbie_lpid(lpid); 3908c2ecf20Sopenharmony_ci break; 3918c2ecf20Sopenharmony_ci case RIC_FLUSH_PWC: 3928c2ecf20Sopenharmony_ci __tlbie_lpid(lpid, RIC_FLUSH_PWC); 3938c2ecf20Sopenharmony_ci break; 3948c2ecf20Sopenharmony_ci case RIC_FLUSH_ALL: 3958c2ecf20Sopenharmony_ci default: 3968c2ecf20Sopenharmony_ci __tlbie_lpid(lpid, RIC_FLUSH_ALL); 3978c2ecf20Sopenharmony_ci fixup_tlbie_lpid(lpid); 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci asm volatile("eieio; tlbsync; ptesync": : :"memory"); 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic __always_inline void _tlbie_lpid_guest(unsigned long lpid, unsigned long ric) 4038c2ecf20Sopenharmony_ci{ 4048c2ecf20Sopenharmony_ci /* 4058c2ecf20Sopenharmony_ci * Workaround the fact that the "ric" argument to __tlbie_pid 4068c2ecf20Sopenharmony_ci * must be a compile-time contraint to match the "i" constraint 4078c2ecf20Sopenharmony_ci * in the asm statement. 4088c2ecf20Sopenharmony_ci */ 4098c2ecf20Sopenharmony_ci switch (ric) { 4108c2ecf20Sopenharmony_ci case RIC_FLUSH_TLB: 4118c2ecf20Sopenharmony_ci __tlbie_lpid_guest(lpid, RIC_FLUSH_TLB); 4128c2ecf20Sopenharmony_ci break; 4138c2ecf20Sopenharmony_ci case RIC_FLUSH_PWC: 4148c2ecf20Sopenharmony_ci __tlbie_lpid_guest(lpid, RIC_FLUSH_PWC); 4158c2ecf20Sopenharmony_ci break; 4168c2ecf20Sopenharmony_ci case RIC_FLUSH_ALL: 4178c2ecf20Sopenharmony_ci default: 4188c2ecf20Sopenharmony_ci __tlbie_lpid_guest(lpid, RIC_FLUSH_ALL); 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci fixup_tlbie_lpid(lpid); 4218c2ecf20Sopenharmony_ci asm volatile("eieio; tlbsync; ptesync": : :"memory"); 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_cistatic inline void __tlbiel_va_range(unsigned long start, unsigned long end, 4258c2ecf20Sopenharmony_ci unsigned long pid, unsigned long page_size, 4268c2ecf20Sopenharmony_ci unsigned long psize) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci unsigned long addr; 4298c2ecf20Sopenharmony_ci unsigned long ap = mmu_get_ap(psize); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci for (addr = start; addr < end; addr += page_size) 4328c2ecf20Sopenharmony_ci __tlbiel_va(addr, pid, ap, RIC_FLUSH_TLB); 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic __always_inline void _tlbiel_va(unsigned long va, unsigned long pid, 4368c2ecf20Sopenharmony_ci unsigned long psize, unsigned long ric) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci unsigned long ap = mmu_get_ap(psize); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci asm volatile("ptesync": : :"memory"); 4418c2ecf20Sopenharmony_ci __tlbiel_va(va, pid, ap, ric); 4428c2ecf20Sopenharmony_ci ppc_after_tlbiel_barrier(); 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic inline void _tlbiel_va_range(unsigned long start, unsigned long end, 4468c2ecf20Sopenharmony_ci unsigned long pid, unsigned long page_size, 4478c2ecf20Sopenharmony_ci unsigned long psize, bool also_pwc) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci asm volatile("ptesync": : :"memory"); 4508c2ecf20Sopenharmony_ci if (also_pwc) 4518c2ecf20Sopenharmony_ci __tlbiel_pid(pid, 0, RIC_FLUSH_PWC); 4528c2ecf20Sopenharmony_ci __tlbiel_va_range(start, end, pid, page_size, psize); 4538c2ecf20Sopenharmony_ci ppc_after_tlbiel_barrier(); 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cistatic inline void __tlbie_va_range(unsigned long start, unsigned long end, 4578c2ecf20Sopenharmony_ci unsigned long pid, unsigned long page_size, 4588c2ecf20Sopenharmony_ci unsigned long psize) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci unsigned long addr; 4618c2ecf20Sopenharmony_ci unsigned long ap = mmu_get_ap(psize); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci for (addr = start; addr < end; addr += page_size) 4648c2ecf20Sopenharmony_ci __tlbie_va(addr, pid, ap, RIC_FLUSH_TLB); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci fixup_tlbie_va_range(addr - page_size, pid, ap); 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic __always_inline void _tlbie_va(unsigned long va, unsigned long pid, 4708c2ecf20Sopenharmony_ci unsigned long psize, unsigned long ric) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci unsigned long ap = mmu_get_ap(psize); 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci asm volatile("ptesync": : :"memory"); 4758c2ecf20Sopenharmony_ci __tlbie_va(va, pid, ap, ric); 4768c2ecf20Sopenharmony_ci fixup_tlbie_va(va, pid, ap); 4778c2ecf20Sopenharmony_ci asm volatile("eieio; tlbsync; ptesync": : :"memory"); 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistruct tlbiel_va { 4818c2ecf20Sopenharmony_ci unsigned long pid; 4828c2ecf20Sopenharmony_ci unsigned long va; 4838c2ecf20Sopenharmony_ci unsigned long psize; 4848c2ecf20Sopenharmony_ci unsigned long ric; 4858c2ecf20Sopenharmony_ci}; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cistatic void do_tlbiel_va(void *info) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci struct tlbiel_va *t = info; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (t->ric == RIC_FLUSH_TLB) 4928c2ecf20Sopenharmony_ci _tlbiel_va(t->va, t->pid, t->psize, RIC_FLUSH_TLB); 4938c2ecf20Sopenharmony_ci else if (t->ric == RIC_FLUSH_PWC) 4948c2ecf20Sopenharmony_ci _tlbiel_va(t->va, t->pid, t->psize, RIC_FLUSH_PWC); 4958c2ecf20Sopenharmony_ci else 4968c2ecf20Sopenharmony_ci _tlbiel_va(t->va, t->pid, t->psize, RIC_FLUSH_ALL); 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_cistatic inline void _tlbiel_va_multicast(struct mm_struct *mm, 5008c2ecf20Sopenharmony_ci unsigned long va, unsigned long pid, 5018c2ecf20Sopenharmony_ci unsigned long psize, unsigned long ric) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci struct cpumask *cpus = mm_cpumask(mm); 5048c2ecf20Sopenharmony_ci struct tlbiel_va t = { .va = va, .pid = pid, .psize = psize, .ric = ric }; 5058c2ecf20Sopenharmony_ci on_each_cpu_mask(cpus, do_tlbiel_va, &t, 1); 5068c2ecf20Sopenharmony_ci if (atomic_read(&mm->context.copros) > 0) 5078c2ecf20Sopenharmony_ci _tlbie_va(va, pid, psize, RIC_FLUSH_TLB); 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistruct tlbiel_va_range { 5118c2ecf20Sopenharmony_ci unsigned long pid; 5128c2ecf20Sopenharmony_ci unsigned long start; 5138c2ecf20Sopenharmony_ci unsigned long end; 5148c2ecf20Sopenharmony_ci unsigned long page_size; 5158c2ecf20Sopenharmony_ci unsigned long psize; 5168c2ecf20Sopenharmony_ci bool also_pwc; 5178c2ecf20Sopenharmony_ci}; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_cistatic void do_tlbiel_va_range(void *info) 5208c2ecf20Sopenharmony_ci{ 5218c2ecf20Sopenharmony_ci struct tlbiel_va_range *t = info; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci _tlbiel_va_range(t->start, t->end, t->pid, t->page_size, 5248c2ecf20Sopenharmony_ci t->psize, t->also_pwc); 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_cistatic __always_inline void _tlbie_lpid_va(unsigned long va, unsigned long lpid, 5288c2ecf20Sopenharmony_ci unsigned long psize, unsigned long ric) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci unsigned long ap = mmu_get_ap(psize); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci asm volatile("ptesync": : :"memory"); 5338c2ecf20Sopenharmony_ci __tlbie_lpid_va(va, lpid, ap, ric); 5348c2ecf20Sopenharmony_ci fixup_tlbie_lpid_va(va, lpid, ap); 5358c2ecf20Sopenharmony_ci asm volatile("eieio; tlbsync; ptesync": : :"memory"); 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_cistatic inline void _tlbie_va_range(unsigned long start, unsigned long end, 5398c2ecf20Sopenharmony_ci unsigned long pid, unsigned long page_size, 5408c2ecf20Sopenharmony_ci unsigned long psize, bool also_pwc) 5418c2ecf20Sopenharmony_ci{ 5428c2ecf20Sopenharmony_ci asm volatile("ptesync": : :"memory"); 5438c2ecf20Sopenharmony_ci if (also_pwc) 5448c2ecf20Sopenharmony_ci __tlbie_pid(pid, RIC_FLUSH_PWC); 5458c2ecf20Sopenharmony_ci __tlbie_va_range(start, end, pid, page_size, psize); 5468c2ecf20Sopenharmony_ci asm volatile("eieio; tlbsync; ptesync": : :"memory"); 5478c2ecf20Sopenharmony_ci} 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_cistatic inline void _tlbiel_va_range_multicast(struct mm_struct *mm, 5508c2ecf20Sopenharmony_ci unsigned long start, unsigned long end, 5518c2ecf20Sopenharmony_ci unsigned long pid, unsigned long page_size, 5528c2ecf20Sopenharmony_ci unsigned long psize, bool also_pwc) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci struct cpumask *cpus = mm_cpumask(mm); 5558c2ecf20Sopenharmony_ci struct tlbiel_va_range t = { .start = start, .end = end, 5568c2ecf20Sopenharmony_ci .pid = pid, .page_size = page_size, 5578c2ecf20Sopenharmony_ci .psize = psize, .also_pwc = also_pwc }; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci on_each_cpu_mask(cpus, do_tlbiel_va_range, &t, 1); 5608c2ecf20Sopenharmony_ci if (atomic_read(&mm->context.copros) > 0) 5618c2ecf20Sopenharmony_ci _tlbie_va_range(start, end, pid, page_size, psize, also_pwc); 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci/* 5658c2ecf20Sopenharmony_ci * Base TLB flushing operations: 5668c2ecf20Sopenharmony_ci * 5678c2ecf20Sopenharmony_ci * - flush_tlb_mm(mm) flushes the specified mm context TLB's 5688c2ecf20Sopenharmony_ci * - flush_tlb_page(vma, vmaddr) flushes one page 5698c2ecf20Sopenharmony_ci * - flush_tlb_range(vma, start, end) flushes a range of pages 5708c2ecf20Sopenharmony_ci * - flush_tlb_kernel_range(start, end) flushes kernel pages 5718c2ecf20Sopenharmony_ci * 5728c2ecf20Sopenharmony_ci * - local_* variants of page and mm only apply to the current 5738c2ecf20Sopenharmony_ci * processor 5748c2ecf20Sopenharmony_ci */ 5758c2ecf20Sopenharmony_civoid radix__local_flush_tlb_mm(struct mm_struct *mm) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci unsigned long pid; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci preempt_disable(); 5808c2ecf20Sopenharmony_ci pid = mm->context.id; 5818c2ecf20Sopenharmony_ci if (pid != MMU_NO_CONTEXT) 5828c2ecf20Sopenharmony_ci _tlbiel_pid(pid, RIC_FLUSH_TLB); 5838c2ecf20Sopenharmony_ci preempt_enable(); 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(radix__local_flush_tlb_mm); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci#ifndef CONFIG_SMP 5888c2ecf20Sopenharmony_civoid radix__local_flush_all_mm(struct mm_struct *mm) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci unsigned long pid; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci preempt_disable(); 5938c2ecf20Sopenharmony_ci pid = mm->context.id; 5948c2ecf20Sopenharmony_ci if (pid != MMU_NO_CONTEXT) 5958c2ecf20Sopenharmony_ci _tlbiel_pid(pid, RIC_FLUSH_ALL); 5968c2ecf20Sopenharmony_ci preempt_enable(); 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ciEXPORT_SYMBOL(radix__local_flush_all_mm); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_cistatic void __flush_all_mm(struct mm_struct *mm, bool fullmm) 6018c2ecf20Sopenharmony_ci{ 6028c2ecf20Sopenharmony_ci radix__local_flush_all_mm(mm); 6038c2ecf20Sopenharmony_ci} 6048c2ecf20Sopenharmony_ci#endif /* CONFIG_SMP */ 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_civoid radix__local_flush_tlb_page_psize(struct mm_struct *mm, unsigned long vmaddr, 6078c2ecf20Sopenharmony_ci int psize) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci unsigned long pid; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci preempt_disable(); 6128c2ecf20Sopenharmony_ci pid = mm->context.id; 6138c2ecf20Sopenharmony_ci if (pid != MMU_NO_CONTEXT) 6148c2ecf20Sopenharmony_ci _tlbiel_va(vmaddr, pid, psize, RIC_FLUSH_TLB); 6158c2ecf20Sopenharmony_ci preempt_enable(); 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_civoid radix__local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci#ifdef CONFIG_HUGETLB_PAGE 6218c2ecf20Sopenharmony_ci /* need the return fix for nohash.c */ 6228c2ecf20Sopenharmony_ci if (is_vm_hugetlb_page(vma)) 6238c2ecf20Sopenharmony_ci return radix__local_flush_hugetlb_page(vma, vmaddr); 6248c2ecf20Sopenharmony_ci#endif 6258c2ecf20Sopenharmony_ci radix__local_flush_tlb_page_psize(vma->vm_mm, vmaddr, mmu_virtual_psize); 6268c2ecf20Sopenharmony_ci} 6278c2ecf20Sopenharmony_ciEXPORT_SYMBOL(radix__local_flush_tlb_page); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_cistatic bool mm_is_singlethreaded(struct mm_struct *mm) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci if (atomic_read(&mm->context.copros) > 0) 6328c2ecf20Sopenharmony_ci return false; 6338c2ecf20Sopenharmony_ci if (atomic_read(&mm->mm_users) <= 1 && current->mm == mm) 6348c2ecf20Sopenharmony_ci return true; 6358c2ecf20Sopenharmony_ci return false; 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_cistatic bool mm_needs_flush_escalation(struct mm_struct *mm) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci /* 6418c2ecf20Sopenharmony_ci * P9 nest MMU has issues with the page walk cache 6428c2ecf20Sopenharmony_ci * caching PTEs and not flushing them properly when 6438c2ecf20Sopenharmony_ci * RIC = 0 for a PID/LPID invalidate 6448c2ecf20Sopenharmony_ci */ 6458c2ecf20Sopenharmony_ci if (atomic_read(&mm->context.copros) > 0) 6468c2ecf20Sopenharmony_ci return true; 6478c2ecf20Sopenharmony_ci return false; 6488c2ecf20Sopenharmony_ci} 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP 6518c2ecf20Sopenharmony_cistatic void do_exit_flush_lazy_tlb(void *arg) 6528c2ecf20Sopenharmony_ci{ 6538c2ecf20Sopenharmony_ci struct mm_struct *mm = arg; 6548c2ecf20Sopenharmony_ci unsigned long pid = mm->context.id; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci /* 6578c2ecf20Sopenharmony_ci * A kthread could have done a mmget_not_zero() after the flushing CPU 6588c2ecf20Sopenharmony_ci * checked mm_is_singlethreaded, and be in the process of 6598c2ecf20Sopenharmony_ci * kthread_use_mm when interrupted here. In that case, current->mm will 6608c2ecf20Sopenharmony_ci * be set to mm, because kthread_use_mm() setting ->mm and switching to 6618c2ecf20Sopenharmony_ci * the mm is done with interrupts off. 6628c2ecf20Sopenharmony_ci */ 6638c2ecf20Sopenharmony_ci if (current->mm == mm) 6648c2ecf20Sopenharmony_ci goto out_flush; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci if (current->active_mm == mm) { 6678c2ecf20Sopenharmony_ci WARN_ON_ONCE(current->mm != NULL); 6688c2ecf20Sopenharmony_ci /* Is a kernel thread and is using mm as the lazy tlb */ 6698c2ecf20Sopenharmony_ci mmgrab(&init_mm); 6708c2ecf20Sopenharmony_ci current->active_mm = &init_mm; 6718c2ecf20Sopenharmony_ci switch_mm_irqs_off(mm, &init_mm, current); 6728c2ecf20Sopenharmony_ci mmdrop(mm); 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci atomic_dec(&mm->context.active_cpus); 6768c2ecf20Sopenharmony_ci cpumask_clear_cpu(smp_processor_id(), mm_cpumask(mm)); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ciout_flush: 6798c2ecf20Sopenharmony_ci _tlbiel_pid(pid, RIC_FLUSH_ALL); 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_cistatic void exit_flush_lazy_tlbs(struct mm_struct *mm) 6838c2ecf20Sopenharmony_ci{ 6848c2ecf20Sopenharmony_ci /* 6858c2ecf20Sopenharmony_ci * Would be nice if this was async so it could be run in 6868c2ecf20Sopenharmony_ci * parallel with our local flush, but generic code does not 6878c2ecf20Sopenharmony_ci * give a good API for it. Could extend the generic code or 6888c2ecf20Sopenharmony_ci * make a special powerpc IPI for flushing TLBs. 6898c2ecf20Sopenharmony_ci * For now it's not too performance critical. 6908c2ecf20Sopenharmony_ci */ 6918c2ecf20Sopenharmony_ci smp_call_function_many(mm_cpumask(mm), do_exit_flush_lazy_tlb, 6928c2ecf20Sopenharmony_ci (void *)mm, 1); 6938c2ecf20Sopenharmony_ci} 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_civoid radix__flush_tlb_mm(struct mm_struct *mm) 6968c2ecf20Sopenharmony_ci{ 6978c2ecf20Sopenharmony_ci unsigned long pid; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci pid = mm->context.id; 7008c2ecf20Sopenharmony_ci if (unlikely(pid == MMU_NO_CONTEXT)) 7018c2ecf20Sopenharmony_ci return; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci preempt_disable(); 7048c2ecf20Sopenharmony_ci /* 7058c2ecf20Sopenharmony_ci * Order loads of mm_cpumask vs previous stores to clear ptes before 7068c2ecf20Sopenharmony_ci * the invalidate. See barrier in switch_mm_irqs_off 7078c2ecf20Sopenharmony_ci */ 7088c2ecf20Sopenharmony_ci smp_mb(); 7098c2ecf20Sopenharmony_ci if (!mm_is_thread_local(mm)) { 7108c2ecf20Sopenharmony_ci if (unlikely(mm_is_singlethreaded(mm))) { 7118c2ecf20Sopenharmony_ci exit_flush_lazy_tlbs(mm); 7128c2ecf20Sopenharmony_ci goto local; 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci if (!mmu_has_feature(MMU_FTR_GTSE)) { 7168c2ecf20Sopenharmony_ci unsigned long tgt = H_RPTI_TARGET_CMMU; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci if (atomic_read(&mm->context.copros) > 0) 7198c2ecf20Sopenharmony_ci tgt |= H_RPTI_TARGET_NMMU; 7208c2ecf20Sopenharmony_ci pseries_rpt_invalidate(pid, tgt, H_RPTI_TYPE_TLB, 7218c2ecf20Sopenharmony_ci H_RPTI_PAGE_ALL, 0, -1UL); 7228c2ecf20Sopenharmony_ci } else if (cputlb_use_tlbie()) { 7238c2ecf20Sopenharmony_ci if (mm_needs_flush_escalation(mm)) 7248c2ecf20Sopenharmony_ci _tlbie_pid(pid, RIC_FLUSH_ALL); 7258c2ecf20Sopenharmony_ci else 7268c2ecf20Sopenharmony_ci _tlbie_pid(pid, RIC_FLUSH_TLB); 7278c2ecf20Sopenharmony_ci } else { 7288c2ecf20Sopenharmony_ci _tlbiel_pid_multicast(mm, pid, RIC_FLUSH_TLB); 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci } else { 7318c2ecf20Sopenharmony_cilocal: 7328c2ecf20Sopenharmony_ci _tlbiel_pid(pid, RIC_FLUSH_TLB); 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci preempt_enable(); 7358c2ecf20Sopenharmony_ci} 7368c2ecf20Sopenharmony_ciEXPORT_SYMBOL(radix__flush_tlb_mm); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_cistatic void __flush_all_mm(struct mm_struct *mm, bool fullmm) 7398c2ecf20Sopenharmony_ci{ 7408c2ecf20Sopenharmony_ci unsigned long pid; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci pid = mm->context.id; 7438c2ecf20Sopenharmony_ci if (unlikely(pid == MMU_NO_CONTEXT)) 7448c2ecf20Sopenharmony_ci return; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci preempt_disable(); 7478c2ecf20Sopenharmony_ci smp_mb(); /* see radix__flush_tlb_mm */ 7488c2ecf20Sopenharmony_ci if (!mm_is_thread_local(mm)) { 7498c2ecf20Sopenharmony_ci if (unlikely(mm_is_singlethreaded(mm))) { 7508c2ecf20Sopenharmony_ci if (!fullmm) { 7518c2ecf20Sopenharmony_ci exit_flush_lazy_tlbs(mm); 7528c2ecf20Sopenharmony_ci goto local; 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci if (!mmu_has_feature(MMU_FTR_GTSE)) { 7568c2ecf20Sopenharmony_ci unsigned long tgt = H_RPTI_TARGET_CMMU; 7578c2ecf20Sopenharmony_ci unsigned long type = H_RPTI_TYPE_TLB | H_RPTI_TYPE_PWC | 7588c2ecf20Sopenharmony_ci H_RPTI_TYPE_PRT; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci if (atomic_read(&mm->context.copros) > 0) 7618c2ecf20Sopenharmony_ci tgt |= H_RPTI_TARGET_NMMU; 7628c2ecf20Sopenharmony_ci pseries_rpt_invalidate(pid, tgt, type, 7638c2ecf20Sopenharmony_ci H_RPTI_PAGE_ALL, 0, -1UL); 7648c2ecf20Sopenharmony_ci } else if (cputlb_use_tlbie()) 7658c2ecf20Sopenharmony_ci _tlbie_pid(pid, RIC_FLUSH_ALL); 7668c2ecf20Sopenharmony_ci else 7678c2ecf20Sopenharmony_ci _tlbiel_pid_multicast(mm, pid, RIC_FLUSH_ALL); 7688c2ecf20Sopenharmony_ci } else { 7698c2ecf20Sopenharmony_cilocal: 7708c2ecf20Sopenharmony_ci _tlbiel_pid(pid, RIC_FLUSH_ALL); 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci preempt_enable(); 7738c2ecf20Sopenharmony_ci} 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_civoid radix__flush_all_mm(struct mm_struct *mm) 7768c2ecf20Sopenharmony_ci{ 7778c2ecf20Sopenharmony_ci __flush_all_mm(mm, false); 7788c2ecf20Sopenharmony_ci} 7798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(radix__flush_all_mm); 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_civoid radix__flush_tlb_page_psize(struct mm_struct *mm, unsigned long vmaddr, 7828c2ecf20Sopenharmony_ci int psize) 7838c2ecf20Sopenharmony_ci{ 7848c2ecf20Sopenharmony_ci unsigned long pid; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci pid = mm->context.id; 7878c2ecf20Sopenharmony_ci if (unlikely(pid == MMU_NO_CONTEXT)) 7888c2ecf20Sopenharmony_ci return; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci preempt_disable(); 7918c2ecf20Sopenharmony_ci smp_mb(); /* see radix__flush_tlb_mm */ 7928c2ecf20Sopenharmony_ci if (!mm_is_thread_local(mm)) { 7938c2ecf20Sopenharmony_ci if (unlikely(mm_is_singlethreaded(mm))) { 7948c2ecf20Sopenharmony_ci exit_flush_lazy_tlbs(mm); 7958c2ecf20Sopenharmony_ci goto local; 7968c2ecf20Sopenharmony_ci } 7978c2ecf20Sopenharmony_ci if (!mmu_has_feature(MMU_FTR_GTSE)) { 7988c2ecf20Sopenharmony_ci unsigned long tgt, pg_sizes, size; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci tgt = H_RPTI_TARGET_CMMU; 8018c2ecf20Sopenharmony_ci pg_sizes = psize_to_rpti_pgsize(psize); 8028c2ecf20Sopenharmony_ci size = 1UL << mmu_psize_to_shift(psize); 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci if (atomic_read(&mm->context.copros) > 0) 8058c2ecf20Sopenharmony_ci tgt |= H_RPTI_TARGET_NMMU; 8068c2ecf20Sopenharmony_ci pseries_rpt_invalidate(pid, tgt, H_RPTI_TYPE_TLB, 8078c2ecf20Sopenharmony_ci pg_sizes, vmaddr, 8088c2ecf20Sopenharmony_ci vmaddr + size); 8098c2ecf20Sopenharmony_ci } else if (cputlb_use_tlbie()) 8108c2ecf20Sopenharmony_ci _tlbie_va(vmaddr, pid, psize, RIC_FLUSH_TLB); 8118c2ecf20Sopenharmony_ci else 8128c2ecf20Sopenharmony_ci _tlbiel_va_multicast(mm, vmaddr, pid, psize, RIC_FLUSH_TLB); 8138c2ecf20Sopenharmony_ci } else { 8148c2ecf20Sopenharmony_cilocal: 8158c2ecf20Sopenharmony_ci _tlbiel_va(vmaddr, pid, psize, RIC_FLUSH_TLB); 8168c2ecf20Sopenharmony_ci } 8178c2ecf20Sopenharmony_ci preempt_enable(); 8188c2ecf20Sopenharmony_ci} 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_civoid radix__flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr) 8218c2ecf20Sopenharmony_ci{ 8228c2ecf20Sopenharmony_ci#ifdef CONFIG_HUGETLB_PAGE 8238c2ecf20Sopenharmony_ci if (is_vm_hugetlb_page(vma)) 8248c2ecf20Sopenharmony_ci return radix__flush_hugetlb_page(vma, vmaddr); 8258c2ecf20Sopenharmony_ci#endif 8268c2ecf20Sopenharmony_ci radix__flush_tlb_page_psize(vma->vm_mm, vmaddr, mmu_virtual_psize); 8278c2ecf20Sopenharmony_ci} 8288c2ecf20Sopenharmony_ciEXPORT_SYMBOL(radix__flush_tlb_page); 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci#else /* CONFIG_SMP */ 8318c2ecf20Sopenharmony_cistatic inline void exit_flush_lazy_tlbs(struct mm_struct *mm) { } 8328c2ecf20Sopenharmony_ci#endif /* CONFIG_SMP */ 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_cistatic void do_tlbiel_kernel(void *info) 8358c2ecf20Sopenharmony_ci{ 8368c2ecf20Sopenharmony_ci _tlbiel_pid(0, RIC_FLUSH_ALL); 8378c2ecf20Sopenharmony_ci} 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_cistatic inline void _tlbiel_kernel_broadcast(void) 8408c2ecf20Sopenharmony_ci{ 8418c2ecf20Sopenharmony_ci on_each_cpu(do_tlbiel_kernel, NULL, 1); 8428c2ecf20Sopenharmony_ci if (tlbie_capable) { 8438c2ecf20Sopenharmony_ci /* 8448c2ecf20Sopenharmony_ci * Coherent accelerators don't refcount kernel memory mappings, 8458c2ecf20Sopenharmony_ci * so have to always issue a tlbie for them. This is quite a 8468c2ecf20Sopenharmony_ci * slow path anyway. 8478c2ecf20Sopenharmony_ci */ 8488c2ecf20Sopenharmony_ci _tlbie_pid(0, RIC_FLUSH_ALL); 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci} 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci/* 8538c2ecf20Sopenharmony_ci * If kernel TLBIs ever become local rather than global, then 8548c2ecf20Sopenharmony_ci * drivers/misc/ocxl/link.c:ocxl_link_add_pe will need some work, as it 8558c2ecf20Sopenharmony_ci * assumes kernel TLBIs are global. 8568c2ecf20Sopenharmony_ci */ 8578c2ecf20Sopenharmony_civoid radix__flush_tlb_kernel_range(unsigned long start, unsigned long end) 8588c2ecf20Sopenharmony_ci{ 8598c2ecf20Sopenharmony_ci if (!mmu_has_feature(MMU_FTR_GTSE)) { 8608c2ecf20Sopenharmony_ci unsigned long tgt = H_RPTI_TARGET_CMMU | H_RPTI_TARGET_NMMU; 8618c2ecf20Sopenharmony_ci unsigned long type = H_RPTI_TYPE_TLB | H_RPTI_TYPE_PWC | 8628c2ecf20Sopenharmony_ci H_RPTI_TYPE_PRT; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci pseries_rpt_invalidate(0, tgt, type, H_RPTI_PAGE_ALL, 8658c2ecf20Sopenharmony_ci start, end); 8668c2ecf20Sopenharmony_ci } else if (cputlb_use_tlbie()) 8678c2ecf20Sopenharmony_ci _tlbie_pid(0, RIC_FLUSH_ALL); 8688c2ecf20Sopenharmony_ci else 8698c2ecf20Sopenharmony_ci _tlbiel_kernel_broadcast(); 8708c2ecf20Sopenharmony_ci} 8718c2ecf20Sopenharmony_ciEXPORT_SYMBOL(radix__flush_tlb_kernel_range); 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci#define TLB_FLUSH_ALL -1UL 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci/* 8768c2ecf20Sopenharmony_ci * Number of pages above which we invalidate the entire PID rather than 8778c2ecf20Sopenharmony_ci * flush individual pages, for local and global flushes respectively. 8788c2ecf20Sopenharmony_ci * 8798c2ecf20Sopenharmony_ci * tlbie goes out to the interconnect and individual ops are more costly. 8808c2ecf20Sopenharmony_ci * It also does not iterate over sets like the local tlbiel variant when 8818c2ecf20Sopenharmony_ci * invalidating a full PID, so it has a far lower threshold to change from 8828c2ecf20Sopenharmony_ci * individual page flushes to full-pid flushes. 8838c2ecf20Sopenharmony_ci */ 8848c2ecf20Sopenharmony_cistatic unsigned long tlb_single_page_flush_ceiling __read_mostly = 33; 8858c2ecf20Sopenharmony_cistatic unsigned long tlb_local_single_page_flush_ceiling __read_mostly = POWER9_TLB_SETS_RADIX * 2; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_cistatic inline void __radix__flush_tlb_range(struct mm_struct *mm, 8888c2ecf20Sopenharmony_ci unsigned long start, unsigned long end) 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci{ 8918c2ecf20Sopenharmony_ci unsigned long pid; 8928c2ecf20Sopenharmony_ci unsigned int page_shift = mmu_psize_defs[mmu_virtual_psize].shift; 8938c2ecf20Sopenharmony_ci unsigned long page_size = 1UL << page_shift; 8948c2ecf20Sopenharmony_ci unsigned long nr_pages = (end - start) >> page_shift; 8958c2ecf20Sopenharmony_ci bool local, full; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci pid = mm->context.id; 8988c2ecf20Sopenharmony_ci if (unlikely(pid == MMU_NO_CONTEXT)) 8998c2ecf20Sopenharmony_ci return; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci preempt_disable(); 9028c2ecf20Sopenharmony_ci smp_mb(); /* see radix__flush_tlb_mm */ 9038c2ecf20Sopenharmony_ci if (!mm_is_thread_local(mm)) { 9048c2ecf20Sopenharmony_ci if (unlikely(mm_is_singlethreaded(mm))) { 9058c2ecf20Sopenharmony_ci if (end != TLB_FLUSH_ALL) { 9068c2ecf20Sopenharmony_ci exit_flush_lazy_tlbs(mm); 9078c2ecf20Sopenharmony_ci goto is_local; 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci } 9108c2ecf20Sopenharmony_ci local = false; 9118c2ecf20Sopenharmony_ci full = (end == TLB_FLUSH_ALL || 9128c2ecf20Sopenharmony_ci nr_pages > tlb_single_page_flush_ceiling); 9138c2ecf20Sopenharmony_ci } else { 9148c2ecf20Sopenharmony_ciis_local: 9158c2ecf20Sopenharmony_ci local = true; 9168c2ecf20Sopenharmony_ci full = (end == TLB_FLUSH_ALL || 9178c2ecf20Sopenharmony_ci nr_pages > tlb_local_single_page_flush_ceiling); 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci if (!mmu_has_feature(MMU_FTR_GTSE) && !local) { 9218c2ecf20Sopenharmony_ci unsigned long tgt = H_RPTI_TARGET_CMMU; 9228c2ecf20Sopenharmony_ci unsigned long pg_sizes = psize_to_rpti_pgsize(mmu_virtual_psize); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) 9258c2ecf20Sopenharmony_ci pg_sizes |= psize_to_rpti_pgsize(MMU_PAGE_2M); 9268c2ecf20Sopenharmony_ci if (atomic_read(&mm->context.copros) > 0) 9278c2ecf20Sopenharmony_ci tgt |= H_RPTI_TARGET_NMMU; 9288c2ecf20Sopenharmony_ci pseries_rpt_invalidate(pid, tgt, H_RPTI_TYPE_TLB, pg_sizes, 9298c2ecf20Sopenharmony_ci start, end); 9308c2ecf20Sopenharmony_ci } else if (full) { 9318c2ecf20Sopenharmony_ci if (local) { 9328c2ecf20Sopenharmony_ci _tlbiel_pid(pid, RIC_FLUSH_TLB); 9338c2ecf20Sopenharmony_ci } else { 9348c2ecf20Sopenharmony_ci if (cputlb_use_tlbie()) { 9358c2ecf20Sopenharmony_ci if (mm_needs_flush_escalation(mm)) 9368c2ecf20Sopenharmony_ci _tlbie_pid(pid, RIC_FLUSH_ALL); 9378c2ecf20Sopenharmony_ci else 9388c2ecf20Sopenharmony_ci _tlbie_pid(pid, RIC_FLUSH_TLB); 9398c2ecf20Sopenharmony_ci } else { 9408c2ecf20Sopenharmony_ci _tlbiel_pid_multicast(mm, pid, RIC_FLUSH_TLB); 9418c2ecf20Sopenharmony_ci } 9428c2ecf20Sopenharmony_ci } 9438c2ecf20Sopenharmony_ci } else { 9448c2ecf20Sopenharmony_ci bool hflush; 9458c2ecf20Sopenharmony_ci unsigned long hstart, hend; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci hstart = (start + PMD_SIZE - 1) & PMD_MASK; 9488c2ecf20Sopenharmony_ci hend = end & PMD_MASK; 9498c2ecf20Sopenharmony_ci hflush = IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && hstart < hend; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci if (local) { 9528c2ecf20Sopenharmony_ci asm volatile("ptesync": : :"memory"); 9538c2ecf20Sopenharmony_ci __tlbiel_va_range(start, end, pid, page_size, mmu_virtual_psize); 9548c2ecf20Sopenharmony_ci if (hflush) 9558c2ecf20Sopenharmony_ci __tlbiel_va_range(hstart, hend, pid, 9568c2ecf20Sopenharmony_ci PMD_SIZE, MMU_PAGE_2M); 9578c2ecf20Sopenharmony_ci ppc_after_tlbiel_barrier(); 9588c2ecf20Sopenharmony_ci } else if (cputlb_use_tlbie()) { 9598c2ecf20Sopenharmony_ci asm volatile("ptesync": : :"memory"); 9608c2ecf20Sopenharmony_ci __tlbie_va_range(start, end, pid, page_size, mmu_virtual_psize); 9618c2ecf20Sopenharmony_ci if (hflush) 9628c2ecf20Sopenharmony_ci __tlbie_va_range(hstart, hend, pid, 9638c2ecf20Sopenharmony_ci PMD_SIZE, MMU_PAGE_2M); 9648c2ecf20Sopenharmony_ci asm volatile("eieio; tlbsync; ptesync": : :"memory"); 9658c2ecf20Sopenharmony_ci } else { 9668c2ecf20Sopenharmony_ci _tlbiel_va_range_multicast(mm, 9678c2ecf20Sopenharmony_ci start, end, pid, page_size, mmu_virtual_psize, false); 9688c2ecf20Sopenharmony_ci if (hflush) 9698c2ecf20Sopenharmony_ci _tlbiel_va_range_multicast(mm, 9708c2ecf20Sopenharmony_ci hstart, hend, pid, PMD_SIZE, MMU_PAGE_2M, false); 9718c2ecf20Sopenharmony_ci } 9728c2ecf20Sopenharmony_ci } 9738c2ecf20Sopenharmony_ci preempt_enable(); 9748c2ecf20Sopenharmony_ci} 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_civoid radix__flush_tlb_range(struct vm_area_struct *vma, unsigned long start, 9778c2ecf20Sopenharmony_ci unsigned long end) 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci{ 9808c2ecf20Sopenharmony_ci#ifdef CONFIG_HUGETLB_PAGE 9818c2ecf20Sopenharmony_ci if (is_vm_hugetlb_page(vma)) 9828c2ecf20Sopenharmony_ci return radix__flush_hugetlb_tlb_range(vma, start, end); 9838c2ecf20Sopenharmony_ci#endif 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci __radix__flush_tlb_range(vma->vm_mm, start, end); 9868c2ecf20Sopenharmony_ci} 9878c2ecf20Sopenharmony_ciEXPORT_SYMBOL(radix__flush_tlb_range); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_cistatic int radix_get_mmu_psize(int page_size) 9908c2ecf20Sopenharmony_ci{ 9918c2ecf20Sopenharmony_ci int psize; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci if (page_size == (1UL << mmu_psize_defs[mmu_virtual_psize].shift)) 9948c2ecf20Sopenharmony_ci psize = mmu_virtual_psize; 9958c2ecf20Sopenharmony_ci else if (page_size == (1UL << mmu_psize_defs[MMU_PAGE_2M].shift)) 9968c2ecf20Sopenharmony_ci psize = MMU_PAGE_2M; 9978c2ecf20Sopenharmony_ci else if (page_size == (1UL << mmu_psize_defs[MMU_PAGE_1G].shift)) 9988c2ecf20Sopenharmony_ci psize = MMU_PAGE_1G; 9998c2ecf20Sopenharmony_ci else 10008c2ecf20Sopenharmony_ci return -1; 10018c2ecf20Sopenharmony_ci return psize; 10028c2ecf20Sopenharmony_ci} 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci/* 10058c2ecf20Sopenharmony_ci * Flush partition scoped LPID address translation for all CPUs. 10068c2ecf20Sopenharmony_ci */ 10078c2ecf20Sopenharmony_civoid radix__flush_tlb_lpid_page(unsigned int lpid, 10088c2ecf20Sopenharmony_ci unsigned long addr, 10098c2ecf20Sopenharmony_ci unsigned long page_size) 10108c2ecf20Sopenharmony_ci{ 10118c2ecf20Sopenharmony_ci int psize = radix_get_mmu_psize(page_size); 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci _tlbie_lpid_va(addr, lpid, psize, RIC_FLUSH_TLB); 10148c2ecf20Sopenharmony_ci} 10158c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(radix__flush_tlb_lpid_page); 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci/* 10188c2ecf20Sopenharmony_ci * Flush partition scoped PWC from LPID for all CPUs. 10198c2ecf20Sopenharmony_ci */ 10208c2ecf20Sopenharmony_civoid radix__flush_pwc_lpid(unsigned int lpid) 10218c2ecf20Sopenharmony_ci{ 10228c2ecf20Sopenharmony_ci _tlbie_lpid(lpid, RIC_FLUSH_PWC); 10238c2ecf20Sopenharmony_ci} 10248c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(radix__flush_pwc_lpid); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci/* 10278c2ecf20Sopenharmony_ci * Flush partition scoped translations from LPID (=LPIDR) 10288c2ecf20Sopenharmony_ci */ 10298c2ecf20Sopenharmony_civoid radix__flush_all_lpid(unsigned int lpid) 10308c2ecf20Sopenharmony_ci{ 10318c2ecf20Sopenharmony_ci _tlbie_lpid(lpid, RIC_FLUSH_ALL); 10328c2ecf20Sopenharmony_ci} 10338c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(radix__flush_all_lpid); 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci/* 10368c2ecf20Sopenharmony_ci * Flush process scoped translations from LPID (=LPIDR) 10378c2ecf20Sopenharmony_ci */ 10388c2ecf20Sopenharmony_civoid radix__flush_all_lpid_guest(unsigned int lpid) 10398c2ecf20Sopenharmony_ci{ 10408c2ecf20Sopenharmony_ci _tlbie_lpid_guest(lpid, RIC_FLUSH_ALL); 10418c2ecf20Sopenharmony_ci} 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_cistatic void radix__flush_tlb_pwc_range_psize(struct mm_struct *mm, unsigned long start, 10448c2ecf20Sopenharmony_ci unsigned long end, int psize); 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_civoid radix__tlb_flush(struct mmu_gather *tlb) 10478c2ecf20Sopenharmony_ci{ 10488c2ecf20Sopenharmony_ci int psize = 0; 10498c2ecf20Sopenharmony_ci struct mm_struct *mm = tlb->mm; 10508c2ecf20Sopenharmony_ci int page_size = tlb->page_size; 10518c2ecf20Sopenharmony_ci unsigned long start = tlb->start; 10528c2ecf20Sopenharmony_ci unsigned long end = tlb->end; 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci /* 10558c2ecf20Sopenharmony_ci * if page size is not something we understand, do a full mm flush 10568c2ecf20Sopenharmony_ci * 10578c2ecf20Sopenharmony_ci * A "fullmm" flush must always do a flush_all_mm (RIC=2) flush 10588c2ecf20Sopenharmony_ci * that flushes the process table entry cache upon process teardown. 10598c2ecf20Sopenharmony_ci * See the comment for radix in arch_exit_mmap(). 10608c2ecf20Sopenharmony_ci */ 10618c2ecf20Sopenharmony_ci if (tlb->fullmm || tlb->need_flush_all) { 10628c2ecf20Sopenharmony_ci __flush_all_mm(mm, true); 10638c2ecf20Sopenharmony_ci } else if ( (psize = radix_get_mmu_psize(page_size)) == -1) { 10648c2ecf20Sopenharmony_ci if (!tlb->freed_tables) 10658c2ecf20Sopenharmony_ci radix__flush_tlb_mm(mm); 10668c2ecf20Sopenharmony_ci else 10678c2ecf20Sopenharmony_ci radix__flush_all_mm(mm); 10688c2ecf20Sopenharmony_ci } else { 10698c2ecf20Sopenharmony_ci if (!tlb->freed_tables) 10708c2ecf20Sopenharmony_ci radix__flush_tlb_range_psize(mm, start, end, psize); 10718c2ecf20Sopenharmony_ci else 10728c2ecf20Sopenharmony_ci radix__flush_tlb_pwc_range_psize(mm, start, end, psize); 10738c2ecf20Sopenharmony_ci } 10748c2ecf20Sopenharmony_ci} 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_cistatic void __radix__flush_tlb_range_psize(struct mm_struct *mm, 10778c2ecf20Sopenharmony_ci unsigned long start, unsigned long end, 10788c2ecf20Sopenharmony_ci int psize, bool also_pwc) 10798c2ecf20Sopenharmony_ci{ 10808c2ecf20Sopenharmony_ci unsigned long pid; 10818c2ecf20Sopenharmony_ci unsigned int page_shift = mmu_psize_defs[psize].shift; 10828c2ecf20Sopenharmony_ci unsigned long page_size = 1UL << page_shift; 10838c2ecf20Sopenharmony_ci unsigned long nr_pages = (end - start) >> page_shift; 10848c2ecf20Sopenharmony_ci bool local, full; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci pid = mm->context.id; 10878c2ecf20Sopenharmony_ci if (unlikely(pid == MMU_NO_CONTEXT)) 10888c2ecf20Sopenharmony_ci return; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci preempt_disable(); 10918c2ecf20Sopenharmony_ci smp_mb(); /* see radix__flush_tlb_mm */ 10928c2ecf20Sopenharmony_ci if (!mm_is_thread_local(mm)) { 10938c2ecf20Sopenharmony_ci if (unlikely(mm_is_singlethreaded(mm))) { 10948c2ecf20Sopenharmony_ci if (end != TLB_FLUSH_ALL) { 10958c2ecf20Sopenharmony_ci exit_flush_lazy_tlbs(mm); 10968c2ecf20Sopenharmony_ci goto is_local; 10978c2ecf20Sopenharmony_ci } 10988c2ecf20Sopenharmony_ci } 10998c2ecf20Sopenharmony_ci local = false; 11008c2ecf20Sopenharmony_ci full = (end == TLB_FLUSH_ALL || 11018c2ecf20Sopenharmony_ci nr_pages > tlb_single_page_flush_ceiling); 11028c2ecf20Sopenharmony_ci } else { 11038c2ecf20Sopenharmony_ciis_local: 11048c2ecf20Sopenharmony_ci local = true; 11058c2ecf20Sopenharmony_ci full = (end == TLB_FLUSH_ALL || 11068c2ecf20Sopenharmony_ci nr_pages > tlb_local_single_page_flush_ceiling); 11078c2ecf20Sopenharmony_ci } 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci if (!mmu_has_feature(MMU_FTR_GTSE) && !local) { 11108c2ecf20Sopenharmony_ci unsigned long tgt = H_RPTI_TARGET_CMMU; 11118c2ecf20Sopenharmony_ci unsigned long type = H_RPTI_TYPE_TLB; 11128c2ecf20Sopenharmony_ci unsigned long pg_sizes = psize_to_rpti_pgsize(psize); 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci if (also_pwc) 11158c2ecf20Sopenharmony_ci type |= H_RPTI_TYPE_PWC; 11168c2ecf20Sopenharmony_ci if (atomic_read(&mm->context.copros) > 0) 11178c2ecf20Sopenharmony_ci tgt |= H_RPTI_TARGET_NMMU; 11188c2ecf20Sopenharmony_ci pseries_rpt_invalidate(pid, tgt, type, pg_sizes, start, end); 11198c2ecf20Sopenharmony_ci } else if (full) { 11208c2ecf20Sopenharmony_ci if (local) { 11218c2ecf20Sopenharmony_ci _tlbiel_pid(pid, also_pwc ? RIC_FLUSH_ALL : RIC_FLUSH_TLB); 11228c2ecf20Sopenharmony_ci } else { 11238c2ecf20Sopenharmony_ci if (cputlb_use_tlbie()) { 11248c2ecf20Sopenharmony_ci if (mm_needs_flush_escalation(mm)) 11258c2ecf20Sopenharmony_ci also_pwc = true; 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci _tlbie_pid(pid, 11288c2ecf20Sopenharmony_ci also_pwc ? RIC_FLUSH_ALL : RIC_FLUSH_TLB); 11298c2ecf20Sopenharmony_ci } else { 11308c2ecf20Sopenharmony_ci _tlbiel_pid_multicast(mm, pid, 11318c2ecf20Sopenharmony_ci also_pwc ? RIC_FLUSH_ALL : RIC_FLUSH_TLB); 11328c2ecf20Sopenharmony_ci } 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci } else { 11368c2ecf20Sopenharmony_ci if (local) 11378c2ecf20Sopenharmony_ci _tlbiel_va_range(start, end, pid, page_size, psize, also_pwc); 11388c2ecf20Sopenharmony_ci else if (cputlb_use_tlbie()) 11398c2ecf20Sopenharmony_ci _tlbie_va_range(start, end, pid, page_size, psize, also_pwc); 11408c2ecf20Sopenharmony_ci else 11418c2ecf20Sopenharmony_ci _tlbiel_va_range_multicast(mm, 11428c2ecf20Sopenharmony_ci start, end, pid, page_size, psize, also_pwc); 11438c2ecf20Sopenharmony_ci } 11448c2ecf20Sopenharmony_ci preempt_enable(); 11458c2ecf20Sopenharmony_ci} 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_civoid radix__flush_tlb_range_psize(struct mm_struct *mm, unsigned long start, 11488c2ecf20Sopenharmony_ci unsigned long end, int psize) 11498c2ecf20Sopenharmony_ci{ 11508c2ecf20Sopenharmony_ci return __radix__flush_tlb_range_psize(mm, start, end, psize, false); 11518c2ecf20Sopenharmony_ci} 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_cistatic void radix__flush_tlb_pwc_range_psize(struct mm_struct *mm, unsigned long start, 11548c2ecf20Sopenharmony_ci unsigned long end, int psize) 11558c2ecf20Sopenharmony_ci{ 11568c2ecf20Sopenharmony_ci __radix__flush_tlb_range_psize(mm, start, end, psize, true); 11578c2ecf20Sopenharmony_ci} 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci#ifdef CONFIG_TRANSPARENT_HUGEPAGE 11608c2ecf20Sopenharmony_civoid radix__flush_tlb_collapsed_pmd(struct mm_struct *mm, unsigned long addr) 11618c2ecf20Sopenharmony_ci{ 11628c2ecf20Sopenharmony_ci unsigned long pid, end; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci pid = mm->context.id; 11658c2ecf20Sopenharmony_ci if (unlikely(pid == MMU_NO_CONTEXT)) 11668c2ecf20Sopenharmony_ci return; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci /* 4k page size, just blow the world */ 11698c2ecf20Sopenharmony_ci if (PAGE_SIZE == 0x1000) { 11708c2ecf20Sopenharmony_ci radix__flush_all_mm(mm); 11718c2ecf20Sopenharmony_ci return; 11728c2ecf20Sopenharmony_ci } 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci end = addr + HPAGE_PMD_SIZE; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci /* Otherwise first do the PWC, then iterate the pages. */ 11778c2ecf20Sopenharmony_ci preempt_disable(); 11788c2ecf20Sopenharmony_ci smp_mb(); /* see radix__flush_tlb_mm */ 11798c2ecf20Sopenharmony_ci if (!mm_is_thread_local(mm)) { 11808c2ecf20Sopenharmony_ci if (unlikely(mm_is_singlethreaded(mm))) { 11818c2ecf20Sopenharmony_ci exit_flush_lazy_tlbs(mm); 11828c2ecf20Sopenharmony_ci goto local; 11838c2ecf20Sopenharmony_ci } 11848c2ecf20Sopenharmony_ci if (!mmu_has_feature(MMU_FTR_GTSE)) { 11858c2ecf20Sopenharmony_ci unsigned long tgt, type, pg_sizes; 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci tgt = H_RPTI_TARGET_CMMU; 11888c2ecf20Sopenharmony_ci type = H_RPTI_TYPE_TLB | H_RPTI_TYPE_PWC | 11898c2ecf20Sopenharmony_ci H_RPTI_TYPE_PRT; 11908c2ecf20Sopenharmony_ci pg_sizes = psize_to_rpti_pgsize(mmu_virtual_psize); 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci if (atomic_read(&mm->context.copros) > 0) 11938c2ecf20Sopenharmony_ci tgt |= H_RPTI_TARGET_NMMU; 11948c2ecf20Sopenharmony_ci pseries_rpt_invalidate(pid, tgt, type, pg_sizes, 11958c2ecf20Sopenharmony_ci addr, end); 11968c2ecf20Sopenharmony_ci } else if (cputlb_use_tlbie()) 11978c2ecf20Sopenharmony_ci _tlbie_va_range(addr, end, pid, PAGE_SIZE, mmu_virtual_psize, true); 11988c2ecf20Sopenharmony_ci else 11998c2ecf20Sopenharmony_ci _tlbiel_va_range_multicast(mm, 12008c2ecf20Sopenharmony_ci addr, end, pid, PAGE_SIZE, mmu_virtual_psize, true); 12018c2ecf20Sopenharmony_ci } else { 12028c2ecf20Sopenharmony_cilocal: 12038c2ecf20Sopenharmony_ci _tlbiel_va_range(addr, end, pid, PAGE_SIZE, mmu_virtual_psize, true); 12048c2ecf20Sopenharmony_ci } 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci preempt_enable(); 12078c2ecf20Sopenharmony_ci} 12088c2ecf20Sopenharmony_ci#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_civoid radix__flush_pmd_tlb_range(struct vm_area_struct *vma, 12118c2ecf20Sopenharmony_ci unsigned long start, unsigned long end) 12128c2ecf20Sopenharmony_ci{ 12138c2ecf20Sopenharmony_ci radix__flush_tlb_range_psize(vma->vm_mm, start, end, MMU_PAGE_2M); 12148c2ecf20Sopenharmony_ci} 12158c2ecf20Sopenharmony_ciEXPORT_SYMBOL(radix__flush_pmd_tlb_range); 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_civoid radix__flush_tlb_all(void) 12188c2ecf20Sopenharmony_ci{ 12198c2ecf20Sopenharmony_ci unsigned long rb,prs,r,rs; 12208c2ecf20Sopenharmony_ci unsigned long ric = RIC_FLUSH_ALL; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci rb = 0x3 << PPC_BITLSHIFT(53); /* IS = 3 */ 12238c2ecf20Sopenharmony_ci prs = 0; /* partition scoped */ 12248c2ecf20Sopenharmony_ci r = 1; /* radix format */ 12258c2ecf20Sopenharmony_ci rs = 1 & ((1UL << 32) - 1); /* any LPID value to flush guest mappings */ 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci asm volatile("ptesync": : :"memory"); 12288c2ecf20Sopenharmony_ci /* 12298c2ecf20Sopenharmony_ci * now flush guest entries by passing PRS = 1 and LPID != 0 12308c2ecf20Sopenharmony_ci */ 12318c2ecf20Sopenharmony_ci asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1) 12328c2ecf20Sopenharmony_ci : : "r"(rb), "i"(r), "i"(1), "i"(ric), "r"(rs) : "memory"); 12338c2ecf20Sopenharmony_ci /* 12348c2ecf20Sopenharmony_ci * now flush host entires by passing PRS = 0 and LPID == 0 12358c2ecf20Sopenharmony_ci */ 12368c2ecf20Sopenharmony_ci asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1) 12378c2ecf20Sopenharmony_ci : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(0) : "memory"); 12388c2ecf20Sopenharmony_ci asm volatile("eieio; tlbsync; ptesync": : :"memory"); 12398c2ecf20Sopenharmony_ci} 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE 12428c2ecf20Sopenharmony_ciextern void radix_kvm_prefetch_workaround(struct mm_struct *mm) 12438c2ecf20Sopenharmony_ci{ 12448c2ecf20Sopenharmony_ci unsigned long pid = mm->context.id; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci if (unlikely(pid == MMU_NO_CONTEXT)) 12478c2ecf20Sopenharmony_ci return; 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci if (!cpu_has_feature(CPU_FTR_P9_RADIX_PREFETCH_BUG)) 12508c2ecf20Sopenharmony_ci return; 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci /* 12538c2ecf20Sopenharmony_ci * If this context hasn't run on that CPU before and KVM is 12548c2ecf20Sopenharmony_ci * around, there's a slim chance that the guest on another 12558c2ecf20Sopenharmony_ci * CPU just brought in obsolete translation into the TLB of 12568c2ecf20Sopenharmony_ci * this CPU due to a bad prefetch using the guest PID on 12578c2ecf20Sopenharmony_ci * the way into the hypervisor. 12588c2ecf20Sopenharmony_ci * 12598c2ecf20Sopenharmony_ci * We work around this here. If KVM is possible, we check if 12608c2ecf20Sopenharmony_ci * any sibling thread is in KVM. If it is, the window may exist 12618c2ecf20Sopenharmony_ci * and thus we flush that PID from the core. 12628c2ecf20Sopenharmony_ci * 12638c2ecf20Sopenharmony_ci * A potential future improvement would be to mark which PIDs 12648c2ecf20Sopenharmony_ci * have never been used on the system and avoid it if the PID 12658c2ecf20Sopenharmony_ci * is new and the process has no other cpumask bit set. 12668c2ecf20Sopenharmony_ci */ 12678c2ecf20Sopenharmony_ci if (cpu_has_feature(CPU_FTR_HVMODE) && radix_enabled()) { 12688c2ecf20Sopenharmony_ci int cpu = smp_processor_id(); 12698c2ecf20Sopenharmony_ci int sib = cpu_first_thread_sibling(cpu); 12708c2ecf20Sopenharmony_ci bool flush = false; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci for (; sib <= cpu_last_thread_sibling(cpu) && !flush; sib++) { 12738c2ecf20Sopenharmony_ci if (sib == cpu) 12748c2ecf20Sopenharmony_ci continue; 12758c2ecf20Sopenharmony_ci if (!cpu_possible(sib)) 12768c2ecf20Sopenharmony_ci continue; 12778c2ecf20Sopenharmony_ci if (paca_ptrs[sib]->kvm_hstate.kvm_vcpu) 12788c2ecf20Sopenharmony_ci flush = true; 12798c2ecf20Sopenharmony_ci } 12808c2ecf20Sopenharmony_ci if (flush) 12818c2ecf20Sopenharmony_ci _tlbiel_pid(pid, RIC_FLUSH_ALL); 12828c2ecf20Sopenharmony_ci } 12838c2ecf20Sopenharmony_ci} 12848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(radix_kvm_prefetch_workaround); 12858c2ecf20Sopenharmony_ci#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */ 1286