diff options
author | Hollis Blanchard <hollisb@us.ibm.com> | 2009-01-03 17:23:13 -0500 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-03-24 05:02:59 -0400 |
commit | bb3a8a178dec1e46df3138a30f76acf67fe12397 (patch) | |
tree | 175effadbcdc3efb79e6b96a9f307052afaba46b | |
parent | bdc89f13ec955c14777d5caf02dfca3f51d639bd (diff) |
KVM: ppc: Add extra E500 exceptions
e500 has additional interrupt vectors (and corresponding IVORs) for SPE and
performance monitoring interrupts.
Signed-off-by: Liu Yu <yu.liu@freescale.com>
Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r-- | arch/powerpc/include/asm/kvm_asm.h | 7 | ||||
-rw-r--r-- | arch/powerpc/include/asm/kvm_host.h | 2 | ||||
-rw-r--r-- | arch/powerpc/kvm/booke.c | 18 | ||||
-rw-r--r-- | arch/powerpc/kvm/booke.h | 30 | ||||
-rw-r--r-- | arch/powerpc/kvm/booke_interrupts.S | 3 | ||||
-rw-r--r-- | arch/powerpc/kvm/e500.c | 20 | ||||
-rw-r--r-- | arch/powerpc/kvm/e500_emulate.c | 27 |
7 files changed, 92 insertions, 15 deletions
diff --git a/arch/powerpc/include/asm/kvm_asm.h b/arch/powerpc/include/asm/kvm_asm.h index 2197764796d9..56bfae59837f 100644 --- a/arch/powerpc/include/asm/kvm_asm.h +++ b/arch/powerpc/include/asm/kvm_asm.h | |||
@@ -42,7 +42,12 @@ | |||
42 | #define BOOKE_INTERRUPT_DTLB_MISS 13 | 42 | #define BOOKE_INTERRUPT_DTLB_MISS 13 |
43 | #define BOOKE_INTERRUPT_ITLB_MISS 14 | 43 | #define BOOKE_INTERRUPT_ITLB_MISS 14 |
44 | #define BOOKE_INTERRUPT_DEBUG 15 | 44 | #define BOOKE_INTERRUPT_DEBUG 15 |
45 | #define BOOKE_MAX_INTERRUPT 15 | 45 | |
46 | /* E500 */ | ||
47 | #define BOOKE_INTERRUPT_SPE_UNAVAIL 32 | ||
48 | #define BOOKE_INTERRUPT_SPE_FP_DATA 33 | ||
49 | #define BOOKE_INTERRUPT_SPE_FP_ROUND 34 | ||
50 | #define BOOKE_INTERRUPT_PERFORMANCE_MONITOR 35 | ||
46 | 51 | ||
47 | #define RESUME_FLAG_NV (1<<0) /* Reload guest nonvolatile state? */ | 52 | #define RESUME_FLAG_NV (1<<0) /* Reload guest nonvolatile state? */ |
48 | #define RESUME_FLAG_HOST (1<<1) /* Resume host? */ | 53 | #define RESUME_FLAG_HOST (1<<1) /* Resume host? */ |
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index 50e5ce1b400a..1c6187697520 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h | |||
@@ -150,7 +150,7 @@ struct kvm_vcpu_arch { | |||
150 | u32 tbu; | 150 | u32 tbu; |
151 | u32 tcr; | 151 | u32 tcr; |
152 | u32 tsr; | 152 | u32 tsr; |
153 | u32 ivor[16]; | 153 | u32 ivor[64]; |
154 | ulong ivpr; | 154 | ulong ivpr; |
155 | u32 pir; | 155 | u32 pir; |
156 | 156 | ||
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index f192fbee2f29..642e4204cf25 100644 --- a/arch/powerpc/kvm/booke.c +++ b/arch/powerpc/kvm/booke.c | |||
@@ -118,6 +118,9 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu, | |||
118 | case BOOKE_IRQPRIO_DATA_STORAGE: | 118 | case BOOKE_IRQPRIO_DATA_STORAGE: |
119 | case BOOKE_IRQPRIO_INST_STORAGE: | 119 | case BOOKE_IRQPRIO_INST_STORAGE: |
120 | case BOOKE_IRQPRIO_FP_UNAVAIL: | 120 | case BOOKE_IRQPRIO_FP_UNAVAIL: |
121 | case BOOKE_IRQPRIO_SPE_UNAVAIL: | ||
122 | case BOOKE_IRQPRIO_SPE_FP_DATA: | ||
123 | case BOOKE_IRQPRIO_SPE_FP_ROUND: | ||
121 | case BOOKE_IRQPRIO_AP_UNAVAIL: | 124 | case BOOKE_IRQPRIO_AP_UNAVAIL: |
122 | case BOOKE_IRQPRIO_ALIGNMENT: | 125 | case BOOKE_IRQPRIO_ALIGNMENT: |
123 | allowed = 1; | 126 | allowed = 1; |
@@ -261,6 +264,21 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | |||
261 | r = RESUME_GUEST; | 264 | r = RESUME_GUEST; |
262 | break; | 265 | break; |
263 | 266 | ||
267 | case BOOKE_INTERRUPT_SPE_UNAVAIL: | ||
268 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SPE_UNAVAIL); | ||
269 | r = RESUME_GUEST; | ||
270 | break; | ||
271 | |||
272 | case BOOKE_INTERRUPT_SPE_FP_DATA: | ||
273 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SPE_FP_DATA); | ||
274 | r = RESUME_GUEST; | ||
275 | break; | ||
276 | |||
277 | case BOOKE_INTERRUPT_SPE_FP_ROUND: | ||
278 | kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SPE_FP_ROUND); | ||
279 | r = RESUME_GUEST; | ||
280 | break; | ||
281 | |||
264 | case BOOKE_INTERRUPT_DATA_STORAGE: | 282 | case BOOKE_INTERRUPT_DATA_STORAGE: |
265 | vcpu->arch.dear = vcpu->arch.fault_dear; | 283 | vcpu->arch.dear = vcpu->arch.fault_dear; |
266 | vcpu->arch.esr = vcpu->arch.fault_esr; | 284 | vcpu->arch.esr = vcpu->arch.fault_esr; |
diff --git a/arch/powerpc/kvm/booke.h b/arch/powerpc/kvm/booke.h index 7ceeb3e739b4..d59bcca1f9d8 100644 --- a/arch/powerpc/kvm/booke.h +++ b/arch/powerpc/kvm/booke.h | |||
@@ -31,18 +31,24 @@ | |||
31 | #define BOOKE_IRQPRIO_ALIGNMENT 2 | 31 | #define BOOKE_IRQPRIO_ALIGNMENT 2 |
32 | #define BOOKE_IRQPRIO_PROGRAM 3 | 32 | #define BOOKE_IRQPRIO_PROGRAM 3 |
33 | #define BOOKE_IRQPRIO_FP_UNAVAIL 4 | 33 | #define BOOKE_IRQPRIO_FP_UNAVAIL 4 |
34 | #define BOOKE_IRQPRIO_SYSCALL 5 | 34 | #define BOOKE_IRQPRIO_SPE_UNAVAIL 5 |
35 | #define BOOKE_IRQPRIO_AP_UNAVAIL 6 | 35 | #define BOOKE_IRQPRIO_SPE_FP_DATA 6 |
36 | #define BOOKE_IRQPRIO_DTLB_MISS 7 | 36 | #define BOOKE_IRQPRIO_SPE_FP_ROUND 7 |
37 | #define BOOKE_IRQPRIO_ITLB_MISS 8 | 37 | #define BOOKE_IRQPRIO_SYSCALL 8 |
38 | #define BOOKE_IRQPRIO_MACHINE_CHECK 9 | 38 | #define BOOKE_IRQPRIO_AP_UNAVAIL 9 |
39 | #define BOOKE_IRQPRIO_DEBUG 10 | 39 | #define BOOKE_IRQPRIO_DTLB_MISS 10 |
40 | #define BOOKE_IRQPRIO_CRITICAL 11 | 40 | #define BOOKE_IRQPRIO_ITLB_MISS 11 |
41 | #define BOOKE_IRQPRIO_WATCHDOG 12 | 41 | #define BOOKE_IRQPRIO_MACHINE_CHECK 12 |
42 | #define BOOKE_IRQPRIO_EXTERNAL 13 | 42 | #define BOOKE_IRQPRIO_DEBUG 13 |
43 | #define BOOKE_IRQPRIO_FIT 14 | 43 | #define BOOKE_IRQPRIO_CRITICAL 14 |
44 | #define BOOKE_IRQPRIO_DECREMENTER 15 | 44 | #define BOOKE_IRQPRIO_WATCHDOG 15 |
45 | #define BOOKE_IRQPRIO_MAX 15 | 45 | #define BOOKE_IRQPRIO_EXTERNAL 16 |
46 | #define BOOKE_IRQPRIO_FIT 17 | ||
47 | #define BOOKE_IRQPRIO_DECREMENTER 18 | ||
48 | #define BOOKE_IRQPRIO_PERFORMANCE_MONITOR 19 | ||
49 | #define BOOKE_IRQPRIO_MAX 19 | ||
50 | |||
51 | extern unsigned long kvmppc_booke_handlers; | ||
46 | 52 | ||
47 | /* Helper function for "full" MSR writes. No need to call this if only EE is | 53 | /* Helper function for "full" MSR writes. No need to call this if only EE is |
48 | * changing. */ | 54 | * changing. */ |
diff --git a/arch/powerpc/kvm/booke_interrupts.S b/arch/powerpc/kvm/booke_interrupts.S index 4679ec287e62..d0c6f841bbd1 100644 --- a/arch/powerpc/kvm/booke_interrupts.S +++ b/arch/powerpc/kvm/booke_interrupts.S | |||
@@ -86,6 +86,9 @@ KVM_HANDLER BOOKE_INTERRUPT_WATCHDOG | |||
86 | KVM_HANDLER BOOKE_INTERRUPT_DTLB_MISS | 86 | KVM_HANDLER BOOKE_INTERRUPT_DTLB_MISS |
87 | KVM_HANDLER BOOKE_INTERRUPT_ITLB_MISS | 87 | KVM_HANDLER BOOKE_INTERRUPT_ITLB_MISS |
88 | KVM_HANDLER BOOKE_INTERRUPT_DEBUG | 88 | KVM_HANDLER BOOKE_INTERRUPT_DEBUG |
89 | KVM_HANDLER BOOKE_INTERRUPT_SPE_UNAVAIL | ||
90 | KVM_HANDLER BOOKE_INTERRUPT_SPE_FP_DATA | ||
91 | KVM_HANDLER BOOKE_INTERRUPT_SPE_FP_ROUND | ||
89 | 92 | ||
90 | _GLOBAL(kvmppc_handler_len) | 93 | _GLOBAL(kvmppc_handler_len) |
91 | .long kvmppc_handler_1 - kvmppc_handler_0 | 94 | .long kvmppc_handler_1 - kvmppc_handler_0 |
diff --git a/arch/powerpc/kvm/e500.c b/arch/powerpc/kvm/e500.c index 7992da497cd4..d8067fd81cdd 100644 --- a/arch/powerpc/kvm/e500.c +++ b/arch/powerpc/kvm/e500.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <asm/kvm_e500.h> | 21 | #include <asm/kvm_e500.h> |
22 | #include <asm/kvm_ppc.h> | 22 | #include <asm/kvm_ppc.h> |
23 | 23 | ||
24 | #include "booke.h" | ||
24 | #include "e500_tlb.h" | 25 | #include "e500_tlb.h" |
25 | 26 | ||
26 | void kvmppc_core_load_host_debugstate(struct kvm_vcpu *vcpu) | 27 | void kvmppc_core_load_host_debugstate(struct kvm_vcpu *vcpu) |
@@ -133,12 +134,29 @@ void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu) | |||
133 | 134 | ||
134 | static int kvmppc_e500_init(void) | 135 | static int kvmppc_e500_init(void) |
135 | { | 136 | { |
136 | int r; | 137 | int r, i; |
138 | unsigned long ivor[3]; | ||
139 | unsigned long max_ivor = 0; | ||
137 | 140 | ||
138 | r = kvmppc_booke_init(); | 141 | r = kvmppc_booke_init(); |
139 | if (r) | 142 | if (r) |
140 | return r; | 143 | return r; |
141 | 144 | ||
145 | /* copy extra E500 exception handlers */ | ||
146 | ivor[0] = mfspr(SPRN_IVOR32); | ||
147 | ivor[1] = mfspr(SPRN_IVOR33); | ||
148 | ivor[2] = mfspr(SPRN_IVOR34); | ||
149 | for (i = 0; i < 3; i++) { | ||
150 | if (ivor[i] > max_ivor) | ||
151 | max_ivor = ivor[i]; | ||
152 | |||
153 | memcpy((void *)kvmppc_booke_handlers + ivor[i], | ||
154 | kvmppc_handlers_start + (i + 16) * kvmppc_handler_len, | ||
155 | kvmppc_handler_len); | ||
156 | } | ||
157 | flush_icache_range(kvmppc_booke_handlers, | ||
158 | kvmppc_booke_handlers + max_ivor + kvmppc_handler_len); | ||
159 | |||
142 | return kvm_init(NULL, sizeof(struct kvmppc_vcpu_e500), THIS_MODULE); | 160 | return kvm_init(NULL, sizeof(struct kvmppc_vcpu_e500), THIS_MODULE); |
143 | } | 161 | } |
144 | 162 | ||
diff --git a/arch/powerpc/kvm/e500_emulate.c b/arch/powerpc/kvm/e500_emulate.c index a47f44cd2cfd..d3c0c7c7f209 100644 --- a/arch/powerpc/kvm/e500_emulate.c +++ b/arch/powerpc/kvm/e500_emulate.c | |||
@@ -107,6 +107,20 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) | |||
107 | case SPRN_HID1: | 107 | case SPRN_HID1: |
108 | vcpu_e500->hid1 = vcpu->arch.gpr[rs]; break; | 108 | vcpu_e500->hid1 = vcpu->arch.gpr[rs]; break; |
109 | 109 | ||
110 | /* extra exceptions */ | ||
111 | case SPRN_IVOR32: | ||
112 | vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL] = vcpu->arch.gpr[rs]; | ||
113 | break; | ||
114 | case SPRN_IVOR33: | ||
115 | vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_DATA] = vcpu->arch.gpr[rs]; | ||
116 | break; | ||
117 | case SPRN_IVOR34: | ||
118 | vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND] = vcpu->arch.gpr[rs]; | ||
119 | break; | ||
120 | case SPRN_IVOR35: | ||
121 | vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR] = vcpu->arch.gpr[rs]; | ||
122 | break; | ||
123 | |||
110 | default: | 124 | default: |
111 | emulated = kvmppc_booke_emulate_mtspr(vcpu, sprn, rs); | 125 | emulated = kvmppc_booke_emulate_mtspr(vcpu, sprn, rs); |
112 | } | 126 | } |
@@ -160,6 +174,19 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt) | |||
160 | case SPRN_HID1: | 174 | case SPRN_HID1: |
161 | vcpu->arch.gpr[rt] = vcpu_e500->hid1; break; | 175 | vcpu->arch.gpr[rt] = vcpu_e500->hid1; break; |
162 | 176 | ||
177 | /* extra exceptions */ | ||
178 | case SPRN_IVOR32: | ||
179 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL]; | ||
180 | break; | ||
181 | case SPRN_IVOR33: | ||
182 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_DATA]; | ||
183 | break; | ||
184 | case SPRN_IVOR34: | ||
185 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND]; | ||
186 | break; | ||
187 | case SPRN_IVOR35: | ||
188 | vcpu->arch.gpr[rt] = vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR]; | ||
189 | break; | ||
163 | default: | 190 | default: |
164 | emulated = kvmppc_booke_emulate_mfspr(vcpu, sprn, rt); | 191 | emulated = kvmppc_booke_emulate_mfspr(vcpu, sprn, rt); |
165 | } | 192 | } |