powerpc/mm: Update tlbiel loop on POWER10

With POWER10, single tlbiel instruction invalidates all the congruence
class of the TLB and hence we need to issue only one tlbiel with SET=0.

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20201007053305.232879-1-aneesh.kumar@linux.ibm.com
This commit is contained in:
Aneesh Kumar K.V 2020-10-07 11:03:05 +05:30 коммит произвёл Michael Ellerman
Родитель a7223f5bfc
Коммит e80639405c
3 изменённых файлов: 32 добавлений и 9 удалений

Просмотреть файл

@ -4949,7 +4949,12 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm)
* Work out how many sets the TLB has, for the use of
* the TLB invalidation loop in book3s_hv_rmhandlers.S.
*/
if (radix_enabled())
if (cpu_has_feature(CPU_FTR_ARCH_31)) {
/*
* P10 will flush all the congruence class with a single tlbiel
*/
kvm->arch.tlb_sets = 1;
} else if (radix_enabled())
kvm->arch.tlb_sets = POWER9_TLB_SETS_RADIX; /* 128 */
else if (cpu_has_feature(CPU_FTR_ARCH_300))
kvm->arch.tlb_sets = POWER9_TLB_SETS_HASH; /* 256 */

Просмотреть файл

@ -694,6 +694,7 @@ static void wait_for_sync(struct kvm_split_mode *sip, int phase)
void kvmhv_p9_set_lpcr(struct kvm_split_mode *sip)
{
int num_sets;
unsigned long rb, set;
/* wait for every other thread to get to real mode */
@ -704,11 +705,19 @@ void kvmhv_p9_set_lpcr(struct kvm_split_mode *sip)
mtspr(SPRN_LPID, sip->lpidr_req);
isync();
/*
* P10 will flush all the congruence class with a single tlbiel
*/
if (cpu_has_feature(CPU_FTR_ARCH_31))
num_sets = 1;
else
num_sets = POWER9_TLB_SETS_RADIX;
/* Invalidate the TLB on thread 0 */
if (local_paca->kvm_hstate.tid == 0) {
sip->do_set = 0;
asm volatile("ptesync" : : : "memory");
for (set = 0; set < POWER9_TLB_SETS_RADIX; ++set) {
for (set = 0; set < num_sets; ++set) {
rb = TLBIEL_INVAL_SET_LPID +
(set << TLBIEL_INVAL_SET_SHIFT);
asm volatile(PPC_TLBIEL(%0, %1, 0, 0, 0) : :

Просмотреть файл

@ -56,14 +56,21 @@ static void tlbiel_all_isa300(unsigned int num_sets, unsigned int is)
if (early_cpu_has_feature(CPU_FTR_HVMODE)) {
/* MSR[HV] should flush partition scope translations first. */
tlbiel_radix_set_isa300(0, is, 0, RIC_FLUSH_ALL, 0);
for (set = 1; set < num_sets; set++)
tlbiel_radix_set_isa300(set, is, 0, RIC_FLUSH_TLB, 0);
if (!early_cpu_has_feature(CPU_FTR_ARCH_31)) {
for (set = 1; set < num_sets; set++)
tlbiel_radix_set_isa300(set, is, 0,
RIC_FLUSH_TLB, 0);
}
}
/* Flush process scoped entries. */
tlbiel_radix_set_isa300(0, is, 0, RIC_FLUSH_ALL, 1);
for (set = 1; set < num_sets; set++)
tlbiel_radix_set_isa300(set, is, 0, RIC_FLUSH_TLB, 1);
if (!early_cpu_has_feature(CPU_FTR_ARCH_31)) {
for (set = 1; set < num_sets; set++)
tlbiel_radix_set_isa300(set, is, 0, RIC_FLUSH_TLB, 1);
}
ppc_after_tlbiel_barrier();
}
@ -300,9 +307,11 @@ static __always_inline void _tlbiel_pid(unsigned long pid, unsigned long ric)
return;
}
/* For the remaining sets, just flush the TLB */
for (set = 1; set < POWER9_TLB_SETS_RADIX ; set++)
__tlbiel_pid(pid, set, RIC_FLUSH_TLB);
if (!cpu_has_feature(CPU_FTR_ARCH_31)) {
/* For the remaining sets, just flush the TLB */
for (set = 1; set < POWER9_TLB_SETS_RADIX ; set++)
__tlbiel_pid(pid, set, RIC_FLUSH_TLB);
}
ppc_after_tlbiel_barrier();
asm volatile(PPC_RADIX_INVALIDATE_ERAT_USER "; isync" : : :"memory");