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