diff options
Diffstat (limited to 'arch/powerpc/kvm')
-rw-r--r-- | arch/powerpc/kvm/book3s_hv_ras.c | 50 | ||||
-rw-r--r-- | arch/powerpc/kvm/bookehv_interrupts.S | 2 |
2 files changed, 26 insertions, 26 deletions
diff --git a/arch/powerpc/kvm/book3s_hv_ras.c b/arch/powerpc/kvm/book3s_hv_ras.c index a353c485808c..768a9f977c00 100644 --- a/arch/powerpc/kvm/book3s_hv_ras.c +++ b/arch/powerpc/kvm/book3s_hv_ras.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/kvm_host.h> | 12 | #include <linux/kvm_host.h> |
13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
14 | #include <asm/opal.h> | 14 | #include <asm/opal.h> |
15 | #include <asm/mce.h> | ||
15 | 16 | ||
16 | /* SRR1 bits for machine check on POWER7 */ | 17 | /* SRR1 bits for machine check on POWER7 */ |
17 | #define SRR1_MC_LDSTERR (1ul << (63-42)) | 18 | #define SRR1_MC_LDSTERR (1ul << (63-42)) |
@@ -58,18 +59,6 @@ static void reload_slb(struct kvm_vcpu *vcpu) | |||
58 | } | 59 | } |
59 | } | 60 | } |
60 | 61 | ||
61 | /* POWER7 TLB flush */ | ||
62 | static void flush_tlb_power7(struct kvm_vcpu *vcpu) | ||
63 | { | ||
64 | unsigned long i, rb; | ||
65 | |||
66 | rb = TLBIEL_INVAL_SET_LPID; | ||
67 | for (i = 0; i < POWER7_TLB_SETS; ++i) { | ||
68 | asm volatile("tlbiel %0" : : "r" (rb)); | ||
69 | rb += 1 << TLBIEL_INVAL_SET_SHIFT; | ||
70 | } | ||
71 | } | ||
72 | |||
73 | /* | 62 | /* |
74 | * On POWER7, see if we can handle a machine check that occurred inside | 63 | * On POWER7, see if we can handle a machine check that occurred inside |
75 | * the guest in real mode, without switching to the host partition. | 64 | * the guest in real mode, without switching to the host partition. |
@@ -79,9 +68,7 @@ static void flush_tlb_power7(struct kvm_vcpu *vcpu) | |||
79 | static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu) | 68 | static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu) |
80 | { | 69 | { |
81 | unsigned long srr1 = vcpu->arch.shregs.msr; | 70 | unsigned long srr1 = vcpu->arch.shregs.msr; |
82 | #ifdef CONFIG_PPC_POWERNV | 71 | struct machine_check_event mce_evt; |
83 | struct opal_machine_check_event *opal_evt; | ||
84 | #endif | ||
85 | long handled = 1; | 72 | long handled = 1; |
86 | 73 | ||
87 | if (srr1 & SRR1_MC_LDSTERR) { | 74 | if (srr1 & SRR1_MC_LDSTERR) { |
@@ -96,7 +83,8 @@ static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu) | |||
96 | DSISR_MC_SLB_PARITY | DSISR_MC_DERAT_MULTI); | 83 | DSISR_MC_SLB_PARITY | DSISR_MC_DERAT_MULTI); |
97 | } | 84 | } |
98 | if (dsisr & DSISR_MC_TLB_MULTI) { | 85 | if (dsisr & DSISR_MC_TLB_MULTI) { |
99 | flush_tlb_power7(vcpu); | 86 | if (cur_cpu_spec && cur_cpu_spec->flush_tlb) |
87 | cur_cpu_spec->flush_tlb(TLBIEL_INVAL_SET_LPID); | ||
100 | dsisr &= ~DSISR_MC_TLB_MULTI; | 88 | dsisr &= ~DSISR_MC_TLB_MULTI; |
101 | } | 89 | } |
102 | /* Any other errors we don't understand? */ | 90 | /* Any other errors we don't understand? */ |
@@ -113,28 +101,38 @@ static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu) | |||
113 | reload_slb(vcpu); | 101 | reload_slb(vcpu); |
114 | break; | 102 | break; |
115 | case SRR1_MC_IFETCH_TLBMULTI: | 103 | case SRR1_MC_IFETCH_TLBMULTI: |
116 | flush_tlb_power7(vcpu); | 104 | if (cur_cpu_spec && cur_cpu_spec->flush_tlb) |
105 | cur_cpu_spec->flush_tlb(TLBIEL_INVAL_SET_LPID); | ||
117 | break; | 106 | break; |
118 | default: | 107 | default: |
119 | handled = 0; | 108 | handled = 0; |
120 | } | 109 | } |
121 | 110 | ||
122 | #ifdef CONFIG_PPC_POWERNV | ||
123 | /* | 111 | /* |
124 | * See if OPAL has already handled the condition. | 112 | * See if we have already handled the condition in the linux host. |
125 | * We assume that if the condition is recovered then OPAL | 113 | * We assume that if the condition is recovered then linux host |
126 | * will have generated an error log event that we will pick | 114 | * will have generated an error log event that we will pick |
127 | * up and log later. | 115 | * up and log later. |
116 | * Don't release mce event now. In case if condition is not | ||
117 | * recovered we do guest exit and go back to linux host machine | ||
118 | * check handler. Hence we need make sure that current mce event | ||
119 | * is available for linux host to consume. | ||
128 | */ | 120 | */ |
129 | opal_evt = local_paca->opal_mc_evt; | 121 | if (!get_mce_event(&mce_evt, MCE_EVENT_DONTRELEASE)) |
130 | if (opal_evt->version == OpalMCE_V1 && | 122 | goto out; |
131 | (opal_evt->severity == OpalMCE_SEV_NO_ERROR || | 123 | |
132 | opal_evt->disposition == OpalMCE_DISPOSITION_RECOVERED)) | 124 | if (mce_evt.version == MCE_V1 && |
125 | (mce_evt.severity == MCE_SEV_NO_ERROR || | ||
126 | mce_evt.disposition == MCE_DISPOSITION_RECOVERED)) | ||
133 | handled = 1; | 127 | handled = 1; |
134 | 128 | ||
129 | out: | ||
130 | /* | ||
131 | * If we have handled the error, then release the mce event because | ||
132 | * we will be delivering machine check to guest. | ||
133 | */ | ||
135 | if (handled) | 134 | if (handled) |
136 | opal_evt->in_use = 0; | 135 | release_mce_event(); |
137 | #endif | ||
138 | 136 | ||
139 | return handled; | 137 | return handled; |
140 | } | 138 | } |
diff --git a/arch/powerpc/kvm/bookehv_interrupts.S b/arch/powerpc/kvm/bookehv_interrupts.S index be3de1dd7bb3..e4185f6b3309 100644 --- a/arch/powerpc/kvm/bookehv_interrupts.S +++ b/arch/powerpc/kvm/bookehv_interrupts.S | |||
@@ -321,6 +321,8 @@ kvm_handler BOOKE_INTERRUPT_DEBUG, EX_PARAMS(DBG), \ | |||
321 | SPRN_DSRR0, SPRN_DSRR1, 0 | 321 | SPRN_DSRR0, SPRN_DSRR1, 0 |
322 | kvm_handler BOOKE_INTERRUPT_DEBUG, EX_PARAMS(CRIT), \ | 322 | kvm_handler BOOKE_INTERRUPT_DEBUG, EX_PARAMS(CRIT), \ |
323 | SPRN_CSRR0, SPRN_CSRR1, 0 | 323 | SPRN_CSRR0, SPRN_CSRR1, 0 |
324 | kvm_handler BOOKE_INTERRUPT_LRAT_ERROR, EX_PARAMS(GEN), \ | ||
325 | SPRN_SRR0, SPRN_SRR1, (NEED_EMU | NEED_DEAR | NEED_ESR) | ||
324 | #else | 326 | #else |
325 | /* | 327 | /* |
326 | * For input register values, see arch/powerpc/include/asm/kvm_booke_hv_asm.h | 328 | * For input register values, see arch/powerpc/include/asm/kvm_booke_hv_asm.h |