aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>2018-03-23 00:56:27 -0400
committerMichael Ellerman <mpe@ellerman.id.au>2018-03-23 05:48:03 -0400
commita5d4b5891c2f1f865a2def1eb0030f534e77ff86 (patch)
tree7c3f4cce6cc8156676b76a384d032145af3507bb
parent243fee3249ff78e5f7ab822139dc89719def82d2 (diff)
powerpc/mm: Fixup tlbie vs store ordering issue on POWER9
On POWER9, under some circumstances, a broadcast TLB invalidation might complete before all previous stores have drained, potentially allowing stale stores from becoming visible after the invalidation. This works around it by doubling up those TLB invalidations which was verified by HW to be sufficient to close the risk window. This will be documented in a yet-to-be-published errata. Fixes: 1a472c9dba6b ("powerpc/mm/radix: Add tlbflush routines") Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> [mpe: Enable the feature in the DT CPU features code for all Power9, rename the feature to CPU_FTR_P9_TLBIE_BUG per benh.] Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r--arch/powerpc/include/asm/cputable.h3
-rw-r--r--arch/powerpc/kernel/dt_cpu_ftrs.c3
-rw-r--r--arch/powerpc/kvm/book3s_64_mmu_radix.c3
-rw-r--r--arch/powerpc/kvm/book3s_hv_rm_mmu.c11
-rw-r--r--arch/powerpc/mm/hash_native_64.c16
-rw-r--r--arch/powerpc/mm/pgtable_64.c1
-rw-r--r--arch/powerpc/mm/tlb-radix.c15
7 files changed, 50 insertions, 2 deletions
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index a2c5c95882cf..2e2bacbdf6ed 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -203,6 +203,7 @@ static inline void cpu_feature_keys_init(void) { }
203#define CPU_FTR_DAWR LONG_ASM_CONST(0x0400000000000000) 203#define CPU_FTR_DAWR LONG_ASM_CONST(0x0400000000000000)
204#define CPU_FTR_DABRX LONG_ASM_CONST(0x0800000000000000) 204#define CPU_FTR_DABRX LONG_ASM_CONST(0x0800000000000000)
205#define CPU_FTR_PMAO_BUG LONG_ASM_CONST(0x1000000000000000) 205#define CPU_FTR_PMAO_BUG LONG_ASM_CONST(0x1000000000000000)
206#define CPU_FTR_P9_TLBIE_BUG LONG_ASM_CONST(0x2000000000000000)
206#define CPU_FTR_POWER9_DD1 LONG_ASM_CONST(0x4000000000000000) 207#define CPU_FTR_POWER9_DD1 LONG_ASM_CONST(0x4000000000000000)
207#define CPU_FTR_POWER9_DD2_1 LONG_ASM_CONST(0x8000000000000000) 208#define CPU_FTR_POWER9_DD2_1 LONG_ASM_CONST(0x8000000000000000)
208 209
@@ -465,7 +466,7 @@ static inline void cpu_feature_keys_init(void) { }
465 CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY | \ 466 CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY | \
466 CPU_FTR_DBELL | CPU_FTR_HAS_PPR | CPU_FTR_DAWR | \ 467 CPU_FTR_DBELL | CPU_FTR_HAS_PPR | CPU_FTR_DAWR | \
467 CPU_FTR_ARCH_207S | CPU_FTR_TM_COMP | CPU_FTR_ARCH_300 | \ 468 CPU_FTR_ARCH_207S | CPU_FTR_TM_COMP | CPU_FTR_ARCH_300 | \
468 CPU_FTR_PKEY) 469 CPU_FTR_PKEY | CPU_FTR_P9_TLBIE_BUG)
469#define CPU_FTRS_POWER9_DD1 ((CPU_FTRS_POWER9 | CPU_FTR_POWER9_DD1) & \ 470#define CPU_FTRS_POWER9_DD1 ((CPU_FTRS_POWER9 | CPU_FTR_POWER9_DD1) & \
470 (~CPU_FTR_SAO)) 471 (~CPU_FTR_SAO))
471#define CPU_FTRS_POWER9_DD2_0 CPU_FTRS_POWER9 472#define CPU_FTRS_POWER9_DD2_0 CPU_FTRS_POWER9
diff --git a/arch/powerpc/kernel/dt_cpu_ftrs.c b/arch/powerpc/kernel/dt_cpu_ftrs.c
index 0bcfb0f256e1..8ca5d5b74618 100644
--- a/arch/powerpc/kernel/dt_cpu_ftrs.c
+++ b/arch/powerpc/kernel/dt_cpu_ftrs.c
@@ -709,6 +709,9 @@ static __init void cpufeatures_cpu_quirks(void)
709 cur_cpu_spec->cpu_features |= CPU_FTR_POWER9_DD1; 709 cur_cpu_spec->cpu_features |= CPU_FTR_POWER9_DD1;
710 else if ((version & 0xffffefff) == 0x004e0201) 710 else if ((version & 0xffffefff) == 0x004e0201)
711 cur_cpu_spec->cpu_features |= CPU_FTR_POWER9_DD2_1; 711 cur_cpu_spec->cpu_features |= CPU_FTR_POWER9_DD2_1;
712
713 if ((version & 0xffff0000) == 0x004e0000)
714 cur_cpu_spec->cpu_features |= CPU_FTR_P9_TLBIE_BUG;
712} 715}
713 716
714static void __init cpufeatures_setup_finished(void) 717static void __init cpufeatures_setup_finished(void)
diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c
index 0c854816e653..0837b9738d76 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_radix.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c
@@ -157,6 +157,9 @@ static void kvmppc_radix_tlbie_page(struct kvm *kvm, unsigned long addr,
157 asm volatile("ptesync": : :"memory"); 157 asm volatile("ptesync": : :"memory");
158 asm volatile(PPC_TLBIE_5(%0, %1, 0, 0, 1) 158 asm volatile(PPC_TLBIE_5(%0, %1, 0, 0, 1)
159 : : "r" (addr), "r" (kvm->arch.lpid) : "memory"); 159 : : "r" (addr), "r" (kvm->arch.lpid) : "memory");
160 if (cpu_has_feature(CPU_FTR_P9_TLBIE_BUG))
161 asm volatile(PPC_TLBIE_5(%0, %1, 0, 0, 1)
162 : : "r" (addr), "r" (kvm->arch.lpid) : "memory");
160 asm volatile("ptesync": : :"memory"); 163 asm volatile("ptesync": : :"memory");
161} 164}
162 165
diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
index 8888e625a999..e1c083fbe434 100644
--- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c
+++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
@@ -473,6 +473,17 @@ static void do_tlbies(struct kvm *kvm, unsigned long *rbvalues,
473 trace_tlbie(kvm->arch.lpid, 0, rbvalues[i], 473 trace_tlbie(kvm->arch.lpid, 0, rbvalues[i],
474 kvm->arch.lpid, 0, 0, 0); 474 kvm->arch.lpid, 0, 0, 0);
475 } 475 }
476
477 if (cpu_has_feature(CPU_FTR_P9_TLBIE_BUG)) {
478 /*
479 * Need the extra ptesync to make sure we don't
480 * re-order the tlbie
481 */
482 asm volatile("ptesync": : :"memory");
483 asm volatile(PPC_TLBIE_5(%0,%1,0,0,0) : :
484 "r" (rbvalues[0]), "r" (kvm->arch.lpid));
485 }
486
476 asm volatile("eieio; tlbsync; ptesync" : : : "memory"); 487 asm volatile("eieio; tlbsync; ptesync" : : : "memory");
477 kvm->arch.tlbie_lock = 0; 488 kvm->arch.tlbie_lock = 0;
478 } else { 489 } else {
diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c
index a0675e91ad7d..656933c85925 100644
--- a/arch/powerpc/mm/hash_native_64.c
+++ b/arch/powerpc/mm/hash_native_64.c
@@ -201,6 +201,15 @@ static inline unsigned long ___tlbie(unsigned long vpn, int psize,
201 return va; 201 return va;
202} 202}
203 203
204static inline void fixup_tlbie(unsigned long vpn, int psize, int apsize, int ssize)
205{
206 if (cpu_has_feature(CPU_FTR_P9_TLBIE_BUG)) {
207 /* Need the extra ptesync to ensure we don't reorder tlbie*/
208 asm volatile("ptesync": : :"memory");
209 ___tlbie(vpn, psize, apsize, ssize);
210 }
211}
212
204static inline void __tlbie(unsigned long vpn, int psize, int apsize, int ssize) 213static inline void __tlbie(unsigned long vpn, int psize, int apsize, int ssize)
205{ 214{
206 unsigned long rb; 215 unsigned long rb;
@@ -278,6 +287,7 @@ static inline void tlbie(unsigned long vpn, int psize, int apsize,
278 asm volatile("ptesync": : :"memory"); 287 asm volatile("ptesync": : :"memory");
279 } else { 288 } else {
280 __tlbie(vpn, psize, apsize, ssize); 289 __tlbie(vpn, psize, apsize, ssize);
290 fixup_tlbie(vpn, psize, apsize, ssize);
281 asm volatile("eieio; tlbsync; ptesync": : :"memory"); 291 asm volatile("eieio; tlbsync; ptesync": : :"memory");
282 } 292 }
283 if (lock_tlbie && !use_local) 293 if (lock_tlbie && !use_local)
@@ -771,7 +781,7 @@ static void native_hpte_clear(void)
771 */ 781 */
772static void native_flush_hash_range(unsigned long number, int local) 782static void native_flush_hash_range(unsigned long number, int local)
773{ 783{
774 unsigned long vpn; 784 unsigned long vpn = 0;
775 unsigned long hash, index, hidx, shift, slot; 785 unsigned long hash, index, hidx, shift, slot;
776 struct hash_pte *hptep; 786 struct hash_pte *hptep;
777 unsigned long hpte_v; 787 unsigned long hpte_v;
@@ -843,6 +853,10 @@ static void native_flush_hash_range(unsigned long number, int local)
843 __tlbie(vpn, psize, psize, ssize); 853 __tlbie(vpn, psize, psize, ssize);
844 } pte_iterate_hashed_end(); 854 } pte_iterate_hashed_end();
845 } 855 }
856 /*
857 * Just do one more with the last used values.
858 */
859 fixup_tlbie(vpn, psize, psize, ssize);
846 asm volatile("eieio; tlbsync; ptesync":::"memory"); 860 asm volatile("eieio; tlbsync; ptesync":::"memory");
847 861
848 if (lock_tlbie) 862 if (lock_tlbie)
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index 28c980eb4422..adf469f312f2 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -481,6 +481,7 @@ void mmu_partition_table_set_entry(unsigned int lpid, unsigned long dw0,
481 "r" (TLBIEL_INVAL_SET_LPID), "r" (lpid)); 481 "r" (TLBIEL_INVAL_SET_LPID), "r" (lpid));
482 trace_tlbie(lpid, 0, TLBIEL_INVAL_SET_LPID, lpid, 2, 0, 0); 482 trace_tlbie(lpid, 0, TLBIEL_INVAL_SET_LPID, lpid, 2, 0, 0);
483 } 483 }
484 /* do we need fixup here ?*/
484 asm volatile("eieio; tlbsync; ptesync" : : : "memory"); 485 asm volatile("eieio; tlbsync; ptesync" : : : "memory");
485} 486}
486EXPORT_SYMBOL_GPL(mmu_partition_table_set_entry); 487EXPORT_SYMBOL_GPL(mmu_partition_table_set_entry);
diff --git a/arch/powerpc/mm/tlb-radix.c b/arch/powerpc/mm/tlb-radix.c
index 74354c26d316..a07f5372a4bf 100644
--- a/arch/powerpc/mm/tlb-radix.c
+++ b/arch/powerpc/mm/tlb-radix.c
@@ -151,6 +151,17 @@ static inline void __tlbie_va(unsigned long va, unsigned long pid,
151 trace_tlbie(0, 0, rb, rs, ric, prs, r); 151 trace_tlbie(0, 0, rb, rs, ric, prs, r);
152} 152}
153 153
154static inline void fixup_tlbie(void)
155{
156 unsigned long pid = 0;
157 unsigned long va = ((1UL << 52) - 1);
158
159 if (cpu_has_feature(CPU_FTR_P9_TLBIE_BUG)) {
160 asm volatile("ptesync": : :"memory");
161 __tlbie_va(va, pid, mmu_get_ap(MMU_PAGE_64K), RIC_FLUSH_TLB);
162 }
163}
164
154/* 165/*
155 * We use 128 set in radix mode and 256 set in hpt mode. 166 * We use 128 set in radix mode and 256 set in hpt mode.
156 */ 167 */
@@ -200,6 +211,7 @@ static inline void _tlbie_pid(unsigned long pid, unsigned long ric)
200 default: 211 default:
201 __tlbie_pid(pid, RIC_FLUSH_ALL); 212 __tlbie_pid(pid, RIC_FLUSH_ALL);
202 } 213 }
214 fixup_tlbie();
203 asm volatile("eieio; tlbsync; ptesync": : :"memory"); 215 asm volatile("eieio; tlbsync; ptesync": : :"memory");
204} 216}
205 217
@@ -253,6 +265,7 @@ static inline void _tlbie_va(unsigned long va, unsigned long pid,
253 265
254 asm volatile("ptesync": : :"memory"); 266 asm volatile("ptesync": : :"memory");
255 __tlbie_va(va, pid, ap, ric); 267 __tlbie_va(va, pid, ap, ric);
268 fixup_tlbie();
256 asm volatile("eieio; tlbsync; ptesync": : :"memory"); 269 asm volatile("eieio; tlbsync; ptesync": : :"memory");
257} 270}
258 271
@@ -264,6 +277,7 @@ static inline void _tlbie_va_range(unsigned long start, unsigned long end,
264 if (also_pwc) 277 if (also_pwc)
265 __tlbie_pid(pid, RIC_FLUSH_PWC); 278 __tlbie_pid(pid, RIC_FLUSH_PWC);
266 __tlbie_va_range(start, end, pid, page_size, psize); 279 __tlbie_va_range(start, end, pid, page_size, psize);
280 fixup_tlbie();
267 asm volatile("eieio; tlbsync; ptesync": : :"memory"); 281 asm volatile("eieio; tlbsync; ptesync": : :"memory");
268} 282}
269 283
@@ -498,6 +512,7 @@ void radix__flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
498 if (hflush) 512 if (hflush)
499 __tlbie_va_range(hstart, hend, pid, 513 __tlbie_va_range(hstart, hend, pid,
500 HPAGE_PMD_SIZE, MMU_PAGE_2M); 514 HPAGE_PMD_SIZE, MMU_PAGE_2M);
515 fixup_tlbie();
501 asm volatile("eieio; tlbsync; ptesync": : :"memory"); 516 asm volatile("eieio; tlbsync; ptesync": : :"memory");
502 } 517 }
503 } 518 }