aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorHollis Blanchard <hollisb@us.ibm.com>2009-01-03 17:23:13 -0500
committerAvi Kivity <avi@redhat.com>2009-03-24 05:02:59 -0400
commitbb3a8a178dec1e46df3138a30f76acf67fe12397 (patch)
tree175effadbcdc3efb79e6b96a9f307052afaba46b /arch/powerpc
parentbdc89f13ec955c14777d5caf02dfca3f51d639bd (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>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/include/asm/kvm_asm.h7
-rw-r--r--arch/powerpc/include/asm/kvm_host.h2
-rw-r--r--arch/powerpc/kvm/booke.c18
-rw-r--r--arch/powerpc/kvm/booke.h30
-rw-r--r--arch/powerpc/kvm/booke_interrupts.S3
-rw-r--r--arch/powerpc/kvm/e500.c20
-rw-r--r--arch/powerpc/kvm/e500_emulate.c27
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
51extern 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
86KVM_HANDLER BOOKE_INTERRUPT_DTLB_MISS 86KVM_HANDLER BOOKE_INTERRUPT_DTLB_MISS
87KVM_HANDLER BOOKE_INTERRUPT_ITLB_MISS 87KVM_HANDLER BOOKE_INTERRUPT_ITLB_MISS
88KVM_HANDLER BOOKE_INTERRUPT_DEBUG 88KVM_HANDLER BOOKE_INTERRUPT_DEBUG
89KVM_HANDLER BOOKE_INTERRUPT_SPE_UNAVAIL
90KVM_HANDLER BOOKE_INTERRUPT_SPE_FP_DATA
91KVM_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
26void kvmppc_core_load_host_debugstate(struct kvm_vcpu *vcpu) 27void kvmppc_core_load_host_debugstate(struct kvm_vcpu *vcpu)
@@ -133,12 +134,29 @@ void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
133 134
134static int kvmppc_e500_init(void) 135static 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 }