diff options
author | Ian Munsie <imunsie@au1.ibm.com> | 2012-11-14 13:49:48 -0500 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2013-01-09 23:09:07 -0500 |
commit | fe9e1d54e3ea2e5134d7aaa233441f9229326ef6 (patch) | |
tree | b8347ea44bef6ad8c8a615a26a9a8124745f50f3 /arch/powerpc/kernel | |
parent | 919ca8681f48ce81848c76f0ed66edb1bb99209b (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.S | 13 | ||||
-rw-r--r-- | arch/powerpc/kernel/exceptions-64s.S | 37 | ||||
-rw-r--r-- | arch/powerpc/kernel/irq.c | 11 |
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 | ||
840 | 1: | ||
839 | #ifdef CONFIG_PPC_BOOK3E | 841 | #ifdef CONFIG_PPC_BOOK3E |
840 | 1: 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 */ |
846 | 1: b .ret_from_except /* What else to do here ? */ | 855 | 1: b .ret_from_except /* What else to do here ? */ |
847 | 856 | ||
848 | unrecov_restore: | 857 | unrecov_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) \ |
537 | masked_##_H##interrupt: \ | 539 | masked_##_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; \ |
548 | 1: mfspr r10,SPRN_##_H##SRR1; \ | 550 | 1: 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 | ||
590 | BEGIN_FTR_SECTION | ||
591 | cmpwi r3,0xe80 | ||
592 | beq h_doorbell_common | ||
593 | FTR_SECTION_ELSE | ||
594 | cmpwi r3,0xa00 | ||
595 | beq doorbell_super_common | ||
596 | ALT_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 ! */ |