aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
authorIan Munsie <imunsie@au1.ibm.com>2012-11-14 13:49:48 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-01-09 23:09:07 -0500
commitfe9e1d54e3ea2e5134d7aaa233441f9229326ef6 (patch)
treeb8347ea44bef6ad8c8a615a26a9a8124745f50f3 /arch/powerpc/kernel
parent919ca8681f48ce81848c76f0ed66edb1bb99209b (diff)
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>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r--arch/powerpc/kernel/entry_64.S13
-rw-r--r--arch/powerpc/kernel/exceptions-64s.S37
-rw-r--r--arch/powerpc/kernel/irq.c11
3 files changed, 45 insertions, 16 deletions
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index b310a0573625..73c1f083ba21 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -836,13 +836,22 @@ restore_check_irq_replay:
836 addi r3,r1,STACK_FRAME_OVERHEAD; 836 addi r3,r1,STACK_FRAME_OVERHEAD;
837 bl .timer_interrupt 837 bl .timer_interrupt
838 b .ret_from_except 838 b .ret_from_except
839#ifdef CONFIG_PPC_DOORBELL
8401:
839#ifdef CONFIG_PPC_BOOK3E 841#ifdef CONFIG_PPC_BOOK3E
8401: cmpwi cr0,r3,0x280 842 cmpwi cr0,r3,0x280
843#else
844 BEGIN_FTR_SECTION
845 cmpwi cr0,r3,0xe80
846 FTR_SECTION_ELSE
847 cmpwi cr0,r3,0xa00
848 ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
849#endif /* CONFIG_PPC_BOOK3E */
841 bne 1f 850 bne 1f
842 addi r3,r1,STACK_FRAME_OVERHEAD; 851 addi r3,r1,STACK_FRAME_OVERHEAD;
843 bl .doorbell_exception 852 bl .doorbell_exception
844 b .ret_from_except 853 b .ret_from_except
845#endif /* CONFIG_PPC_BOOK3E */ 854#endif /* CONFIG_PPC_DOORBELL */
8461: b .ret_from_except /* What else to do here ? */ 8551: b .ret_from_except /* What else to do here ? */
847 856
848unrecov_restore: 857unrecov_restore:
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 176bf99e01c6..32fc04f78890 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -528,10 +528,12 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_206)
528 KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf40) 528 KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf40)
529 529
530/* 530/*
531 * An interrupt came in while soft-disabled. We set paca->irq_happened, 531 * An interrupt came in while soft-disabled. We set paca->irq_happened, then:
532 * then, if it was a decrementer interrupt, we bump the dec to max and 532 * - If it was a decrementer interrupt, we bump the dec to max and and return.
533 * and return, else we hard disable and return. This is called with 533 * - If it was a doorbell we return immediately since doorbells are edge
534 * r10 containing the value to OR to the paca field. 534 * triggered and won't automatically refire.
535 * - else we hard disable and return.
536 * This is called with r10 containing the value to OR to the paca field.
535 */ 537 */
536#define MASKED_INTERRUPT(_H) \ 538#define MASKED_INTERRUPT(_H) \
537masked_##_H##interrupt: \ 539masked_##_H##interrupt: \
@@ -539,13 +541,15 @@ masked_##_H##interrupt: \
539 lbz r11,PACAIRQHAPPENED(r13); \ 541 lbz r11,PACAIRQHAPPENED(r13); \
540 or r11,r11,r10; \ 542 or r11,r11,r10; \
541 stb r11,PACAIRQHAPPENED(r13); \ 543 stb r11,PACAIRQHAPPENED(r13); \
542 andi. r10,r10,PACA_IRQ_DEC; \ 544 cmpwi r10,PACA_IRQ_DEC; \
543 beq 1f; \ 545 bne 1f; \
544 lis r10,0x7fff; \ 546 lis r10,0x7fff; \
545 ori r10,r10,0xffff; \ 547 ori r10,r10,0xffff; \
546 mtspr SPRN_DEC,r10; \ 548 mtspr SPRN_DEC,r10; \
547 b 2f; \ 549 b 2f; \
5481: mfspr r10,SPRN_##_H##SRR1; \ 5501: cmpwi r10,PACA_IRQ_DBELL; \
551 beq 2f; \
552 mfspr r10,SPRN_##_H##SRR1; \
549 rldicl r10,r10,48,1; /* clear MSR_EE */ \ 553 rldicl r10,r10,48,1; /* clear MSR_EE */ \
550 rotldi r10,r10,16; \ 554 rotldi r10,r10,16; \
551 mtspr SPRN_##_H##SRR1,r10; \ 555 mtspr SPRN_##_H##SRR1,r10; \
@@ -562,8 +566,8 @@ masked_##_H##interrupt: \
562 566
563/* 567/*
564 * Called from arch_local_irq_enable when an interrupt needs 568 * Called from arch_local_irq_enable when an interrupt needs
565 * to be resent. r3 contains 0x500 or 0x900 to indicate which 569 * to be resent. r3 contains 0x500, 0x900, 0xa00 or 0xe80 to indicate
566 * kind of interrupt. MSR:EE is already off. We generate a 570 * which kind of interrupt. MSR:EE is already off. We generate a
567 * stackframe like if a real interrupt had happened. 571 * stackframe like if a real interrupt had happened.
568 * 572 *
569 * Note: While MSR:EE is off, we need to make sure that _MSR 573 * Note: While MSR:EE is off, we need to make sure that _MSR
@@ -579,9 +583,18 @@ _GLOBAL(__replay_interrupt)
579 mflr r11 583 mflr r11
580 mfcr r9 584 mfcr r9
581 ori r12,r12,MSR_EE 585 ori r12,r12,MSR_EE
582 andi. r3,r3,0x0800 586 cmpwi r3,0x900
583 bne decrementer_common 587 beq decrementer_common
584 b hardware_interrupt_common 588 cmpwi r3,0x500
589 beq hardware_interrupt_common
590BEGIN_FTR_SECTION
591 cmpwi r3,0xe80
592 beq h_doorbell_common
593FTR_SECTION_ELSE
594 cmpwi r3,0xa00
595 beq doorbell_super_common
596ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
597 blr
585 598
586#ifdef CONFIG_PPC_PSERIES 599#ifdef CONFIG_PPC_PSERIES
587/* 600/*
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 71413f41278f..4f97fe345526 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -122,8 +122,8 @@ static inline notrace int decrementer_check_overflow(void)
122} 122}
123 123
124/* This is called whenever we are re-enabling interrupts 124/* This is called whenever we are re-enabling interrupts
125 * and returns either 0 (nothing to do) or 500/900 if there's 125 * and returns either 0 (nothing to do) or 500/900/280/a00/e80 if
126 * either an EE or a DEC to generate. 126 * there's an EE, DEC or DBELL to generate.
127 * 127 *
128 * This is called in two contexts: From arch_local_irq_restore() 128 * This is called in two contexts: From arch_local_irq_restore()
129 * before soft-enabling interrupts, and from the exception exit 129 * before soft-enabling interrupts, and from the exception exit
@@ -182,6 +182,13 @@ notrace unsigned int __check_irq_replay(void)
182 local_paca->irq_happened &= ~PACA_IRQ_DBELL; 182 local_paca->irq_happened &= ~PACA_IRQ_DBELL;
183 if (happened & PACA_IRQ_DBELL) 183 if (happened & PACA_IRQ_DBELL)
184 return 0x280; 184 return 0x280;
185#else
186 local_paca->irq_happened &= ~PACA_IRQ_DBELL;
187 if (happened & PACA_IRQ_DBELL) {
188 if (cpu_has_feature(CPU_FTR_HVMODE))
189 return 0xe80;
190 return 0xa00;
191 }
185#endif /* CONFIG_PPC_BOOK3E */ 192#endif /* CONFIG_PPC_BOOK3E */
186 193
187 /* There should be nothing left ! */ 194 /* There should be nothing left ! */