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

powernv/pseries: consolidate code for mce early handling.



Now that other platforms also implements real mode mce handler,
lets consolidate the code by sharing existing powernv machine check
early code. Rename machine_check_powernv_early to
machine_check_common_early and reuse the code.

Signed-off-by: default avatarMahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent c6d15258
Loading
Loading
Loading
Loading
+28 −127
Original line number Original line Diff line number Diff line
@@ -244,14 +244,13 @@ EXC_REAL_BEGIN(machine_check, 0x200, 0x100)
	SET_SCRATCH0(r13)		/* save r13 */
	SET_SCRATCH0(r13)		/* save r13 */
	EXCEPTION_PROLOG_0(PACA_EXMC)
	EXCEPTION_PROLOG_0(PACA_EXMC)
BEGIN_FTR_SECTION
BEGIN_FTR_SECTION
	b	machine_check_powernv_early
	b	machine_check_common_early
FTR_SECTION_ELSE
FTR_SECTION_ELSE
	b	machine_check_pSeries_0
	b	machine_check_pSeries_0
ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
EXC_REAL_END(machine_check, 0x200, 0x100)
EXC_REAL_END(machine_check, 0x200, 0x100)
EXC_VIRT_NONE(0x4200, 0x100)
EXC_VIRT_NONE(0x4200, 0x100)
TRAMP_REAL_BEGIN(machine_check_powernv_early)
TRAMP_REAL_BEGIN(machine_check_common_early)
BEGIN_FTR_SECTION
	EXCEPTION_PROLOG_1(PACA_EXMC, NOTEST, 0x200)
	EXCEPTION_PROLOG_1(PACA_EXMC, NOTEST, 0x200)
	/*
	/*
	 * Register contents:
	 * Register contents:
@@ -305,7 +304,9 @@ BEGIN_FTR_SECTION
	/* Save r9 through r13 from EXMC save area to stack frame. */
	/* Save r9 through r13 from EXMC save area to stack frame. */
	EXCEPTION_PROLOG_COMMON_2(PACA_EXMC)
	EXCEPTION_PROLOG_COMMON_2(PACA_EXMC)
	mfmsr	r11			/* get MSR value */
	mfmsr	r11			/* get MSR value */
BEGIN_FTR_SECTION
	ori	r11,r11,MSR_ME		/* turn on ME bit */
	ori	r11,r11,MSR_ME		/* turn on ME bit */
END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
	ori	r11,r11,MSR_RI		/* turn on RI bit */
	ori	r11,r11,MSR_RI		/* turn on RI bit */
	LOAD_HANDLER(r12, machine_check_handle_early)
	LOAD_HANDLER(r12, machine_check_handle_early)
1:	mtspr	SPRN_SRR0,r12
1:	mtspr	SPRN_SRR0,r12
@@ -324,7 +325,6 @@ BEGIN_FTR_SECTION
	andc	r11,r11,r10		/* Turn off MSR_ME */
	andc	r11,r11,r10		/* Turn off MSR_ME */
	b	1b
	b	1b
	b	.	/* prevent speculative execution */
	b	.	/* prevent speculative execution */
END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)


TRAMP_REAL_BEGIN(machine_check_pSeries)
TRAMP_REAL_BEGIN(machine_check_pSeries)
	.globl machine_check_fwnmi
	.globl machine_check_fwnmi
@@ -332,7 +332,7 @@ machine_check_fwnmi:
	SET_SCRATCH0(r13)		/* save r13 */
	SET_SCRATCH0(r13)		/* save r13 */
	EXCEPTION_PROLOG_0(PACA_EXMC)
	EXCEPTION_PROLOG_0(PACA_EXMC)
BEGIN_FTR_SECTION
BEGIN_FTR_SECTION
	b	machine_check_pSeries_early
	b	machine_check_common_early
END_FTR_SECTION_IFCLR(CPU_FTR_HVMODE)
END_FTR_SECTION_IFCLR(CPU_FTR_HVMODE)
machine_check_pSeries_0:
machine_check_pSeries_0:
	EXCEPTION_PROLOG_1(PACA_EXMC, KVMTEST_PR, 0x200)
	EXCEPTION_PROLOG_1(PACA_EXMC, KVMTEST_PR, 0x200)
@@ -345,103 +345,6 @@ machine_check_pSeries_0:


TRAMP_KVM_SKIP(PACA_EXMC, 0x200)
TRAMP_KVM_SKIP(PACA_EXMC, 0x200)


TRAMP_REAL_BEGIN(machine_check_pSeries_early)
BEGIN_FTR_SECTION
	EXCEPTION_PROLOG_1(PACA_EXMC, NOTEST, 0x200)
	mr	r10,r1			/* Save r1 */
	lhz	r11,PACA_IN_MCE(r13)
	cmpwi	r11,0			/* Are we in nested machine check */
	bne	0f			/* Yes, we are. */
	/* First machine check entry */
	ld	r1,PACAMCEMERGSP(r13)	/* Use MC emergency stack */
