KVM: PPC: Add dequeue for external on BookE
[safe/jmp/linux-2.6] / arch / powerpc / kvm / booke.c
index e283e44..c922240 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/kvm_host.h>
+#include <linux/gfp.h>
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
@@ -82,9 +83,32 @@ static void kvmppc_booke_queue_irqprio(struct kvm_vcpu *vcpu,
        set_bit(priority, &vcpu->arch.pending_exceptions);
 }
 
-void kvmppc_core_queue_program(struct kvm_vcpu *vcpu, ulong flags)
+static void kvmppc_core_queue_dtlb_miss(struct kvm_vcpu *vcpu,
+                                        ulong dear_flags, ulong esr_flags)
 {
-       /* BookE does flags in ESR, so ignore those we get here */
+       vcpu->arch.queued_dear = dear_flags;
+       vcpu->arch.queued_esr = esr_flags;
+       kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_DTLB_MISS);
+}
+
+static void kvmppc_core_queue_data_storage(struct kvm_vcpu *vcpu,
+                                           ulong dear_flags, ulong esr_flags)
+{
+       vcpu->arch.queued_dear = dear_flags;
+       vcpu->arch.queued_esr = esr_flags;
+       kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_DATA_STORAGE);
+}
+
+static void kvmppc_core_queue_inst_storage(struct kvm_vcpu *vcpu,
+                                           ulong esr_flags)
+{
+       vcpu->arch.queued_esr = esr_flags;
+       kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_INST_STORAGE);
+}
+
+void kvmppc_core_queue_program(struct kvm_vcpu *vcpu, ulong esr_flags)
+{
+       vcpu->arch.queued_esr = esr_flags;
        kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_PROGRAM);
 }
 
@@ -109,20 +133,31 @@ void kvmppc_core_queue_external(struct kvm_vcpu *vcpu,
        kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_EXTERNAL);
 }
 
+void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu,
+                                  struct kvm_interrupt *irq)
+{
+       clear_bit(BOOKE_IRQPRIO_EXTERNAL, &vcpu->arch.pending_exceptions);
+}
+
 /* Deliver the interrupt of the corresponding priority, if possible. */
 static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
                                         unsigned int priority)
 {
        int allowed = 0;
        ulong msr_mask;
+       bool update_esr = false, update_dear = false;
 
        switch (priority) {
-       case BOOKE_IRQPRIO_PROGRAM:
        case BOOKE_IRQPRIO_DTLB_MISS:
-       case BOOKE_IRQPRIO_ITLB_MISS:
-       case BOOKE_IRQPRIO_SYSCALL:
        case BOOKE_IRQPRIO_DATA_STORAGE:
+               update_dear = true;
+               /* fall through */
        case BOOKE_IRQPRIO_INST_STORAGE:
+       case BOOKE_IRQPRIO_PROGRAM:
+               update_esr = true;
+               /* fall through */
+       case BOOKE_IRQPRIO_ITLB_MISS:
+       case BOOKE_IRQPRIO_SYSCALL:
        case BOOKE_IRQPRIO_FP_UNAVAIL:
        case BOOKE_IRQPRIO_SPE_UNAVAIL:
        case BOOKE_IRQPRIO_SPE_FP_DATA:
@@ -157,6 +192,10 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
                vcpu->arch.srr0 = vcpu->arch.pc;
                vcpu->arch.srr1 = vcpu->arch.msr;
                vcpu->arch.pc = vcpu->arch.ivpr | vcpu->arch.ivor[priority];
+               if (update_esr == true)
+                       vcpu->arch.esr = vcpu->arch.queued_esr;
+               if (update_dear == true)
+                       vcpu->arch.dear = vcpu->arch.queued_dear;
                kvmppc_set_msr(vcpu, vcpu->arch.msr & msr_mask);
 
                clear_bit(priority, &vcpu->arch.pending_exceptions);
@@ -229,8 +268,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
                if (vcpu->arch.msr & MSR_PR) {
                        /* Program traps generated by user-level software must be handled
                         * by the guest kernel. */
-                       vcpu->arch.esr = vcpu->arch.fault_esr;
-                       kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_PROGRAM);
+                       kvmppc_core_queue_program(vcpu, vcpu->arch.fault_esr);
                        r = RESUME_GUEST;
                        kvmppc_account_exit(vcpu, USR_PR_INST);
                        break;
@@ -286,16 +324,14 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
                break;
 
        case BOOKE_INTERRUPT_DATA_STORAGE:
-               vcpu->arch.dear = vcpu->arch.fault_dear;
-               vcpu->arch.esr = vcpu->arch.fault_esr;
-               kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_DATA_STORAGE);
+               kvmppc_core_queue_data_storage(vcpu, vcpu->arch.fault_dear,
+                                              vcpu->arch.fault_esr);
                kvmppc_account_exit(vcpu, DSI_EXITS);
                r = RESUME_GUEST;
                break;
 
        case BOOKE_INTERRUPT_INST_STORAGE:
-               vcpu->arch.esr = vcpu->arch.fault_esr;
-               kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_INST_STORAGE);
+               kvmppc_core_queue_inst_storage(vcpu, vcpu->arch.fault_esr);
                kvmppc_account_exit(vcpu, ISI_EXITS);
                r = RESUME_GUEST;
                break;
@@ -316,9 +352,9 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
                gtlb_index = kvmppc_mmu_dtlb_index(vcpu, eaddr);
                if (gtlb_index < 0) {
                        /* The guest didn't have a mapping for it. */
-                       kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_DTLB_MISS);
-                       vcpu->arch.dear = vcpu->arch.fault_dear;
-                       vcpu->arch.esr = vcpu->arch.fault_esr;
+                       kvmppc_core_queue_dtlb_miss(vcpu,
+                                                   vcpu->arch.fault_dear,
+                                                   vcpu->arch.fault_esr);
                        kvmppc_mmu_dtlb_miss(vcpu);
                        kvmppc_account_exit(vcpu, DTLB_REAL_MISS_EXITS);
                        r = RESUME_GUEST;