提交 45706bb5 编写于 作者: M Mahesh Salgaonkar 提交者: Michael Ellerman

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: NBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: NMahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
Signed-off-by: NMichael Ellerman <mpe@ellerman.id.au>
上级 7f664cf9
...@@ -100,7 +100,7 @@ struct cpu_spec { ...@@ -100,7 +100,7 @@ struct cpu_spec {
/* /*
* Processor specific routine to flush tlbs. * Processor specific routine to flush tlbs.
*/ */
void (*flush_tlb)(unsigned long inval_selector); void (*flush_tlb)(unsigned int action);
}; };
...@@ -114,6 +114,12 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start, ...@@ -114,6 +114,12 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
extern const char *powerpc_base_platform; extern const char *powerpc_base_platform;
/* TLB flush actions. Used as argument to cpu_spec.flush_tlb() hook */
enum {
TLB_INVAL_SCOPE_GLOBAL = 0, /* invalidate all TLBs */
TLB_INVAL_SCOPE_LPID = 1, /* invalidate TLBs for current LPID */
};
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
/* CPU kernel features */ /* CPU kernel features */
......
...@@ -112,6 +112,7 @@ ...@@ -112,6 +112,7 @@
#define TLBIEL_INVAL_SET_SHIFT 12 #define TLBIEL_INVAL_SET_SHIFT 12
#define POWER7_TLB_SETS 128 /* # sets in POWER7 TLB */ #define POWER7_TLB_SETS 128 /* # sets in POWER7 TLB */
#define POWER8_TLB_SETS 512 /* # sets in POWER8 TLB */
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
......
...@@ -137,15 +137,11 @@ __init_HFSCR: ...@@ -137,15 +137,11 @@ __init_HFSCR:
/* /*
* Clear the TLB using the specified IS form of tlbiel instruction * Clear the TLB using the specified IS form of tlbiel instruction
* (invalidate by congruence class). P7 has 128 CCs., P8 has 512. * (invalidate by congruence class). P7 has 128 CCs., P8 has 512.
*
* r3 = IS field
*/ */
__init_tlb_power7: __init_tlb_power7:
li r3,0xc00 /* IS field = 0b11 */
_GLOBAL(__flush_tlb_power7)
li r6,128 li r6,128
mtctr r6 mtctr r6
mr r7,r3 /* IS field */ li r7,0xc00 /* IS field = 0b11 */
ptesync ptesync
2: tlbiel r7 2: tlbiel r7
addi r7,r7,0x1000 addi r7,r7,0x1000
...@@ -154,11 +150,9 @@ _GLOBAL(__flush_tlb_power7) ...@@ -154,11 +150,9 @@ _GLOBAL(__flush_tlb_power7)
1: blr 1: blr
__init_tlb_power8: __init_tlb_power8:
li r3,0xc00 /* IS field = 0b11 */
_GLOBAL(__flush_tlb_power8)
li r6,512 li r6,512
mtctr r6 mtctr r6
mr r7,r3 /* IS field */ li r7,0xc00 /* IS field = 0b11 */
ptesync ptesync
2: tlbiel r7 2: tlbiel r7
addi r7,r7,0x1000 addi r7,r7,0x1000
......
...@@ -71,8 +71,8 @@ extern void __restore_cpu_power7(void); ...@@ -71,8 +71,8 @@ extern void __restore_cpu_power7(void);
extern void __setup_cpu_power8(unsigned long offset, struct cpu_spec* spec); extern void __setup_cpu_power8(unsigned long offset, struct cpu_spec* spec);
extern void __restore_cpu_power8(void); extern void __restore_cpu_power8(void);
extern void __restore_cpu_a2(void); extern void __restore_cpu_a2(void);
extern void __flush_tlb_power7(unsigned long inval_selector); extern void __flush_tlb_power7(unsigned int action);
extern void __flush_tlb_power8(unsigned long inval_selector); extern void __flush_tlb_power8(unsigned int action);
extern long __machine_check_early_realmode_p7(struct pt_regs *regs); extern long __machine_check_early_realmode_p7(struct pt_regs *regs);
extern long __machine_check_early_realmode_p8(struct pt_regs *regs); extern long __machine_check_early_realmode_p8(struct pt_regs *regs);
#endif /* CONFIG_PPC64 */ #endif /* CONFIG_PPC64 */
......
...@@ -28,6 +28,55 @@ ...@@ -28,6 +28,55 @@
#include <asm/mce.h> #include <asm/mce.h>
#include <asm/machdep.h> #include <asm/machdep.h>
static void flush_tlb_206(unsigned int num_sets, unsigned int action)
{
unsigned long rb;
unsigned int i;
switch (action) {
case TLB_INVAL_SCOPE_GLOBAL:
rb = TLBIEL_INVAL_SET;
break;
case TLB_INVAL_SCOPE_LPID:
rb = TLBIEL_INVAL_SET_LPID;
break;
default:
BUG();
break;
}
asm volatile("ptesync" : : : "memory");
for (i = 0; i < num_sets; i++) {
asm volatile("tlbiel %0" : : "r" (rb));
rb += 1 << TLBIEL_INVAL_SET_SHIFT;
}
asm volatile("ptesync" : : : "memory");
}
/*
* Generic routine to flush TLB on power7. This routine is used as
* flush_tlb hook in cpu_spec for Power7 processor.
*
* action => TLB_INVAL_SCOPE_GLOBAL: Invalidate all TLBs.
* TLB_INVAL_SCOPE_LPID: Invalidate TLB for current LPID.
*/
void __flush_tlb_power7(unsigned int action)
{
flush_tlb_206(POWER7_TLB_SETS, action);
}
/*
* Generic routine to flush TLB on power8. This routine is used as
* flush_tlb hook in cpu_spec for power8 processor.
*
* action => TLB_INVAL_SCOPE_GLOBAL: Invalidate all TLBs.
* TLB_INVAL_SCOPE_LPID: Invalidate TLB for current LPID.
*/
void __flush_tlb_power8(unsigned int action)
{
flush_tlb_206(POWER8_TLB_SETS, action);
}
/* flush SLBs and reload */ /* flush SLBs and reload */
static void flush_and_reload_slb(void) static void flush_and_reload_slb(void)
{ {
...@@ -79,7 +128,7 @@ static long mce_handle_derror(uint64_t dsisr, uint64_t slb_error_bits) ...@@ -79,7 +128,7 @@ static long mce_handle_derror(uint64_t dsisr, uint64_t slb_error_bits)
} }
if (dsisr & P7_DSISR_MC_TLB_MULTIHIT_MFTLB) { if (dsisr & P7_DSISR_MC_TLB_MULTIHIT_MFTLB) {
if (cur_cpu_spec && cur_cpu_spec->flush_tlb) if (cur_cpu_spec && cur_cpu_spec->flush_tlb)
cur_cpu_spec->flush_tlb(TLBIEL_INVAL_SET); cur_cpu_spec->flush_tlb(TLB_INVAL_SCOPE_GLOBAL);
/* reset error bits */ /* reset error bits */
dsisr &= ~P7_DSISR_MC_TLB_MULTIHIT_MFTLB; dsisr &= ~P7_DSISR_MC_TLB_MULTIHIT_MFTLB;
} }
...@@ -110,7 +159,7 @@ static long mce_handle_common_ierror(uint64_t srr1) ...@@ -110,7 +159,7 @@ static long mce_handle_common_ierror(uint64_t srr1)
break; break;
case P7_SRR1_MC_IFETCH_TLB_MULTIHIT: case P7_SRR1_MC_IFETCH_TLB_MULTIHIT:
if (cur_cpu_spec && cur_cpu_spec->flush_tlb) { if (cur_cpu_spec && cur_cpu_spec->flush_tlb) {
cur_cpu_spec->flush_tlb(TLBIEL_INVAL_SET); cur_cpu_spec->flush_tlb(TLB_INVAL_SCOPE_GLOBAL);
handled = 1; handled = 1;
} }
break; break;
......
...@@ -84,7 +84,7 @@ static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu) ...@@ -84,7 +84,7 @@ static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu)
} }
if (dsisr & DSISR_MC_TLB_MULTI) { if (dsisr & DSISR_MC_TLB_MULTI) {
if (cur_cpu_spec && cur_cpu_spec->flush_tlb) if (cur_cpu_spec && cur_cpu_spec->flush_tlb)
cur_cpu_spec->flush_tlb(TLBIEL_INVAL_SET_LPID); cur_cpu_spec->flush_tlb(TLB_INVAL_SCOPE_LPID);
dsisr &= ~DSISR_MC_TLB_MULTI; dsisr &= ~DSISR_MC_TLB_MULTI;
} }
/* Any other errors we don't understand? */ /* Any other errors we don't understand? */
...@@ -102,7 +102,7 @@ static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu) ...@@ -102,7 +102,7 @@ static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu)
break; break;
case SRR1_MC_IFETCH_TLBMULTI: case SRR1_MC_IFETCH_TLBMULTI:
if (cur_cpu_spec && cur_cpu_spec->flush_tlb) if (cur_cpu_spec && cur_cpu_spec->flush_tlb)
cur_cpu_spec->flush_tlb(TLBIEL_INVAL_SET_LPID); cur_cpu_spec->flush_tlb(TLB_INVAL_SCOPE_LPID);
break; break;
default: default:
handled = 0; handled = 0;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册