0:	subi	r1,r1,INT_FRAME_SIZE	/* alloc stack frame */
	addi	r11,r11,1		/* increment paca->in_mce */
	sth	r11,PACA_IN_MCE(r13)
	/* Limit nested MCE to level 4 to avoid stack overflow */
	cmpwi	r11,MAX_MCE_DEPTH
	bgt	1f			/* Check if we hit limit of 4 */
	mfspr	r11,SPRN_SRR0		/* Save SRR0 */
	mfspr	r12,SPRN_SRR1		/* Save SRR1 */
	EXCEPTION_PROLOG_COMMON_1()
	EXCEPTION_PROLOG_COMMON_2(PACA_EXMC)
	EXCEPTION_PROLOG_COMMON_3(0x200)
	addi	r3,r1,STACK_FRAME_OVERHEAD
	BRANCH_LINK_TO_FAR(machine_check_early) /* Function call ABI */
	ld	r12,_MSR(r1)
	andi.	r11,r12,MSR_PR		/* See if coming from user. */
	bne	2f			/* continue in V mode if we are. */

	/*
	 * At this point we are not sure about what context we come from.
	 * We may be in the middle of switching stack. r1 may not be valid.
	 * Hence stay on emergency stack, call machine_check_exception and
	 * return from the interrupt.
	 * But before that, check if this is an un-recoverable exception.
	 * If yes, then stay on emergency stack and panic.
	 */
	andi.	r11,r12,MSR_RI
	beq	1f

	/*
	 * Check if we have successfully handled/recovered from error, if not
	 * then stay on emergency stack and panic.
	 */
	cmpdi	r3,0		/* see if we handled MCE successfully */
	beq	1f		/* if !handled then panic */

	/* Stay on emergency stack and return from interrupt. */
	LOAD_HANDLER(r10,mce_return)
	mtspr	SPRN_SRR0,r10
	ld	r10,PACAKMSR(r13)
	mtspr	SPRN_SRR1,r10
	RFI_TO_KERNEL
	b	.

1:	LOAD_HANDLER(r10,unrecover_mce)
	mtspr	SPRN_SRR0,r10
	ld	r10,PACAKMSR(r13)
	/*
	 * We are going down. But there are chances that we might get hit by
	 * another MCE during panic path and we may run into unstable state
	 * with no way out. Hence, turn ME bit off while going down, so that
	 * when another MCE is hit during panic path, hypervisor will
	 * power cycle the lpar, instead of getting into MCE loop.
	 */
	li	r3,MSR_ME
	andc	r10,r10,r3		/* Turn off MSR_ME */
	mtspr	SPRN_SRR1,r10
	RFI_TO_KERNEL
	b	.

	/* Move original SRR0 and SRR1 into the respective regs */
2:	ld	r9,_MSR(r1)
	mtspr	SPRN_SRR1,r9
	ld	r3,_NIP(r1)
	mtspr	SPRN_SRR0,r3
	ld	r9,_CTR(r1)
	mtctr	r9
	ld	r9,_XER(r1)
	mtxer	r9
	ld	r9,_LINK(r1)
	mtlr	r9
	REST_GPR(0, r1)
	REST_8GPRS(2, r1)
	REST_GPR(10, r1)
	ld	r11,_CCR(r1)
	mtcr	r11
	/* Decrement paca->in_mce. */
	lhz	r12,PACA_IN_MCE(r13)
	subi	r12,r12,1
	sth	r12,PACA_IN_MCE(r13)
	REST_GPR(11, r1)
	REST_2GPRS(12, r1)
	/* restore original r1. */
	ld	r1,GPR1(r1)
	SET_SCRATCH0(r13)		/* save r13 */
	EXCEPTION_PROLOG_0(PACA_EXMC)
	b	machine_check_pSeries_0
END_FTR_SECTION_IFCLR(CPU_FTR_HVMODE)

EXC_COMMON_BEGIN(machine_check_common)
EXC_COMMON_BEGIN(machine_check_common)
	/*
	/*
	 * Machine check is different because we use a different
	 * Machine check is different because we use a different
@@ -540,6 +443,9 @@ EXC_COMMON_BEGIN(machine_check_handle_early)
	bl	machine_check_early
	bl	machine_check_early
	std	r3,RESULT(r1)	/* Save result */
	std	r3,RESULT(r1)	/* Save result */
	ld	r12,_MSR(r1)
	ld	r12,_MSR(r1)
BEGIN_FTR_SECTION
	b	4f
END_FTR_SECTION_IFCLR(CPU_FTR_HVMODE)


#ifdef	CONFIG_PPC_P7_NAP
#ifdef	CONFIG_PPC_P7_NAP
	/*
	/*
@@ -563,11 +469,12 @@ EXC_COMMON_BEGIN(machine_check_handle_early)
	 */
	 */
	rldicl.	r11,r12,4,63		/* See if MC hit while in HV mode. */
	rldicl.	r11,r12,4,63		/* See if MC hit while in HV mode. */
	beq	5f
	beq	5f
	andi.	r11,r12,MSR_PR		/* See if coming from user. */
