Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 45706bb5 authored by Mahesh Salgaonkar's avatar Mahesh Salgaonkar Committed by Michael Ellerman
Browse files

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: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarMahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 7f664cf9
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -100,7 +100,7 @@ struct cpu_spec {
	/*
	 * 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,

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__ */

/* CPU kernel features */
+1 −0
Original line number Diff line number Diff line
@@ -112,6 +112,7 @@
#define TLBIEL_INVAL_SET_SHIFT	12

#define POWER7_TLB_SETS		128	/* # sets in POWER7 TLB */
#define POWER8_TLB_SETS		512	/* # sets in POWER8 TLB */

#ifndef __ASSEMBLY__

+2 −8
Original line number Diff line number Diff line
@@ -137,15 +137,11 @@ __init_HFSCR:
/*
 * Clear the TLB using the specified IS form of tlbiel instruction
 * (invalidate by congruence class). P7 has 128 CCs., P8 has 512.
 *
 * r3 = IS field
 */
__init_tlb_power7:
	li	r3,0xc00	/* IS field = 0b11 */
_GLOBAL(__flush_tlb_power7)
	li	r6,128
	mtctr	r6
	mr	r7,r3		/* IS field */
	li	r7,0xc00	/* IS field = 0b11 */
	ptesync
2:	tlbiel	r7
	addi	r7,r7,0x1000
@@ -154,11 +150,9 @@ _GLOBAL(__flush_tlb_power7)
1:	blr

__init_tlb_power8:
	li	r3,0xc00	/* IS field = 0b11 */
_GLOBAL(__flush_tlb_power8)
	li	r6,512
	mtctr	r6
	mr	r7,r3		/* IS field */
	li	r7,0xc00	/* IS field = 0b11 */
	ptesync
2:	tlbiel	r7
	addi	r7,r7,0x1000
+2 −2
Original line number Diff line number Diff line
@@ -71,8 +71,8 @@ extern void __restore_cpu_power7(void);
extern void __setup_cpu_power8(unsigned long offset, struct cpu_spec* spec);
extern void __restore_cpu_power8(void);
extern void __restore_cpu_a2(void);
extern void __flush_tlb_power7(unsigned long inval_selector);
extern void __flush_tlb_power8(unsigned long inval_selector);
extern void __flush_tlb_power7(unsigned int action);
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_p8(struct pt_regs *regs);
#endif /* CONFIG_PPC64 */
+51 −2
Original line number Diff line number Diff line
@@ -28,6 +28,55 @@
#include <asm/mce.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 */
static void flush_and_reload_slb(void)
{
@@ -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 (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 */
		dsisr &= ~P7_DSISR_MC_TLB_MULTIHIT_MFTLB;
	}
@@ -110,7 +159,7 @@ static long mce_handle_common_ierror(uint64_t srr1)
		break;
	case P7_SRR1_MC_IFETCH_TLB_MULTIHIT:
		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;
		}
		break;
Loading