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: Ian Munsie <imunsie@au1.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This commit is contained in:
parent
919ca8681f
commit
fe9e1d54e3
@ -836,13 +836,22 @@ restore_check_irq_replay:
|
|||||||
addi r3,r1,STACK_FRAME_OVERHEAD;
|
addi r3,r1,STACK_FRAME_OVERHEAD;
|
||||||
bl .timer_interrupt
|
bl .timer_interrupt
|
||||||
b .ret_from_except
|
b .ret_from_except
|
||||||
|
#ifdef CONFIG_PPC_DOORBELL
|
||||||
|
1:
|
||||||
#ifdef CONFIG_PPC_BOOK3E
|
#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
|
bne 1f
|
||||||
addi r3,r1,STACK_FRAME_OVERHEAD;
|
addi r3,r1,STACK_FRAME_OVERHEAD;
|
||||||
bl .doorbell_exception
|
bl .doorbell_exception
|
||||||
b .ret_from_except
|
b .ret_from_except
|
||||||
#endif /* CONFIG_PPC_BOOK3E */
|
#endif /* CONFIG_PPC_DOORBELL */
|
||||||
1: b .ret_from_except /* What else to do here ? */
|
1: b .ret_from_except /* What else to do here ? */
|
||||||
|
|
||||||
unrecov_restore:
|
unrecov_restore:
|
||||||
|
@ -528,10 +528,12 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_206)
|
|||||||
KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf40)
|
KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf40)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* An interrupt came in while soft-disabled. We set paca->irq_happened,
|
* An interrupt came in while soft-disabled. We set paca->irq_happened, then:
|
||||||
* then, if it was a decrementer interrupt, we bump the dec to max and
|
* - If it was a decrementer interrupt, we bump the dec to max and and return.
|
||||||
* and return, else we hard disable and return. This is called with
|
* - If it was a doorbell we return immediately since doorbells are edge
|
||||||
* r10 containing the value to OR to the paca field.
|
* 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) \
|
#define MASKED_INTERRUPT(_H) \
|
||||||
masked_##_H##interrupt: \
|
masked_##_H##interrupt: \
|
||||||
@ -539,13 +541,15 @@ masked_##_H##interrupt: \
|
|||||||
lbz r11,PACAIRQHAPPENED(r13); \
|
lbz r11,PACAIRQHAPPENED(r13); \
|
||||||
or r11,r11,r10; \
|
or r11,r11,r10; \
|
||||||
stb r11,PACAIRQHAPPENED(r13); \
|
stb r11,PACAIRQHAPPENED(r13); \
|
||||||
andi. r10,r10,PACA_IRQ_DEC; \
|
cmpwi r10,PACA_IRQ_DEC; \
|
||||||
beq 1f; \
|
bne 1f; \
|
||||||
lis r10,0x7fff; \
|
lis r10,0x7fff; \
|
||||||
ori r10,r10,0xffff; \
|
ori r10,r10,0xffff; \
|
||||||
mtspr SPRN_DEC,r10; \
|
mtspr SPRN_DEC,r10; \
|
||||||
b 2f; \
|
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 */ \
|
rldicl r10,r10,48,1; /* clear MSR_EE */ \
|
||||||
rotldi r10,r10,16; \
|
rotldi r10,r10,16; \
|
||||||
mtspr SPRN_##_H##SRR1,r10; \
|
mtspr SPRN_##_H##SRR1,r10; \
|
||||||
@ -562,8 +566,8 @@ masked_##_H##interrupt: \
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Called from arch_local_irq_enable when an interrupt needs
|
* Called from arch_local_irq_enable when an interrupt needs
|
||||||
* to be resent. r3 contains 0x500 or 0x900 to indicate which
|
* to be resent. r3 contains 0x500, 0x900, 0xa00 or 0xe80 to indicate
|
||||||
* kind of interrupt. MSR:EE is already off. We generate a
|
* which kind of interrupt. MSR:EE is already off. We generate a
|
||||||
* stackframe like if a real interrupt had happened.
|
* stackframe like if a real interrupt had happened.
|
||||||
*
|
*
|
||||||
* Note: While MSR:EE is off, we need to make sure that _MSR
|
* Note: While MSR:EE is off, we need to make sure that _MSR
|
||||||
@ -579,9 +583,18 @@ _GLOBAL(__replay_interrupt)
|
|||||||
mflr r11
|
mflr r11
|
||||||
mfcr r9
|
mfcr r9
|
||||||
ori r12,r12,MSR_EE
|
ori r12,r12,MSR_EE
|
||||||
andi. r3,r3,0x0800
|
cmpwi r3,0x900
|
||||||
bne decrementer_common
|
beq decrementer_common
|
||||||
b hardware_interrupt_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
|
#ifdef CONFIG_PPC_PSERIES
|
||||||
/*
|
/*
|
||||||
|
@ -122,8 +122,8 @@ static inline notrace int decrementer_check_overflow(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* This is called whenever we are re-enabling interrupts
|
/* This is called whenever we are re-enabling interrupts
|
||||||
* and returns either 0 (nothing to do) or 500/900 if there's
|
* and returns either 0 (nothing to do) or 500/900/280/a00/e80 if
|
||||||
* either an EE or a DEC to generate.
|
* there's an EE, DEC or DBELL to generate.
|
||||||
*
|
*
|
||||||
* This is called in two contexts: From arch_local_irq_restore()
|
* This is called in two contexts: From arch_local_irq_restore()
|
||||||
* before soft-enabling interrupts, and from the exception exit
|
* 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;
|
local_paca->irq_happened &= ~PACA_IRQ_DBELL;
|
||||||
if (happened & PACA_IRQ_DBELL)
|
if (happened & PACA_IRQ_DBELL)
|
||||||
return 0x280;
|
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 */
|
#endif /* CONFIG_PPC_BOOK3E */
|
||||||
|
|
||||||
/* There should be nothing left ! */
|
/* There should be nothing left ! */
|
||||||
|
Loading…
Reference in New Issue
Block a user