diff options
-rw-r--r-- | arch/powerpc/include/asm/kvm.h | 1 | ||||
-rw-r--r-- | arch/powerpc/include/asm/kvm_asm.h | 4 | ||||
-rw-r--r-- | arch/powerpc/kvm/book3s.c | 30 |
3 files changed, 31 insertions, 4 deletions
diff --git a/arch/powerpc/include/asm/kvm.h b/arch/powerpc/include/asm/kvm.h index 6c5547d82bbe..18ea6963ad77 100644 --- a/arch/powerpc/include/asm/kvm.h +++ b/arch/powerpc/include/asm/kvm.h | |||
@@ -86,5 +86,6 @@ struct kvm_guest_debug_arch { | |||
86 | 86 | ||
87 | #define KVM_INTERRUPT_SET -1U | 87 | #define KVM_INTERRUPT_SET -1U |
88 | #define KVM_INTERRUPT_UNSET -2U | 88 | #define KVM_INTERRUPT_UNSET -2U |
89 | #define KVM_INTERRUPT_SET_LEVEL -3U | ||
89 | 90 | ||
90 | #endif /* __LINUX_KVM_POWERPC_H */ | 91 | #endif /* __LINUX_KVM_POWERPC_H */ |
diff --git a/arch/powerpc/include/asm/kvm_asm.h b/arch/powerpc/include/asm/kvm_asm.h index c5ea4cda34b3..5b7504674397 100644 --- a/arch/powerpc/include/asm/kvm_asm.h +++ b/arch/powerpc/include/asm/kvm_asm.h | |||
@@ -58,6 +58,7 @@ | |||
58 | #define BOOK3S_INTERRUPT_INST_STORAGE 0x400 | 58 | #define BOOK3S_INTERRUPT_INST_STORAGE 0x400 |
59 | #define BOOK3S_INTERRUPT_INST_SEGMENT 0x480 | 59 | #define BOOK3S_INTERRUPT_INST_SEGMENT 0x480 |
60 | #define BOOK3S_INTERRUPT_EXTERNAL 0x500 | 60 | #define BOOK3S_INTERRUPT_EXTERNAL 0x500 |
61 | #define BOOK3S_INTERRUPT_EXTERNAL_LEVEL 0x501 | ||
61 | #define BOOK3S_INTERRUPT_ALIGNMENT 0x600 | 62 | #define BOOK3S_INTERRUPT_ALIGNMENT 0x600 |
62 | #define BOOK3S_INTERRUPT_PROGRAM 0x700 | 63 | #define BOOK3S_INTERRUPT_PROGRAM 0x700 |
63 | #define BOOK3S_INTERRUPT_FP_UNAVAIL 0x800 | 64 | #define BOOK3S_INTERRUPT_FP_UNAVAIL 0x800 |
@@ -84,7 +85,8 @@ | |||
84 | #define BOOK3S_IRQPRIO_EXTERNAL 13 | 85 | #define BOOK3S_IRQPRIO_EXTERNAL 13 |
85 | #define BOOK3S_IRQPRIO_DECREMENTER 14 | 86 | #define BOOK3S_IRQPRIO_DECREMENTER 14 |
86 | #define BOOK3S_IRQPRIO_PERFORMANCE_MONITOR 15 | 87 | #define BOOK3S_IRQPRIO_PERFORMANCE_MONITOR 15 |
87 | #define BOOK3S_IRQPRIO_MAX 16 | 88 | #define BOOK3S_IRQPRIO_EXTERNAL_LEVEL 16 |
89 | #define BOOK3S_IRQPRIO_MAX 17 | ||
88 | 90 | ||
89 | #define BOOK3S_HFLAG_DCBZ32 0x1 | 91 | #define BOOK3S_HFLAG_DCBZ32 0x1 |
90 | #define BOOK3S_HFLAG_SLB 0x2 | 92 | #define BOOK3S_HFLAG_SLB 0x2 |
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c index 5833df7e8ccc..e316847c08c0 100644 --- a/arch/powerpc/kvm/book3s.c +++ b/arch/powerpc/kvm/book3s.c | |||
@@ -186,6 +186,7 @@ static int kvmppc_book3s_vec2irqprio(unsigned int vec) | |||
186 | case 0x400: prio = BOOK3S_IRQPRIO_INST_STORAGE; break; | 186 | case 0x400: prio = BOOK3S_IRQPRIO_INST_STORAGE; break; |
187 | case 0x480: prio = BOOK3S_IRQPRIO_INST_SEGMENT; break; | 187 | case 0x480: prio = BOOK3S_IRQPRIO_INST_SEGMENT; break; |
188 | case 0x500: prio = BOOK3S_IRQPRIO_EXTERNAL; break; | 188 | case 0x500: prio = BOOK3S_IRQPRIO_EXTERNAL; break; |
189 | case 0x501: prio = BOOK3S_IRQPRIO_EXTERNAL_LEVEL; break; | ||
189 | case 0x600: prio = BOOK3S_IRQPRIO_ALIGNMENT; break; | 190 | case 0x600: prio = BOOK3S_IRQPRIO_ALIGNMENT; break; |
190 | case 0x700: prio = BOOK3S_IRQPRIO_PROGRAM; break; | 191 | case 0x700: prio = BOOK3S_IRQPRIO_PROGRAM; break; |
191 | case 0x800: prio = BOOK3S_IRQPRIO_FP_UNAVAIL; break; | 192 | case 0x800: prio = BOOK3S_IRQPRIO_FP_UNAVAIL; break; |
@@ -246,13 +247,19 @@ void kvmppc_core_dequeue_dec(struct kvm_vcpu *vcpu) | |||
246 | void kvmppc_core_queue_external(struct kvm_vcpu *vcpu, | 247 | void kvmppc_core_queue_external(struct kvm_vcpu *vcpu, |
247 | struct kvm_interrupt *irq) | 248 | struct kvm_interrupt *irq) |
248 | { | 249 | { |
249 | kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL); | 250 | unsigned int vec = BOOK3S_INTERRUPT_EXTERNAL; |
251 | |||
252 | if (irq->irq == KVM_INTERRUPT_SET_LEVEL) | ||
253 | vec = BOOK3S_INTERRUPT_EXTERNAL_LEVEL; | ||
254 | |||
255 | kvmppc_book3s_queue_irqprio(vcpu, vec); | ||
250 | } | 256 | } |
251 | 257 | ||
252 | void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu, | 258 | void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu, |
253 | struct kvm_interrupt *irq) | 259 | struct kvm_interrupt *irq) |
254 | { | 260 | { |
255 | kvmppc_book3s_dequeue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL); | 261 | kvmppc_book3s_dequeue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL); |
262 | kvmppc_book3s_dequeue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL_LEVEL); | ||
256 | } | 263 | } |
257 | 264 | ||
258 | int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority) | 265 | int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority) |
@@ -281,6 +288,7 @@ int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority) | |||
281 | vec = BOOK3S_INTERRUPT_DECREMENTER; | 288 | vec = BOOK3S_INTERRUPT_DECREMENTER; |
282 | break; | 289 | break; |
283 | case BOOK3S_IRQPRIO_EXTERNAL: | 290 | case BOOK3S_IRQPRIO_EXTERNAL: |
291 | case BOOK3S_IRQPRIO_EXTERNAL_LEVEL: | ||
284 | deliver = (vcpu->arch.shared->msr & MSR_EE) && !crit; | 292 | deliver = (vcpu->arch.shared->msr & MSR_EE) && !crit; |
285 | vec = BOOK3S_INTERRUPT_EXTERNAL; | 293 | vec = BOOK3S_INTERRUPT_EXTERNAL; |
286 | break; | 294 | break; |
@@ -343,6 +351,23 @@ int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority) | |||
343 | return deliver; | 351 | return deliver; |
344 | } | 352 | } |
345 | 353 | ||
354 | /* | ||
355 | * This function determines if an irqprio should be cleared once issued. | ||
356 | */ | ||
357 | static bool clear_irqprio(struct kvm_vcpu *vcpu, unsigned int priority) | ||
358 | { | ||
359 | switch (priority) { | ||
360 | case BOOK3S_IRQPRIO_DECREMENTER: | ||
361 | /* DEC interrupts get cleared by mtdec */ | ||
362 | return false; | ||
363 | case BOOK3S_IRQPRIO_EXTERNAL_LEVEL: | ||
364 | /* External interrupts get cleared by userspace */ | ||
365 | return false; | ||
366 | } | ||
367 | |||
368 | return true; | ||
369 | } | ||
370 | |||
346 | void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu) | 371 | void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu) |
347 | { | 372 | { |
348 | unsigned long *pending = &vcpu->arch.pending_exceptions; | 373 | unsigned long *pending = &vcpu->arch.pending_exceptions; |
@@ -356,8 +381,7 @@ void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu) | |||
356 | priority = __ffs(*pending); | 381 | priority = __ffs(*pending); |
357 | while (priority < BOOK3S_IRQPRIO_MAX) { | 382 | while (priority < BOOK3S_IRQPRIO_MAX) { |
358 | if (kvmppc_book3s_irqprio_deliver(vcpu, priority) && | 383 | if (kvmppc_book3s_irqprio_deliver(vcpu, priority) && |
359 | (priority != BOOK3S_IRQPRIO_DECREMENTER)) { | 384 | clear_irqprio(vcpu, priority)) { |
360 | /* DEC interrupts get cleared by mtdec */ | ||
361 | clear_bit(priority, &vcpu->arch.pending_exceptions); | 385 | clear_bit(priority, &vcpu->arch.pending_exceptions); |
362 | break; | 386 | break; |
363 | } | 387 | } |