提交 fe9e1d54 编写于 作者: I Ian Munsie 提交者: Benjamin Herrenschmidt

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: NIan Munsie <imunsie@au1.ibm.com>
Signed-off-by: NBenjamin Herrenschmidt <benh@kernel.crashing.org>
上级 919ca868
...@@ -836,13 +836,22 @@ restore_check_irq_replay: ...@@ -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) ...@@ -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: \ ...@@ -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: \ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 ! */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册