4:	andi.	r11,r12,MSR_PR		/* See if coming from user. */
	bne	9f			/* continue in V mode if we are. */
	bne	9f			/* continue in V mode if we are. */


5:
5:
#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
#ifdef CONFIG_KVM_BOOK3S_64_HANDLER
BEGIN_FTR_SECTION
	/*
	/*
	 * We are coming from kernel context. Check if we are coming from
	 * We are coming from kernel context. Check if we are coming from
	 * guest. if yes, then we can continue. We will fall through
	 * guest. if yes, then we can continue. We will fall through
@@ -576,6 +483,7 @@ EXC_COMMON_BEGIN(machine_check_handle_early)
	lbz	r11,HSTATE_IN_GUEST(r13)
	lbz	r11,HSTATE_IN_GUEST(r13)
	cmpwi	r11,0			/* Check if coming from guest */
	cmpwi	r11,0			/* Check if coming from guest */
	bne	9f			/* continue if we are. */
	bne	9f			/* continue if we are. */
END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
#endif
#endif
	/*
	/*
	 * At this point we are not sure about what context we come from.
	 * At this point we are not sure about what context we come from.
@@ -610,6 +518,7 @@ EXC_COMMON_BEGIN(machine_check_handle_early)
	cmpdi	r3,0		/* see if we handled MCE successfully */
	cmpdi	r3,0		/* see if we handled MCE successfully */


	beq	1b		/* if !handled then panic */
	beq	1b		/* if !handled then panic */
BEGIN_FTR_SECTION
	/*
	/*
	 * Return from MC interrupt.
	 * Return from MC interrupt.
	 * Queue up the MCE event so that we can log it later, while
	 * Queue up the MCE event so that we can log it later, while
@@ -618,10 +527,24 @@ EXC_COMMON_BEGIN(machine_check_handle_early)
	bl	machine_check_queue_event
	bl	machine_check_queue_event
	MACHINE_CHECK_HANDLER_WINDUP
	MACHINE_CHECK_HANDLER_WINDUP
	RFI_TO_USER_OR_KERNEL
	RFI_TO_USER_OR_KERNEL
FTR_SECTION_ELSE
	/*
	 * pSeries: Return from MC interrupt. Before that stay on emergency
	 * stack and call machine_check_exception to log the MCE event.
	 */
	LOAD_HANDLER(r10,mce_return)
	mtspr	SPRN_SRR0,r10
	ld	r10,PACAKMSR(r13)
	mtspr	SPRN_SRR1,r10
	RFI_TO_KERNEL
	b	.
ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
9:
9:
	/* Deliver the machine check to host kernel in V mode. */
	/* Deliver the machine check to host kernel in V mode. */
	MACHINE_CHECK_HANDLER_WINDUP
	MACHINE_CHECK_HANDLER_WINDUP
	b	machine_check_pSeries
	SET_SCRATCH0(r13)		/* save r13 */
	EXCEPTION_PROLOG_0(PACA_EXMC)
	b	machine_check_pSeries_0


EXC_COMMON_BEGIN(unrecover_mce)
EXC_COMMON_BEGIN(unrecover_mce)
	/* Invoke machine_check_exception to print MCE event and panic. */
	/* Invoke machine_check_exception to print MCE event and panic. */
@@ -639,29 +562,7 @@ EXC_COMMON_BEGIN(mce_return)
	/* Invoke machine_check_exception to print MCE event and return. */
	/* Invoke machine_check_exception to print MCE event and return. */
	addi	r3,r1,STACK_FRAME_OVERHEAD
	addi	r3,r1,STACK_FRAME_OVERHEAD
	bl	machine_check_exception
	bl	machine_check_exception
	ld	r9,_MSR(r1)
	MACHINE_CHECK_HANDLER_WINDUP
	mtspr	SPRN_SRR1,r9
	ld	r3,_NIP(r1)
	mtspr	SPRN_SRR0,r3
	ld	r9,_CTR(r1)
	mtctr	r9
	ld	r9,_XER(r1)
	mtxer	r9
	ld	r9,_LINK(r1)
	mtlr	r9
	REST_GPR(0, r1)
	REST_8GPRS(2, r1)
	REST_GPR(10, r1)
	ld	r11,_CCR(r1)
	mtcr	r11
	/* Decrement paca->in_mce. */
	lhz	r12,PACA_IN_MCE(r13)
	subi	r12,r12,1
	sth	r12,PACA_IN_MCE(r13)
	REST_GPR(11, r1)
	REST_2GPRS(12, r1)
	/* restore original r1. */
	ld	r1,GPR1(r1)
	RFI_TO_KERNEL
	RFI_TO_KERNEL
	b	.
	b	.