include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / arch / powerpc / kvm / booke.c
index 56d6ed6..2a3a195 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>
 #include <asm/kvm_ppc.h>
 #include "timing.h"
 #include <asm/cacheflush.h>
-#include <asm/kvm_44x.h>
 
 #include "booke.h"
-#include "44x_tlb.h"
 
 unsigned long kvmppc_booke_handlers;
 
@@ -71,10 +70,10 @@ void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu)
 
        for (i = 0; i < 32; i += 4) {
                printk("gpr%02d: %08lx %08lx %08lx %08lx\n", i,
-                      vcpu->arch.gpr[i],
-                      vcpu->arch.gpr[i+1],
-                      vcpu->arch.gpr[i+2],
-                      vcpu->arch.gpr[i+3]);
+                      kvmppc_get_gpr(vcpu, i),
+                      kvmppc_get_gpr(vcpu, i+1),
+                      kvmppc_get_gpr(vcpu, i+2),
+                      kvmppc_get_gpr(vcpu, i+3));
        }
 }
 
@@ -84,8 +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)
+static void kvmppc_core_queue_dtlb_miss(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_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);
 }
 
@@ -99,6 +122,11 @@ int kvmppc_core_pending_dec(struct kvm_vcpu *vcpu)
        return test_bit(BOOKE_IRQPRIO_DECREMENTER, &vcpu->arch.pending_exceptions);
 }
 
+void kvmppc_core_dequeue_dec(struct kvm_vcpu *vcpu)
+{
+       clear_bit(BOOKE_IRQPRIO_DECREMENTER, &vcpu->arch.pending_exceptions);
+}
+
 void kvmppc_core_queue_external(struct kvm_vcpu *vcpu,
                                 struct kvm_interrupt *irq)
 {
@@ -111,15 +139,23 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
 {
        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:
+       case BOOKE_IRQPRIO_SPE_FP_ROUND:
        case BOOKE_IRQPRIO_AP_UNAVAIL:
        case BOOKE_IRQPRIO_ALIGNMENT:
                allowed = 1;
@@ -150,6 +186,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);
@@ -165,7 +205,7 @@ void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu)
        unsigned int priority;
 
        priority = __ffs(*pending);
-       while (priority <= BOOKE_MAX_INTERRUPT) {
+       while (priority <= BOOKE_IRQPRIO_MAX) {
                if (kvmppc_booke_irqprio_deliver(vcpu, priority))
                        break;
 
@@ -222,8 +262,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;
@@ -263,17 +302,30 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
                r = RESUME_GUEST;
                break;
 
+       case BOOKE_INTERRUPT_SPE_UNAVAIL:
+               kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SPE_UNAVAIL);
+               r = RESUME_GUEST;
+               break;
+
+       case BOOKE_INTERRUPT_SPE_FP_DATA:
+               kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SPE_FP_DATA);
+               r = RESUME_GUEST;
+               break;
+
+       case BOOKE_INTERRUPT_SPE_FP_ROUND:
+               kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SPE_FP_ROUND);
+               r = RESUME_GUEST;
+               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;
@@ -284,7 +336,6 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
                r = RESUME_GUEST;
                break;
 
-       /* XXX move to a 440-specific file. */
        case BOOKE_INTERRUPT_DTLB_MISS: {
                unsigned long eaddr = vcpu->arch.fault_dear;
                int gtlb_index;
@@ -292,12 +343,13 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
                gfn_t gfn;
 
                /* Check the guest TLB. */
-               gtlb_index = kvmppc_44x_dtlb_index(vcpu, eaddr);
+               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;
                        break;
@@ -327,7 +379,6 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
                break;
        }
 
-       /* XXX move to a 440-specific file. */
        case BOOKE_INTERRUPT_ITLB_MISS: {
                unsigned long eaddr = vcpu->arch.pc;
                gpa_t gpaddr;
@@ -337,10 +388,11 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
                r = RESUME_GUEST;
 
                /* Check the guest TLB. */
-               gtlb_index = kvmppc_44x_itlb_index(vcpu, eaddr);
+               gtlb_index = kvmppc_mmu_itlb_index(vcpu, eaddr);
                if (gtlb_index < 0) {
                        /* The guest didn't have a mapping for it. */
                        kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_ITLB_MISS);
+                       kvmppc_mmu_itlb_miss(vcpu);
                        kvmppc_account_exit(vcpu, ITLB_REAL_MISS_EXITS);
                        break;
                }
@@ -410,7 +462,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 {
        vcpu->arch.pc = 0;
        vcpu->arch.msr = 0;
-       vcpu->arch.gpr[1] = (16<<20) - 8; /* -8 for the callee-save LR slot */
+       kvmppc_set_gpr(vcpu, 1, (16<<20) - 8); /* -8 for the callee-save LR slot */
 
        vcpu->arch.shadow_pid = 1;
 
@@ -428,10 +480,10 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
        int i;
 
        regs->pc = vcpu->arch.pc;
-       regs->cr = vcpu->arch.cr;
+       regs->cr = kvmppc_get_cr(vcpu);
        regs->ctr = vcpu->arch.ctr;
        regs->lr = vcpu->arch.lr;
-       regs->xer = vcpu->arch.xer;
+       regs->xer = kvmppc_get_xer(vcpu);
        regs->msr = vcpu->arch.msr;
        regs->srr0 = vcpu->arch.srr0;
        regs->srr1 = vcpu->arch.srr1;
@@ -445,7 +497,7 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
        regs->sprg7 = vcpu->arch.sprg6;
 
        for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
-               regs->gpr[i] = vcpu->arch.gpr[i];
+               regs->gpr[i] = kvmppc_get_gpr(vcpu, i);
 
        return 0;
 }
@@ -455,10 +507,10 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
        int i;
 
        vcpu->arch.pc = regs->pc;
-       vcpu->arch.cr = regs->cr;
+       kvmppc_set_cr(vcpu, regs->cr);
        vcpu->arch.ctr = regs->ctr;
        vcpu->arch.lr = regs->lr;
-       vcpu->arch.xer = regs->xer;
+       kvmppc_set_xer(vcpu, regs->xer);
        kvmppc_set_msr(vcpu, regs->msr);
        vcpu->arch.srr0 = regs->srr0;
        vcpu->arch.srr1 = regs->srr1;
@@ -470,8 +522,8 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
        vcpu->arch.sprg6 = regs->sprg5;
        vcpu->arch.sprg7 = regs->sprg6;
 
-       for (i = 0; i < ARRAY_SIZE(vcpu->arch.gpr); i++)
-               vcpu->arch.gpr[i] = regs->gpr[i];
+       for (i = 0; i < ARRAY_SIZE(regs->gpr); i++)
+               kvmppc_set_gpr(vcpu, i, regs->gpr[i]);
 
        return 0;
 }
@@ -504,7 +556,12 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
        return kvmppc_core_vcpu_translate(vcpu, tr);
 }
 
-int kvmppc_booke_init(void)
+int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log)
+{
+       return -ENOTSUPP;
+}
+
+int __init kvmppc_booke_init(void)
 {
        unsigned long ivor[16];
        unsigned long max_ivor = 0;