aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/include/asm/exception-64s.h2
-rw-r--r--arch/powerpc/include/asm/hardirq.h1
-rw-r--r--arch/powerpc/include/asm/hw_irq.h1
-rw-r--r--arch/powerpc/include/asm/kvm_asm.h1
-rw-r--r--arch/powerpc/include/asm/machdep.h4
-rw-r--r--arch/powerpc/include/asm/opal.h2
-rw-r--r--arch/powerpc/kernel/entry_64.S5
-rw-r--r--arch/powerpc/kernel/exceptions-64s.S66
-rw-r--r--arch/powerpc/kernel/irq.c14
-rw-r--r--arch/powerpc/kernel/traps.c24
-rw-r--r--arch/powerpc/kvm/book3s_hv_rmhandlers.S6
-rw-r--r--arch/powerpc/platforms/powernv/opal.c14
-rw-r--r--arch/powerpc/platforms/powernv/setup.c2
13 files changed, 139 insertions, 3 deletions
diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h
index 13a63379e496..77f52b26dad6 100644
--- a/arch/powerpc/include/asm/exception-64s.h
+++ b/arch/powerpc/include/asm/exception-64s.h
@@ -425,6 +425,8 @@ label##_relon_hv: \
425#define SOFTEN_VALUE_0xa00 PACA_IRQ_DBELL 425#define SOFTEN_VALUE_0xa00 PACA_IRQ_DBELL
426#define SOFTEN_VALUE_0xe80 PACA_IRQ_DBELL 426#define SOFTEN_VALUE_0xe80 PACA_IRQ_DBELL
427#define SOFTEN_VALUE_0xe82 PACA_IRQ_DBELL 427#define SOFTEN_VALUE_0xe82 PACA_IRQ_DBELL
428#define SOFTEN_VALUE_0xe60 PACA_IRQ_HMI
429#define SOFTEN_VALUE_0xe62 PACA_IRQ_HMI
428 430
429#define __SOFTEN_TEST(h, vec) \ 431#define __SOFTEN_TEST(h, vec) \
430 lbz r10,PACASOFTIRQEN(r13); \ 432 lbz r10,PACASOFTIRQEN(r13); \
diff --git a/arch/powerpc/include/asm/hardirq.h b/arch/powerpc/include/asm/hardirq.h
index 418fb654370d..1bbb3013d6aa 100644
--- a/arch/powerpc/include/asm/hardirq.h
+++ b/arch/powerpc/include/asm/hardirq.h
@@ -11,6 +11,7 @@ typedef struct {
11 unsigned int pmu_irqs; 11 unsigned int pmu_irqs;
12 unsigned int mce_exceptions; 12 unsigned int mce_exceptions;
13 unsigned int spurious_irqs; 13 unsigned int spurious_irqs;
14 unsigned int hmi_exceptions;
14#ifdef CONFIG_PPC_DOORBELL 15#ifdef CONFIG_PPC_DOORBELL
15 unsigned int doorbell_irqs; 16 unsigned int doorbell_irqs;
16#endif 17#endif
diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h
index 10be1dd01c6b..b59ac27a6b7d 100644
--- a/arch/powerpc/include/asm/hw_irq.h
+++ b/arch/powerpc/include/asm/hw_irq.h
@@ -25,6 +25,7 @@
25#define PACA_IRQ_EE 0x04 25#define PACA_IRQ_EE 0x04
26#define PACA_IRQ_DEC 0x08 /* Or FIT */ 26#define PACA_IRQ_DEC 0x08 /* Or FIT */
27#define PACA_IRQ_EE_EDGE 0x10 /* BookE only */ 27#define PACA_IRQ_EE_EDGE 0x10 /* BookE only */
28#define PACA_IRQ_HMI 0x20
28 29
29#endif /* CONFIG_PPC64 */ 30#endif /* CONFIG_PPC64 */
30 31
diff --git a/arch/powerpc/include/asm/kvm_asm.h b/arch/powerpc/include/asm/kvm_asm.h
index 9601741080e5..ecf7e133a4f2 100644
--- a/arch/powerpc/include/asm/kvm_asm.h
+++ b/arch/powerpc/include/asm/kvm_asm.h
@@ -98,6 +98,7 @@
98#define BOOK3S_INTERRUPT_H_DATA_STORAGE 0xe00 98#define BOOK3S_INTERRUPT_H_DATA_STORAGE 0xe00
99#define BOOK3S_INTERRUPT_H_INST_STORAGE 0xe20 99#define BOOK3S_INTERRUPT_H_INST_STORAGE 0xe20
100#define BOOK3S_INTERRUPT_H_EMUL_ASSIST 0xe40 100#define BOOK3S_INTERRUPT_H_EMUL_ASSIST 0xe40
101#define BOOK3S_INTERRUPT_HMI 0xe60
101#define BOOK3S_INTERRUPT_H_DOORBELL 0xe80 102#define BOOK3S_INTERRUPT_H_DOORBELL 0xe80
102#define BOOK3S_INTERRUPT_PERFMON 0xf00 103#define BOOK3S_INTERRUPT_PERFMON 0xf00
103#define BOOK3S_INTERRUPT_ALTIVEC 0xf20 104#define BOOK3S_INTERRUPT_ALTIVEC 0xf20
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index 5c7e74ddee4c..44e90516519b 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -174,6 +174,10 @@ struct machdep_calls {
174 /* Exception handlers */ 174 /* Exception handlers */
175 int (*system_reset_exception)(struct pt_regs *regs); 175 int (*system_reset_exception)(struct pt_regs *regs);
176 int (*machine_check_exception)(struct pt_regs *regs); 176 int (*machine_check_exception)(struct pt_regs *regs);
177 int (*handle_hmi_exception)(struct pt_regs *regs);
178
179 /* Early exception handlers called in realmode */
180 int (*hmi_exception_early)(struct pt_regs *regs);
177 181
178 /* Called during machine check exception to retrive fixup address. */ 182 /* Called during machine check exception to retrive fixup address. */
179 bool (*mce_check_early_recovery)(struct pt_regs *regs); 183 bool (*mce_check_early_recovery)(struct pt_regs *regs);
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 7f5fd5396261..efc16c37b959 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -915,6 +915,8 @@ extern void opal_msglog_init(void);
915 915
916extern int opal_machine_check(struct pt_regs *regs); 916extern int opal_machine_check(struct pt_regs *regs);
917extern bool opal_mce_check_early_recovery(struct pt_regs *regs); 917extern bool opal_mce_check_early_recovery(struct pt_regs *regs);
918extern int opal_hmi_exception_early(struct pt_regs *regs);
919extern int opal_handle_hmi_exception(struct pt_regs *regs);
918 920
919extern void opal_shutdown(void); 921extern void opal_shutdown(void);
920extern int opal_resync_timebase(void); 922extern int opal_resync_timebase(void);
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index d6b22e8c8ee1..5bbd1bc8c3b0 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -915,6 +915,11 @@ restore_check_irq_replay:
915 addi r3,r1,STACK_FRAME_OVERHEAD; 915 addi r3,r1,STACK_FRAME_OVERHEAD;
916 bl do_IRQ 916 bl do_IRQ
917 b ret_from_except 917 b ret_from_except
9181: cmpwi cr0,r3,0xe60
919 bne 1f
920 addi r3,r1,STACK_FRAME_OVERHEAD;
921 bl handle_hmi_exception
922 b ret_from_except
9181: cmpwi cr0,r3,0x900 9231: cmpwi cr0,r3,0x900
919 bne 1f 924 bne 1f
920 addi r3,r1,STACK_FRAME_OVERHEAD; 925 addi r3,r1,STACK_FRAME_OVERHEAD;
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index f521b2dac051..6144d5a6bfe7 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -335,7 +335,7 @@ emulation_assist_trampoline:
335hv_exception_trampoline: 335hv_exception_trampoline:
336 SET_SCRATCH0(r13) 336 SET_SCRATCH0(r13)
337 EXCEPTION_PROLOG_0(PACA_EXGEN) 337 EXCEPTION_PROLOG_0(PACA_EXGEN)
338 b hmi_exception_hv 338 b hmi_exception_early
339 339
340 . = 0xe80 340 . = 0xe80
341hv_doorbell_trampoline: 341hv_doorbell_trampoline:
@@ -589,8 +589,64 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
589 KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe22) 589 KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe22)
590 STD_EXCEPTION_HV_OOL(0xe42, emulation_assist) 590 STD_EXCEPTION_HV_OOL(0xe42, emulation_assist)
591 KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe42) 591 KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe42)
592 STD_EXCEPTION_HV_OOL(0xe62, hmi_exception) /* need to flush cache ? */ 592 MASKABLE_EXCEPTION_HV_OOL(0xe62, hmi_exception)
593 KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe62) 593 KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe62)
594
595 .globl hmi_exception_early
596hmi_exception_early:
597 EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0xe60)
598 mr r10,r1 /* Save r1 */
599 ld r1,PACAEMERGSP(r13) /* Use emergency stack */
600 subi r1,r1,INT_FRAME_SIZE /* alloc stack frame */
601 std r9,_CCR(r1) /* save CR in stackframe */
602 mfspr r11,SPRN_HSRR0 /* Save HSRR0 */
603 std r11,_NIP(r1) /* save HSRR0 in stackframe */
604 mfspr r12,SPRN_HSRR1 /* Save SRR1 */
605 std r12,_MSR(r1) /* save SRR1 in stackframe */
606 std r10,0(r1) /* make stack chain pointer */
607 std r0,GPR0(r1) /* save r0 in stackframe */
608 std r10,GPR1(r1) /* save r1 in stackframe */
609 EXCEPTION_PROLOG_COMMON_2(PACA_EXGEN)
610 EXCEPTION_PROLOG_COMMON_3(0xe60)
611 addi r3,r1,STACK_FRAME_OVERHEAD
612 bl hmi_exception_realmode
613 /* Windup the stack. */
614 /* Clear MSR_RI before setting SRR0 and SRR1. */
615 li r0,MSR_RI
616 mfmsr r9 /* get MSR value */
617 andc r9,r9,r0
618 mtmsrd r9,1 /* Clear MSR_RI */
619 /* Move original HSRR0 and HSRR1 into the respective regs */
620 ld r9,_MSR(r1)
621 mtspr SPRN_HSRR1,r9
622 ld r3,_NIP(r1)
623 mtspr SPRN_HSRR0,r3
624 ld r9,_CTR(r1)
625 mtctr r9
626 ld r9,_XER(r1)
627 mtxer r9
628 ld r9,_LINK(r1)
629 mtlr r9
630 REST_GPR(0, r1)
631 REST_8GPRS(2, r1)
632 REST_GPR(10, r1)
633 ld r11,_CCR(r1)
634 mtcr r11
635 REST_GPR(11, r1)
636 REST_2GPRS(12, r1)
637 /* restore original r1. */
638 ld r1,GPR1(r1)
639
640 /*
641 * Go to virtual mode and pull the HMI event information from
642 * firmware.
643 */
644 .globl hmi_exception_after_realmode
645hmi_exception_after_realmode:
646 SET_SCRATCH0(r13)
647 EXCEPTION_PROLOG_0(PACA_EXGEN)
648 b hmi_exception_hv
649
594 MASKABLE_EXCEPTION_HV_OOL(0xe82, h_doorbell) 650 MASKABLE_EXCEPTION_HV_OOL(0xe82, h_doorbell)
595 KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe82) 651 KVM_HANDLER(PACA_EXGEN, EXC_HV, 0xe82)
596 652
@@ -611,6 +667,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
611 * - If it was a decrementer interrupt, we bump the dec to max and and return. 667 * - If it was a decrementer interrupt, we bump the dec to max and and return.
612 * - If it was a doorbell we return immediately since doorbells are edge 668 * - If it was a doorbell we return immediately since doorbells are edge
613 * triggered and won't automatically refire. 669 * triggered and won't automatically refire.
670 * - If it was a HMI we return immediately since we handled it in realmode
671 * and it won't refire.
614 * - else we hard disable and return. 672 * - else we hard disable and return.
615 * This is called with r10 containing the value to OR to the paca field. 673 * This is called with r10 containing the value to OR to the paca field.
616 */ 674 */
@@ -628,6 +686,8 @@ masked_##_H##interrupt: \
628 b 2f; \ 686 b 2f; \
6291: cmpwi r10,PACA_IRQ_DBELL; \ 6871: cmpwi r10,PACA_IRQ_DBELL; \
630 beq 2f; \ 688 beq 2f; \
689 cmpwi r10,PACA_IRQ_HMI; \
690 beq 2f; \
631 mfspr r10,SPRN_##_H##SRR1; \ 691 mfspr r10,SPRN_##_H##SRR1; \
632 rldicl r10,r10,48,1; /* clear MSR_EE */ \ 692 rldicl r10,r10,48,1; /* clear MSR_EE */ \
633 rotldi r10,r10,16; \ 693 rotldi r10,r10,16; \
@@ -767,7 +827,7 @@ kvmppc_skip_Hinterrupt:
767 STD_EXCEPTION_COMMON(0xd00, single_step, single_step_exception) 827 STD_EXCEPTION_COMMON(0xd00, single_step, single_step_exception)
768 STD_EXCEPTION_COMMON(0xe00, trap_0e, unknown_exception) 828 STD_EXCEPTION_COMMON(0xe00, trap_0e, unknown_exception)
769 STD_EXCEPTION_COMMON(0xe40, emulation_assist, emulation_assist_interrupt) 829 STD_EXCEPTION_COMMON(0xe40, emulation_assist, emulation_assist_interrupt)
770 STD_EXCEPTION_COMMON(0xe60, hmi_exception, unknown_exception) 830 STD_EXCEPTION_COMMON_ASYNC(0xe60, hmi_exception, handle_hmi_exception)
771#ifdef CONFIG_PPC_DOORBELL 831#ifdef CONFIG_PPC_DOORBELL
772 STD_EXCEPTION_COMMON_ASYNC(0xe80, h_doorbell, doorbell_exception) 832 STD_EXCEPTION_COMMON_ASYNC(0xe80, h_doorbell, doorbell_exception)
773#else 833#else
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 248ee7e5bebd..4c5891de162e 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -189,6 +189,11 @@ notrace unsigned int __check_irq_replay(void)
189 } 189 }
190#endif /* CONFIG_PPC_BOOK3E */ 190#endif /* CONFIG_PPC_BOOK3E */
191 191
192 /* Check if an hypervisor Maintenance interrupt happened */
193 local_paca->irq_happened &= ~PACA_IRQ_HMI;
194 if (happened & PACA_IRQ_HMI)
195 return 0xe60;
196
192 /* There should be nothing left ! */ 197 /* There should be nothing left ! */
193 BUG_ON(local_paca->irq_happened != 0); 198 BUG_ON(local_paca->irq_happened != 0);
194 199
@@ -377,6 +382,14 @@ int arch_show_interrupts(struct seq_file *p, int prec)
377 seq_printf(p, "%10u ", per_cpu(irq_stat, j).mce_exceptions); 382 seq_printf(p, "%10u ", per_cpu(irq_stat, j).mce_exceptions);
378 seq_printf(p, " Machine check exceptions\n"); 383 seq_printf(p, " Machine check exceptions\n");
379 384
385 if (cpu_has_feature(CPU_FTR_HVMODE)) {
386 seq_printf(p, "%*s: ", prec, "HMI");
387 for_each_online_cpu(j)
388 seq_printf(p, "%10u ",
389 per_cpu(irq_stat, j).hmi_exceptions);
390 seq_printf(p, " Hypervisor Maintenance Interrupts\n");
391 }
392
380#ifdef CONFIG_PPC_DOORBELL 393#ifdef CONFIG_PPC_DOORBELL
381 if (cpu_has_feature(CPU_FTR_DBELL)) { 394 if (cpu_has_feature(CPU_FTR_DBELL)) {
382 seq_printf(p, "%*s: ", prec, "DBL"); 395 seq_printf(p, "%*s: ", prec, "DBL");
@@ -400,6 +413,7 @@ u64 arch_irq_stat_cpu(unsigned int cpu)
400 sum += per_cpu(irq_stat, cpu).mce_exceptions; 413 sum += per_cpu(irq_stat, cpu).mce_exceptions;
401 sum += per_cpu(irq_stat, cpu).spurious_irqs; 414 sum += per_cpu(irq_stat, cpu).spurious_irqs;
402 sum += per_cpu(irq_stat, cpu).timer_irqs_others; 415 sum += per_cpu(irq_stat, cpu).timer_irqs_others;
416 sum += per_cpu(irq_stat, cpu).hmi_exceptions;
403#ifdef CONFIG_PPC_DOORBELL 417#ifdef CONFIG_PPC_DOORBELL
404 sum += per_cpu(irq_stat, cpu).doorbell_irqs; 418 sum += per_cpu(irq_stat, cpu).doorbell_irqs;
405#endif 419#endif
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index cb9cfe448ee8..0dc43f9932cf 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -302,6 +302,16 @@ long machine_check_early(struct pt_regs *regs)
302 return handled; 302 return handled;
303} 303}
304 304
305long hmi_exception_realmode(struct pt_regs *regs)
306{
307 __get_cpu_var(irq_stat).hmi_exceptions++;
308
309 if (ppc_md.hmi_exception_early)
310 ppc_md.hmi_exception_early(regs);
311
312 return 0;
313}
314
305#endif 315#endif
306 316
307/* 317/*
@@ -738,6 +748,20 @@ void SMIException(struct pt_regs *regs)
738 die("System Management Interrupt", regs, SIGABRT); 748 die("System Management Interrupt", regs, SIGABRT);
739} 749}
740 750
751void handle_hmi_exception(struct pt_regs *regs)
752{
753 struct pt_regs *old_regs;
754
755 old_regs = set_irq_regs(regs);
756 irq_enter();
757
758 if (ppc_md.handle_hmi_exception)
759 ppc_md.handle_hmi_exception(regs);
760
761 irq_exit();
762 set_irq_regs(old_regs);
763}
764
741void unknown_exception(struct pt_regs *regs) 765void unknown_exception(struct pt_regs *regs)
742{ 766{
743 enum ctx_state prev_state = exception_enter(); 767 enum ctx_state prev_state = exception_enter();
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index 868347ef09fd..0de9309b9a55 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -159,6 +159,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
159 cmpwi r12, BOOK3S_INTERRUPT_EXTERNAL 159 cmpwi r12, BOOK3S_INTERRUPT_EXTERNAL
160BEGIN_FTR_SECTION 160BEGIN_FTR_SECTION
161 beq 11f 161 beq 11f
162 cmpwi cr2, r12, BOOK3S_INTERRUPT_HMI
163 beq cr2, 14f /* HMI check */
162END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) 164END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
163 165
164 /* RFI into the highmem handler, or branch to interrupt handler */ 166 /* RFI into the highmem handler, or branch to interrupt handler */
@@ -179,6 +181,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
179 181
18013: b machine_check_fwnmi 18213: b machine_check_fwnmi
181 183
18414: mtspr SPRN_HSRR0, r8
185 mtspr SPRN_HSRR1, r7
186 b hmi_exception_after_realmode
187
182kvmppc_primary_no_guest: 188kvmppc_primary_no_guest:
183 /* We handle this much like a ceded vcpu */ 189 /* We handle this much like a ceded vcpu */
184 /* set our bit in napping_threads */ 190 /* set our bit in napping_threads */
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 6ef2e5c5bc64..d20d69921376 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -514,6 +514,20 @@ int opal_machine_check(struct pt_regs *regs)
514 return 0; 514 return 0;
515} 515}
516 516
517/* Early hmi handler called in real mode. */
518int opal_hmi_exception_early(struct pt_regs *regs)
519{
520 /* TODO: Call opal hmi handler. */
521 return 0;
522}
523
524/* HMI exception handler called in virtual mode during check_irq_replay. */
525int opal_handle_hmi_exception(struct pt_regs *regs)
526{
527 /* TODO: Retrive and print HMI event from OPAL. */
528 return 0;
529}
530
517static uint64_t find_recovery_address(uint64_t nip) 531static uint64_t find_recovery_address(uint64_t nip)
518{ 532{
519 int i; 533 int i;
diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c
index d9b88fa7c5a3..5a0e2dc6de5f 100644
--- a/arch/powerpc/platforms/powernv/setup.c
+++ b/arch/powerpc/platforms/powernv/setup.c
@@ -264,6 +264,8 @@ static void __init pnv_setup_machdep_opal(void)
264 ppc_md.halt = pnv_halt; 264 ppc_md.halt = pnv_halt;
265 ppc_md.machine_check_exception = opal_machine_check; 265 ppc_md.machine_check_exception = opal_machine_check;
266 ppc_md.mce_check_early_recovery = opal_mce_check_early_recovery; 266 ppc_md.mce_check_early_recovery = opal_mce_check_early_recovery;
267 ppc_md.hmi_exception_early = opal_hmi_exception_early;
268 ppc_md.handle_hmi_exception = opal_handle_hmi_exception;
267} 269}
268 270
269#ifdef CONFIG_PPC_POWERNV_RTAS 271#ifdef CONFIG_PPC_POWERNV_RTAS