aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorAlexander Graf <agraf@suse.de>2012-02-15 08:28:48 -0500
committerAvi Kivity <avi@redhat.com>2012-04-08 05:54:50 -0400
commit4ab969199ec6a14604ceaffb21fe78cc4881d3b8 (patch)
tree9686269b554aaed9f195cff043fd737ec67b024e /arch/powerpc
parent73196cd364a2d972d73fa08da9d81ca3215bed68 (diff)
KVM: PPC: e500mc: Add doorbell emulation support
When one vcpu wants to kick another, it can issue a special IPI instruction called msgsnd. This patch emulates this instruction, its clearing counterpart and the infrastructure required to actually trigger that interrupt inside a guest vcpu. With this patch, SMP guests on e500mc work. Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/include/asm/dbell.h2
-rw-r--r--arch/powerpc/kvm/booke.c2
-rw-r--r--arch/powerpc/kvm/e500_emulate.c68
3 files changed, 72 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/dbell.h b/arch/powerpc/include/asm/dbell.h
index d7365b01f0c4..154c067761b1 100644
--- a/arch/powerpc/include/asm/dbell.h
+++ b/arch/powerpc/include/asm/dbell.h
@@ -19,7 +19,9 @@
19 19
20#define PPC_DBELL_MSG_BRDCAST (0x04000000) 20#define PPC_DBELL_MSG_BRDCAST (0x04000000)
21#define PPC_DBELL_TYPE(x) (((x) & 0xf) << (63-36)) 21#define PPC_DBELL_TYPE(x) (((x) & 0xf) << (63-36))
22#define PPC_DBELL_TYPE_MASK PPC_DBELL_TYPE(0xf)
22#define PPC_DBELL_LPID(x) ((x) << (63 - 49)) 23#define PPC_DBELL_LPID(x) ((x) << (63 - 49))
24#define PPC_DBELL_PIR_MASK 0x3fff
23enum ppc_dbell { 25enum ppc_dbell {
24 PPC_DBELL = 0, /* doorbell */ 26 PPC_DBELL = 0, /* doorbell */
25 PPC_DBELL_CRIT = 1, /* critical doorbell */ 27 PPC_DBELL_CRIT = 1, /* critical doorbell */
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index 0b77be187cf7..85bd5b8f3fd5 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -326,6 +326,7 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
326 int_class = INT_CLASS_NONCRIT; 326 int_class = INT_CLASS_NONCRIT;
327 break; 327 break;
328 case BOOKE_IRQPRIO_CRITICAL: 328 case BOOKE_IRQPRIO_CRITICAL:
329 case BOOKE_IRQPRIO_DBELL_CRIT:
329 allowed = vcpu->arch.shared->msr & MSR_CE; 330 allowed = vcpu->arch.shared->msr & MSR_CE;
330 allowed = allowed && !crit; 331 allowed = allowed && !crit;
331 msr_mask = MSR_GS | MSR_ME; 332 msr_mask = MSR_GS | MSR_ME;
@@ -342,6 +343,7 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
342 keep_irq = true; 343 keep_irq = true;
343 /* fall through */ 344 /* fall through */
344 case BOOKE_IRQPRIO_EXTERNAL: 345 case BOOKE_IRQPRIO_EXTERNAL:
346 case BOOKE_IRQPRIO_DBELL:
345 allowed = vcpu->arch.shared->msr & MSR_EE; 347 allowed = vcpu->arch.shared->msr & MSR_EE;
346 allowed = allowed && !crit; 348 allowed = allowed && !crit;
347 msr_mask = MSR_GS | MSR_CE | MSR_ME | MSR_DE; 349 msr_mask = MSR_GS | MSR_CE | MSR_ME | MSR_DE;
diff --git a/arch/powerpc/kvm/e500_emulate.c b/arch/powerpc/kvm/e500_emulate.c
index 98b6c1cd6b82..99155f847a6a 100644
--- a/arch/powerpc/kvm/e500_emulate.c
+++ b/arch/powerpc/kvm/e500_emulate.c
@@ -14,16 +14,74 @@
14 14
15#include <asm/kvm_ppc.h> 15#include <asm/kvm_ppc.h>
16#include <asm/disassemble.h> 16#include <asm/disassemble.h>
17#include <asm/dbell.h>
17 18
18#include "booke.h" 19#include "booke.h"
19#include "e500.h" 20#include "e500.h"
20 21
22#define XOP_MSGSND 206
23#define XOP_MSGCLR 238
21#define XOP_TLBIVAX 786 24#define XOP_TLBIVAX 786
22#define XOP_TLBSX 914 25#define XOP_TLBSX 914
23#define XOP_TLBRE 946 26#define XOP_TLBRE 946
24#define XOP_TLBWE 978 27#define XOP_TLBWE 978
25#define XOP_TLBILX 18 28#define XOP_TLBILX 18
26 29
30#ifdef CONFIG_KVM_E500MC
31static int dbell2prio(ulong param)
32{
33 int msg = param & PPC_DBELL_TYPE_MASK;
34 int prio = -1;
35
36 switch (msg) {
37 case PPC_DBELL_TYPE(PPC_DBELL):
38 prio = BOOKE_IRQPRIO_DBELL;
39 break;
40 case PPC_DBELL_TYPE(PPC_DBELL_CRIT):
41 prio = BOOKE_IRQPRIO_DBELL_CRIT;
42 break;
43 default:
44 break;
45 }
46
47 return prio;
48}
49
50static int kvmppc_e500_emul_msgclr(struct kvm_vcpu *vcpu, int rb)
51{
52 ulong param = vcpu->arch.gpr[rb];
53 int prio = dbell2prio(param);
54
55 if (prio < 0)
56 return EMULATE_FAIL;
57
58 clear_bit(prio, &vcpu->arch.pending_exceptions);
59 return EMULATE_DONE;
60}
61
62static int kvmppc_e500_emul_msgsnd(struct kvm_vcpu *vcpu, int rb)
63{
64 ulong param = vcpu->arch.gpr[rb];
65 int prio = dbell2prio(rb);
66 int pir = param & PPC_DBELL_PIR_MASK;
67 int i;
68 struct kvm_vcpu *cvcpu;
69
70 if (prio < 0)
71 return EMULATE_FAIL;
72
73 kvm_for_each_vcpu(i, cvcpu, vcpu->kvm) {
74 int cpir = cvcpu->arch.shared->pir;
75 if ((param & PPC_DBELL_MSG_BRDCAST) || (cpir == pir)) {
76 set_bit(prio, &cvcpu->arch.pending_exceptions);
77 kvm_vcpu_kick(cvcpu);
78 }
79 }
80
81 return EMULATE_DONE;
82}
83#endif
84
27int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, 85int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
28 unsigned int inst, int *advance) 86 unsigned int inst, int *advance)
29{ 87{
@@ -36,6 +94,16 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
36 case 31: 94 case 31:
37 switch (get_xop(inst)) { 95 switch (get_xop(inst)) {
38 96
97#ifdef CONFIG_KVM_E500MC
98 case XOP_MSGSND:
99 emulated = kvmppc_e500_emul_msgsnd(vcpu, get_rb(inst));
100 break;
101
102 case XOP_MSGCLR:
103 emulated = kvmppc_e500_emul_msgclr(vcpu, get_rb(inst));
104 break;
105#endif
106
39 case XOP_TLBRE: 107 case XOP_TLBRE:
40 emulated = kvmppc_e500_emul_tlbre(vcpu); 108 emulated = kvmppc_e500_emul_tlbre(vcpu);
41 break; 109 break;