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

Commit fe9e1d54 authored by Ian Munsie's avatar Ian Munsie Committed by Benjamin Herrenschmidt
Browse files

powerpc: Add code to handle soft-disabled doorbells on server



This patch adds the logic to properly handle doorbells that come in when
interrupts have been soft disabled and to replay them when interrupts
are re-enabled:

- masked_##_H##interrupt is modified to leave interrupts enabled when a
  doorbell has come in since doorbells are edge sensitive and as such
  won't be automatically re-raised.

- __check_irq_replay now tests if a doorbell happened on book3s, and
  returns either 0xe80 or 0xa00 depending on whether we are the
  hypervisor or not.

- restore_check_irq_replay now tests for the two possible server
  doorbell vector numbers to replay.

- __replay_interrupt also adds tests for the two server doorbell vector
  numbers, and is modified to use a compare instruction rather than an
  andi. on the single bit difference between 0x500 and 0x900.

The last two use a CPU feature section to avoid needlessly testing
against the hypervisor vector if it is not the hypervisor, and vice
versa.

Signed-off-by: default avatarIan Munsie <imunsie@au1.ibm.com>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent 919ca868
Loading
Loading
Loading
Loading
+11 −2
Original line number Diff line number Diff line
@@ -836,13 +836,22 @@ restore_check_irq_replay:
	addi	r3,r1,STACK_FRAME_OVERHEAD;
	bl	.timer_interrupt
	b	.ret_from_except
#ifdef CONFIG_PPC_DOORBELL
1:
#ifdef CONFIG_PPC_BOOK3E
1:	cmpwi	cr0,r3,0x280
	cmpwi	cr0,r3,0x280
#else
	BEGIN_FTR_SECTION
		cmpwi	cr0,r3,0xe80
	FTR_SECTION_ELSE
		cmpwi	cr0,r3,0xa00
	ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
#endif /* CONFIG_PPC_BOOK3E */
	bne	1f
	addi	r3,r1,STACK_FRAME_OVERHEAD;
	bl	.doorbell_exception
	b	.ret_from_except
#endif /* CONFIG_PPC_BOOK3E */
#endif /* CONFIG_PPC_DOORBELL */
1:	b	.ret_from_except /* What else to do here ? */
 
unrecov_restore:
+25 −12
Original line number Diff line number Diff line
@@ -528,10 +528,12 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_206)
	KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf40)

/*
 * An interrupt came in while soft-disabled. We set paca->irq_happened,
 * then, if it was a decrementer interrupt, we bump the dec to max and
 * and return, else we hard disable and return. This is called with
 * r10 containing the value to OR to the paca field.
 * An interrupt came in while soft-disabled. We set paca->irq_happened, then:
 * - If it was a decrementer interrupt, we bump the dec to max and and return.
 * - If it was a doorbell we return immediately since doorbells are edge
 *   triggered and won't automatically refire.
 * - else we hard disable and return.
 * This is called with r10 containing the value to OR to the paca field.
 */
#define MASKED_INTERRUPT(_H)				\
masked_##_H##interrupt:					\
@@ -539,13 +541,15 @@ masked_##_H##interrupt: \
	lbz	r11,PACAIRQHAPPENED(r13);		\
	or	r11,r11,r10;				\
	stb	r11,PACAIRQHAPPENED(r13);		\
	andi.	r10,r10,PACA_IRQ_DEC;			\
	beq	1f;					\
	cmpwi	r10,PACA_IRQ_DEC;			\
	bne	1f;					\
	lis	r10,0x7fff;				\
	ori	r10,r10,0xffff;				\
	mtspr	SPRN_DEC,r10;				\
	b	2f;					\
1:	mfspr	r10,SPRN_##_H##SRR1;			\
1:	cmpwi	r10,PACA_IRQ_DBELL;			\
	beq	2f;					\
	mfspr	r10,SPRN_##_H##SRR1;			\
	rldicl	r10,r10,48,1; /* clear MSR_EE */	\
	rotldi	r10,r10,16;				\
	mtspr	SPRN_##_H##SRR1,r10;			\
@@ -562,8 +566,8 @@ masked_##_H##interrupt: \

/*
 * Called from arch_local_irq_enable when an interrupt needs
 * to be resent. r3 contains 0x500 or 0x900 to indicate which
 * kind of interrupt. MSR:EE is already off. We generate a
 * to be resent. r3 contains 0x500, 0x900, 0xa00 or 0xe80 to indicate
 * which kind of interrupt. MSR:EE is already off. We generate a
 * stackframe like if a real interrupt had happened.
 *
 * Note: While MSR:EE is off, we need to make sure that _MSR
@@ -579,9 +583,18 @@ _GLOBAL(__replay_interrupt)
	mflr	r11
	mfcr	r9
	ori	r12,r12,MSR_EE
	andi.	r3,r3,0x0800
	bne	decrementer_common
	b	hardware_interrupt_common
	cmpwi	r3,0x900
	beq	decrementer_common
	cmpwi	r3,0x500
	beq	hardware_interrupt_common
BEGIN_FTR_SECTION
	cmpwi	r3,0xe80
	beq	h_doorbell_common
FTR_SECTION_ELSE
	cmpwi	r3,0xa00
	beq	doorbell_super_common
ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
	blr

#ifdef CONFIG_PPC_PSERIES
/*
+9 −2
Original line number Diff line number Diff line
@@ -122,8 +122,8 @@ static inline notrace int decrementer_check_overflow(void)
}

/* This is called whenever we are re-enabling interrupts
 * and returns either 0 (nothing to do) or 500/900 if there's
 * either an EE or a DEC to generate.
 * and returns either 0 (nothing to do) or 500/900/280/a00/e80 if
 * there's an EE, DEC or DBELL to generate.
 *
 * This is called in two contexts: From arch_local_irq_restore()
 * before soft-enabling interrupts, and from the exception exit
@@ -182,6 +182,13 @@ notrace unsigned int __check_irq_replay(void)
	local_paca->irq_happened &= ~PACA_IRQ_DBELL;
	if (happened & PACA_IRQ_DBELL)
		return 0x280;
#else
	local_paca->irq_happened &= ~PACA_IRQ_DBELL;
	if (happened & PACA_IRQ_DBELL) {
		if (cpu_has_feature(CPU_FTR_HVMODE))
			return 0xe80;
		return 0xa00;
	}
#endif /* CONFIG_PPC_BOOK3E */

	/* There should be nothing left ! */