diff options
author | Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> | 2014-12-18 22:11:05 -0500 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2015-03-16 16:52:48 -0400 |
commit | 45706bb53d118b5340a12926e26444d73b6491f9 (patch) | |
tree | b88f88494c7fd725987973c83b3cbf4cb1760911 | |
parent | 7f664cf9e422105644818b180349e3b10a370de7 (diff) |
powerpc/book3s: Fix flush_tlb cpu_spec hook to take a generic argument.
The flush_tlb hook in cpu_spec was introduced as a generic function hook
to invalidate TLBs. But the current implementation of flush_tlb hook
takes IS (invalidation selector) as an argument which is architecture
dependent. Hence, It is not right to have a generic routine where caller
has to pass non-generic argument.
This patch fixes this and makes flush_tlb hook as high level API.
Reported-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r-- | arch/powerpc/include/asm/cputable.h | 8 | ||||
-rw-r--r-- | arch/powerpc/include/asm/mmu-hash64.h | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/cpu_setup_power.S | 10 | ||||
-rw-r--r-- | arch/powerpc/kernel/cputable.c | 4 | ||||
-rw-r--r-- | arch/powerpc/kernel/mce_power.c | 53 | ||||
-rw-r--r-- | arch/powerpc/kvm/book3s_hv_ras.c | 4 |
6 files changed, 65 insertions, 15 deletions
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index 5cf5a6d10685..6367b8347dad 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h | |||
@@ -100,7 +100,7 @@ struct cpu_spec { | |||
100 | /* | 100 | /* |
101 | * Processor specific routine to flush tlbs. | 101 | * Processor specific routine to flush tlbs. |
102 | */ | 102 | */ |
103 | void (*flush_tlb)(unsigned long inval_selector); | 103 | void (*flush_tlb)(unsigned int action); |
104 | 104 | ||
105 | }; | 105 | }; |
106 | 106 | ||
@@ -114,6 +114,12 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start, | |||
114 | 114 | ||
115 | extern const char *powerpc_base_platform; | 115 | extern const char *powerpc_base_platform; |
116 | 116 | ||
117 | /* TLB flush actions. Used as argument to cpu_spec.flush_tlb() hook */ | ||
118 | enum { | ||
119 | TLB_INVAL_SCOPE_GLOBAL = 0, /* invalidate all TLBs */ | ||
120 | TLB_INVAL_SCOPE_LPID = 1, /* invalidate TLBs for current LPID */ | ||
121 | }; | ||
122 | |||
117 | #endif /* __ASSEMBLY__ */ | 123 | #endif /* __ASSEMBLY__ */ |
118 | 124 | ||
119 | /* CPU kernel features */ | 125 | /* CPU kernel features */ |
diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h index 4f13c3ed7acf..1da6a81ce541 100644 --- a/arch/powerpc/include/asm/mmu-hash64.h +++ b/arch/powerpc/include/asm/mmu-hash64.h | |||
@@ -112,6 +112,7 @@ | |||
112 | #define TLBIEL_INVAL_SET_SHIFT 12 | 112 | #define TLBIEL_INVAL_SET_SHIFT 12 |
113 | 113 | ||
114 | #define POWER7_TLB_SETS 128 /* # sets in POWER7 TLB */ | 114 | #define POWER7_TLB_SETS 128 /* # sets in POWER7 TLB */ |
115 | #define POWER8_TLB_SETS 512 /* # sets in POWER8 TLB */ | ||
115 | 116 | ||
116 | #ifndef __ASSEMBLY__ | 117 | #ifndef __ASSEMBLY__ |
117 | 118 | ||
diff --git a/arch/powerpc/kernel/cpu_setup_power.S b/arch/powerpc/kernel/cpu_setup_power.S index 46733535cc0b..9c9b7411b28b 100644 --- a/arch/powerpc/kernel/cpu_setup_power.S +++ b/arch/powerpc/kernel/cpu_setup_power.S | |||
@@ -137,15 +137,11 @@ __init_HFSCR: | |||
137 | /* | 137 | /* |
138 | * Clear the TLB using the specified IS form of tlbiel instruction | 138 | * Clear the TLB using the specified IS form of tlbiel instruction |
139 | * (invalidate by congruence class). P7 has 128 CCs., P8 has 512. | 139 | * (invalidate by congruence class). P7 has 128 CCs., P8 has 512. |
140 | * | ||
141 | * r3 = IS field | ||
142 | */ | 140 | */ |
143 | __init_tlb_power7: | 141 | __init_tlb_power7: |
144 | li r3,0xc00 /* IS field = 0b11 */ | ||
145 | _GLOBAL(__flush_tlb_power7) | ||
146 | li r6,128 | 142 | li r6,128 |
147 | mtctr r6 | 143 | mtctr r6 |
148 | mr r7,r3 /* IS field */ | 144 | li r7,0xc00 /* IS field = 0b11 */ |
149 | ptesync | 145 | ptesync |
150 | 2: tlbiel r7 | 146 | 2: tlbiel r7 |
151 | addi r7,r7,0x1000 | 147 | addi r7,r7,0x1000 |
@@ -154,11 +150,9 @@ _GLOBAL(__flush_tlb_power7) | |||
154 | 1: blr | 150 | 1: blr |
155 | 151 | ||
156 | __init_tlb_power8: | 152 | __init_tlb_power8: |
157 | li r3,0xc00 /* IS field = 0b11 */ | ||
158 | _GLOBAL(__flush_tlb_power8) | ||
159 | li r6,512 | 153 | li r6,512 |
160 | mtctr r6 | 154 | mtctr r6 |
161 | mr r7,r3 /* IS field */ | 155 | li r7,0xc00 /* IS field = 0b11 */ |
162 | ptesync | 156 | ptesync |
163 | 2: tlbiel r7 | 157 | 2: tlbiel r7 |
164 | addi r7,r7,0x1000 | 158 | addi r7,r7,0x1000 |
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index f337666768a7..7ed126bc9b18 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c | |||
@@ -71,8 +71,8 @@ extern void __restore_cpu_power7(void); | |||
71 | extern void __setup_cpu_power8(unsigned long offset, struct cpu_spec* spec); | 71 | extern void __setup_cpu_power8(unsigned long offset, struct cpu_spec* spec); |
72 | extern void __restore_cpu_power8(void); | 72 | extern void __restore_cpu_power8(void); |
73 | extern void __restore_cpu_a2(void); | 73 | extern void __restore_cpu_a2(void); |
74 | extern void __flush_tlb_power7(unsigned long inval_selector); | 74 | extern void __flush_tlb_power7(unsigned int action); |
75 | extern void __flush_tlb_power8(unsigned long inval_selector); | 75 | extern void __flush_tlb_power8(unsigned int action); |
76 | extern long __machine_check_early_realmode_p7(struct pt_regs *regs); | 76 | extern long __machine_check_early_realmode_p7(struct pt_regs *regs); |
77 | extern long __machine_check_early_realmode_p8(struct pt_regs *regs); | 77 | extern long __machine_check_early_realmode_p8(struct pt_regs *regs); |
78 | #endif /* CONFIG_PPC64 */ | 78 | #endif /* CONFIG_PPC64 */ |
diff --git a/arch/powerpc/kernel/mce_power.c b/arch/powerpc/kernel/mce_power.c index b6f123ab90ed..2c647b1e62e4 100644 --- a/arch/powerpc/kernel/mce_power.c +++ b/arch/powerpc/kernel/mce_power.c | |||
@@ -28,6 +28,55 @@ | |||
28 | #include <asm/mce.h> | 28 | #include <asm/mce.h> |
29 | #include <asm/machdep.h> | 29 | #include <asm/machdep.h> |
30 | 30 | ||
31 | static void flush_tlb_206(unsigned int num_sets, unsigned int action) | ||
32 | { | ||
33 | unsigned long rb; | ||
34 | unsigned int i; | ||
35 | |||
36 | switch (action) { | ||
37 | case TLB_INVAL_SCOPE_GLOBAL: | ||
38 | rb = TLBIEL_INVAL_SET; | ||
39 | break; | ||
40 | case TLB_INVAL_SCOPE_LPID: | ||
41 | rb = TLBIEL_INVAL_SET_LPID; | ||
42 | break; | ||
43 | default: | ||
44 | BUG(); | ||
45 | break; | ||
46 | } | ||
47 | |||
48 | asm volatile("ptesync" : : : "memory"); | ||
49 | for (i = 0; i < num_sets; i++) { | ||
50 | asm volatile("tlbiel %0" : : "r" (rb)); | ||
51 | rb += 1 << TLBIEL_INVAL_SET_SHIFT; | ||
52 | } | ||
53 | asm volatile("ptesync" : : : "memory"); | ||
54 | } | ||
55 | |||
56 | /* | ||
57 | * Generic routine to flush TLB on power7. This routine is used as | ||
58 | * flush_tlb hook in cpu_spec for Power7 processor. | ||
59 | * | ||
60 | * action => TLB_INVAL_SCOPE_GLOBAL: Invalidate all TLBs. | ||
61 | * TLB_INVAL_SCOPE_LPID: Invalidate TLB for current LPID. | ||
62 | */ | ||
63 | void __flush_tlb_power7(unsigned int action) | ||
64 | { | ||
65 | flush_tlb_206(POWER7_TLB_SETS, action); | ||
66 | } | ||
67 | |||
68 | /* | ||
69 | * Generic routine to flush TLB on power8. This routine is used as | ||
70 | * flush_tlb hook in cpu_spec for power8 processor. | ||
71 | * | ||
72 | * action => TLB_INVAL_SCOPE_GLOBAL: Invalidate all TLBs. | ||
73 | * TLB_INVAL_SCOPE_LPID: Invalidate TLB for current LPID. | ||
74 | */ | ||
75 | void __flush_tlb_power8(unsigned int action) | ||
76 | { | ||
77 | flush_tlb_206(POWER8_TLB_SETS, action); | ||
78 | } | ||
79 | |||
31 | /* flush SLBs and reload */ | 80 | /* flush SLBs and reload */ |
32 | static void flush_and_reload_slb(void) | 81 | static void flush_and_reload_slb(void) |
33 | { | 82 | { |
@@ -79,7 +128,7 @@ static long mce_handle_derror(uint64_t dsisr, uint64_t slb_error_bits) | |||
79 | } | 128 | } |
80 | if (dsisr & P7_DSISR_MC_TLB_MULTIHIT_MFTLB) { | 129 | if (dsisr & P7_DSISR_MC_TLB_MULTIHIT_MFTLB) { |
81 | if (cur_cpu_spec && cur_cpu_spec->flush_tlb) | 130 | if (cur_cpu_spec && cur_cpu_spec->flush_tlb) |
82 | cur_cpu_spec->flush_tlb(TLBIEL_INVAL_SET); | 131 | cur_cpu_spec->flush_tlb(TLB_INVAL_SCOPE_GLOBAL); |
83 | /* reset error bits */ | 132 | /* reset error bits */ |
84 | dsisr &= ~P7_DSISR_MC_TLB_MULTIHIT_MFTLB; | 133 | dsisr &= ~P7_DSISR_MC_TLB_MULTIHIT_MFTLB; |
85 | } | 134 | } |
@@ -110,7 +159,7 @@ static long mce_handle_common_ierror(uint64_t srr1) | |||
110 | break; | 159 | break; |
111 | case P7_SRR1_MC_IFETCH_TLB_MULTIHIT: | 160 | case P7_SRR1_MC_IFETCH_TLB_MULTIHIT: |
112 | if (cur_cpu_spec && cur_cpu_spec->flush_tlb) { | 161 | if (cur_cpu_spec && cur_cpu_spec->flush_tlb) { |
113 | cur_cpu_spec->flush_tlb(TLBIEL_INVAL_SET); | 162 | cur_cpu_spec->flush_tlb(TLB_INVAL_SCOPE_GLOBAL); |
114 | handled = 1; | 163 | handled = 1; |
115 | } | 164 | } |
116 | break; | 165 | break; |
diff --git a/arch/powerpc/kvm/book3s_hv_ras.c b/arch/powerpc/kvm/book3s_hv_ras.c index 60081bd75847..93b5f5c9b445 100644 --- a/arch/powerpc/kvm/book3s_hv_ras.c +++ b/arch/powerpc/kvm/book3s_hv_ras.c | |||
@@ -84,7 +84,7 @@ static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu) | |||
84 | } | 84 | } |
85 | if (dsisr & DSISR_MC_TLB_MULTI) { | 85 | if (dsisr & DSISR_MC_TLB_MULTI) { |
86 | if (cur_cpu_spec && cur_cpu_spec->flush_tlb) | 86 | if (cur_cpu_spec && cur_cpu_spec->flush_tlb) |
87 | cur_cpu_spec->flush_tlb(TLBIEL_INVAL_SET_LPID); | 87 | cur_cpu_spec->flush_tlb(TLB_INVAL_SCOPE_LPID); |
88 | dsisr &= ~DSISR_MC_TLB_MULTI; | 88 | dsisr &= ~DSISR_MC_TLB_MULTI; |
89 | } | 89 | } |
90 | /* Any other errors we don't understand? */ | 90 | /* Any other errors we don't understand? */ |
@@ -102,7 +102,7 @@ static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu) | |||
102 | break; | 102 | break; |
103 | case SRR1_MC_IFETCH_TLBMULTI: | 103 | case SRR1_MC_IFETCH_TLBMULTI: |
104 | if (cur_cpu_spec && cur_cpu_spec->flush_tlb) | 104 | if (cur_cpu_spec && cur_cpu_spec->flush_tlb) |
105 | cur_cpu_spec->flush_tlb(TLBIEL_INVAL_SET_LPID); | 105 | cur_cpu_spec->flush_tlb(TLB_INVAL_SCOPE_LPID); |
106 | break; | 106 | break; |
107 | default: | 107 | default: |
108 | handled = 0; | 108 | handled = 0; |