powerpc: Add code to handle soft-disabled doorbells on server
authorIan Munsie <imunsie@au1.ibm.com>
Wed, 14 Nov 2012 18:49:48 +0000 (18:49 +0000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Thu, 10 Jan 2013 04:09:07 +0000 (15:09 +1100)
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>
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kernel/irq.c

index b310a05..73c1f08 100644 (file)
@@ -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:
index 176bf99..32fc04f 100644 (file)
@@ -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
 /*
index 71413f4..4f97fe3 100644 (file)
@@ -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 ! */