aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kvm/booke.c
diff options
context:
space:
mode:
authorHollis Blanchard <hollisb@us.ibm.com>2008-11-05 10:36:23 -0500
committerAvi Kivity <avi@redhat.com>2008-12-31 09:52:23 -0500
commitd4cf3892e50b8e35341086a4fe2bb8a3989b55d4 (patch)
treeadb3275c9d5a2a89605b705434e57e1d0fc48ae6 /arch/powerpc/kvm/booke.c
parent9ab80843c01ac25139e635d018467e528729a317 (diff)
KVM: ppc: optimize irq delivery path
In kvmppc_deliver_interrupt is just one case left in the switch and it is a rare one (less than 8%) when looking at the exit numbers. Therefore we can at least drop the switch/case and if an if. I inserted an unlikely too, but that's open for discussion. In kvmppc_can_deliver_interrupt all frequent cases are in the default case. I know compilers are smart but we can make it easier for them. By writing down all options and removing the default case combined with the fact that ithe values are constants 0..15 should allow the compiler to write an easy jump table. Modifying kvmppc_can_deliver_interrupt pointed me to the fact that gcc seems to be unable to reduce priority_exception[x] to a build time constant. Therefore I changed the usage of the translation arrays in the interrupt delivery path completely. It is now using priority without translation to irq on the full irq delivery path. To be able to do that ivpr regs are stored by their priority now. Additionally the decision made in kvmppc_can_deliver_interrupt is already sufficient to get the value of interrupt_msr_mask[x]. Therefore we can replace the 16x4byte array used here with a single 4byte variable (might still be one miss, but the chance to find this in cache should be better than the right entry of the whole array). Signed-off-by: Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com> Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/powerpc/kvm/booke.c')
-rw-r--r--arch/powerpc/kvm/booke.c175
1 files changed, 55 insertions, 120 deletions
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index 0f064719162c..ec59a6768ec3 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -55,64 +55,6 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
55 { NULL } 55 { NULL }
56}; 56};
57 57
58static const u32 interrupt_msr_mask[16] = {
59 [BOOKE_INTERRUPT_CRITICAL] = MSR_ME,
60 [BOOKE_INTERRUPT_MACHINE_CHECK] = 0,
61 [BOOKE_INTERRUPT_DATA_STORAGE] = MSR_CE|MSR_ME|MSR_DE,
62 [BOOKE_INTERRUPT_INST_STORAGE] = MSR_CE|MSR_ME|MSR_DE,
63 [BOOKE_INTERRUPT_EXTERNAL] = MSR_CE|MSR_ME|MSR_DE,
64 [BOOKE_INTERRUPT_ALIGNMENT] = MSR_CE|MSR_ME|MSR_DE,
65 [BOOKE_INTERRUPT_PROGRAM] = MSR_CE|MSR_ME|MSR_DE,
66 [BOOKE_INTERRUPT_FP_UNAVAIL] = MSR_CE|MSR_ME|MSR_DE,
67 [BOOKE_INTERRUPT_SYSCALL] = MSR_CE|MSR_ME|MSR_DE,
68 [BOOKE_INTERRUPT_AP_UNAVAIL] = MSR_CE|MSR_ME|MSR_DE,
69 [BOOKE_INTERRUPT_DECREMENTER] = MSR_CE|MSR_ME|MSR_DE,
70 [BOOKE_INTERRUPT_FIT] = MSR_CE|MSR_ME|MSR_DE,
71 [BOOKE_INTERRUPT_WATCHDOG] = MSR_ME,
72 [BOOKE_INTERRUPT_DTLB_MISS] = MSR_CE|MSR_ME|MSR_DE,
73 [BOOKE_INTERRUPT_ITLB_MISS] = MSR_CE|MSR_ME|MSR_DE,
74 [BOOKE_INTERRUPT_DEBUG] = MSR_ME,
75};
76
77const unsigned char exception_priority[] = {
78 [BOOKE_INTERRUPT_DATA_STORAGE] = 0,
79 [BOOKE_INTERRUPT_INST_STORAGE] = 1,
80 [BOOKE_INTERRUPT_ALIGNMENT] = 2,
81 [BOOKE_INTERRUPT_PROGRAM] = 3,
82 [BOOKE_INTERRUPT_FP_UNAVAIL] = 4,
83 [BOOKE_INTERRUPT_SYSCALL] = 5,
84 [BOOKE_INTERRUPT_AP_UNAVAIL] = 6,
85 [BOOKE_INTERRUPT_DTLB_MISS] = 7,
86 [BOOKE_INTERRUPT_ITLB_MISS] = 8,
87 [BOOKE_INTERRUPT_MACHINE_CHECK] = 9,
88 [BOOKE_INTERRUPT_DEBUG] = 10,
89 [BOOKE_INTERRUPT_CRITICAL] = 11,
90 [BOOKE_INTERRUPT_WATCHDOG] = 12,
91 [BOOKE_INTERRUPT_EXTERNAL] = 13,
92 [BOOKE_INTERRUPT_FIT] = 14,
93 [BOOKE_INTERRUPT_DECREMENTER] = 15,
94};
95
96const unsigned char priority_exception[] = {
97 BOOKE_INTERRUPT_DATA_STORAGE,
98 BOOKE_INTERRUPT_INST_STORAGE,
99 BOOKE_INTERRUPT_ALIGNMENT,
100 BOOKE_INTERRUPT_PROGRAM,
101 BOOKE_INTERRUPT_FP_UNAVAIL,
102 BOOKE_INTERRUPT_SYSCALL,
103 BOOKE_INTERRUPT_AP_UNAVAIL,
104 BOOKE_INTERRUPT_DTLB_MISS,
105 BOOKE_INTERRUPT_ITLB_MISS,
106 BOOKE_INTERRUPT_MACHINE_CHECK,
107 BOOKE_INTERRUPT_DEBUG,
108 BOOKE_INTERRUPT_CRITICAL,
109 BOOKE_INTERRUPT_WATCHDOG,
110 BOOKE_INTERRUPT_EXTERNAL,
111 BOOKE_INTERRUPT_FIT,
112 BOOKE_INTERRUPT_DECREMENTER,
113};
114
115
116/* TODO: use vcpu_printf() */ 58/* TODO: use vcpu_printf() */
117void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu) 59void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu)
118{ 60{
@@ -133,103 +75,96 @@ void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu)
133 } 75 }
134} 76}
135 77
136static void kvmppc_booke_queue_exception(struct kvm_vcpu *vcpu, int exception) 78static void kvmppc_booke_queue_irqprio(struct kvm_vcpu *vcpu,
79 unsigned int priority)
137{ 80{
138 unsigned int priority = exception_priority[exception];
139 set_bit(priority, &vcpu->arch.pending_exceptions); 81 set_bit(priority, &vcpu->arch.pending_exceptions);
140} 82}
141 83
142static void kvmppc_booke_clear_exception(struct kvm_vcpu *vcpu, int exception)
143{
144 unsigned int priority = exception_priority[exception];
145 clear_bit(priority, &vcpu->arch.pending_exceptions);
146}
147
148void kvmppc_core_queue_program(struct kvm_vcpu *vcpu) 84void kvmppc_core_queue_program(struct kvm_vcpu *vcpu)
149{ 85{
150 kvmppc_booke_queue_exception(vcpu, BOOKE_INTERRUPT_PROGRAM); 86 kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_PROGRAM);
151} 87}
152 88
153void kvmppc_core_queue_dec(struct kvm_vcpu *vcpu) 89void kvmppc_core_queue_dec(struct kvm_vcpu *vcpu)
154{ 90{
155 kvmppc_booke_queue_exception(vcpu, BOOKE_INTERRUPT_DECREMENTER); 91 kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_DECREMENTER);
156} 92}
157 93
158int kvmppc_core_pending_dec(struct kvm_vcpu *vcpu) 94int kvmppc_core_pending_dec(struct kvm_vcpu *vcpu)
159{ 95{
160 unsigned int priority = exception_priority[BOOKE_INTERRUPT_DECREMENTER]; 96 return test_bit(BOOKE_IRQPRIO_DECREMENTER, &vcpu->arch.pending_exceptions);
161 return test_bit(priority, &vcpu->arch.pending_exceptions);
162} 97}
163 98
164void kvmppc_core_queue_external(struct kvm_vcpu *vcpu, 99void kvmppc_core_queue_external(struct kvm_vcpu *vcpu,
165 struct kvm_interrupt *irq) 100 struct kvm_interrupt *irq)
166{ 101{
167 kvmppc_booke_queue_exception(vcpu, BOOKE_INTERRUPT_EXTERNAL); 102 kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_EXTERNAL);
168} 103}
169 104
170/* Check if we are ready to deliver the interrupt */ 105/* Deliver the interrupt of the corresponding priority, if possible. */
171static int kvmppc_can_deliver_interrupt(struct kvm_vcpu *vcpu, int interrupt) 106static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
107 unsigned int priority)
172{ 108{
173 int r; 109 int allowed = 0;
174 110 ulong msr_mask;
175 switch (interrupt) { 111
176 case BOOKE_INTERRUPT_CRITICAL: 112 switch (priority) {
177 r = vcpu->arch.msr & MSR_CE; 113 case BOOKE_IRQPRIO_PROGRAM:
114 case BOOKE_IRQPRIO_DTLB_MISS:
115 case BOOKE_IRQPRIO_ITLB_MISS:
116 case BOOKE_IRQPRIO_SYSCALL:
117 case BOOKE_IRQPRIO_DATA_STORAGE:
118 case BOOKE_IRQPRIO_INST_STORAGE:
119 case BOOKE_IRQPRIO_FP_UNAVAIL:
120 case BOOKE_IRQPRIO_AP_UNAVAIL:
121 case BOOKE_IRQPRIO_ALIGNMENT:
122 allowed = 1;
123 msr_mask = MSR_CE|MSR_ME|MSR_DE;
178 break; 124 break;
179 case BOOKE_INTERRUPT_MACHINE_CHECK: 125 case BOOKE_IRQPRIO_CRITICAL:
180 r = vcpu->arch.msr & MSR_ME; 126 case BOOKE_IRQPRIO_WATCHDOG:
127 allowed = vcpu->arch.msr & MSR_CE;
128 msr_mask = MSR_ME;
181 break; 129 break;
182 case BOOKE_INTERRUPT_EXTERNAL: 130 case BOOKE_IRQPRIO_MACHINE_CHECK:
183 r = vcpu->arch.msr & MSR_EE; 131 allowed = vcpu->arch.msr & MSR_ME;
184 break; 132 msr_mask = 0;
185 case BOOKE_INTERRUPT_DECREMENTER:
186 r = vcpu->arch.msr & MSR_EE;
187 break; 133 break;
188 case BOOKE_INTERRUPT_FIT: 134 case BOOKE_IRQPRIO_EXTERNAL:
189 r = vcpu->arch.msr & MSR_EE; 135 case BOOKE_IRQPRIO_DECREMENTER:
136 case BOOKE_IRQPRIO_FIT:
137 allowed = vcpu->arch.msr & MSR_EE;
138 msr_mask = MSR_CE|MSR_ME|MSR_DE;
190 break; 139 break;
191 case BOOKE_INTERRUPT_WATCHDOG: 140 case BOOKE_IRQPRIO_DEBUG:
192 r = vcpu->arch.msr & MSR_CE; 141 allowed = vcpu->arch.msr & MSR_DE;
142 msr_mask = MSR_ME;
193 break; 143 break;
194 case BOOKE_INTERRUPT_DEBUG:
195 r = vcpu->arch.msr & MSR_DE;
196 break;
197 default:
198 r = 1;
199 } 144 }
200 145
201 return r; 146 if (allowed) {
202} 147 vcpu->arch.srr0 = vcpu->arch.pc;
148 vcpu->arch.srr1 = vcpu->arch.msr;
149 vcpu->arch.pc = vcpu->arch.ivpr | vcpu->arch.ivor[priority];
150 kvmppc_set_msr(vcpu, vcpu->arch.msr & msr_mask);
203 151
204static void kvmppc_booke_deliver_interrupt(struct kvm_vcpu *vcpu, int interrupt) 152 clear_bit(priority, &vcpu->arch.pending_exceptions);
205{
206 switch (interrupt) {
207 case BOOKE_INTERRUPT_DECREMENTER:
208 vcpu->arch.tsr |= TSR_DIS;
209 break;
210 } 153 }
211 154
212 vcpu->arch.srr0 = vcpu->arch.pc; 155 return allowed;
213 vcpu->arch.srr1 = vcpu->arch.msr;
214 vcpu->arch.pc = vcpu->arch.ivpr | vcpu->arch.ivor[interrupt];
215 kvmppc_set_msr(vcpu, vcpu->arch.msr & interrupt_msr_mask[interrupt]);
216} 156}
217 157
218/* Check pending exceptions and deliver one, if possible. */ 158/* Check pending exceptions and deliver one, if possible. */
219void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu) 159void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu)
220{ 160{
221 unsigned long *pending = &vcpu->arch.pending_exceptions; 161 unsigned long *pending = &vcpu->arch.pending_exceptions;
222 unsigned int exception;
223 unsigned int priority; 162 unsigned int priority;
224 163
225 priority = __ffs(*pending); 164 priority = __ffs(*pending);
226 while (priority <= BOOKE_MAX_INTERRUPT) { 165 while (priority <= BOOKE_MAX_INTERRUPT) {
227 exception = priority_exception[priority]; 166 if (kvmppc_booke_irqprio_deliver(vcpu, priority))
228 if (kvmppc_can_deliver_interrupt(vcpu, exception)) {
229 kvmppc_booke_clear_exception(vcpu, exception);
230 kvmppc_booke_deliver_interrupt(vcpu, exception);
231 break; 167 break;
232 }
233 168
234 priority = find_next_bit(pending, 169 priority = find_next_bit(pending,
235 BITS_PER_BYTE * sizeof(*pending), 170 BITS_PER_BYTE * sizeof(*pending),
@@ -287,7 +222,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
287 /* Program traps generated by user-level software must be handled 222 /* Program traps generated by user-level software must be handled
288 * by the guest kernel. */ 223 * by the guest kernel. */
289 vcpu->arch.esr = vcpu->arch.fault_esr; 224 vcpu->arch.esr = vcpu->arch.fault_esr;
290 kvmppc_booke_queue_exception(vcpu, BOOKE_INTERRUPT_PROGRAM); 225 kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_PROGRAM);
291 r = RESUME_GUEST; 226 r = RESUME_GUEST;
292 break; 227 break;
293 } 228 }
@@ -321,27 +256,27 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
321 break; 256 break;
322 257
323 case BOOKE_INTERRUPT_FP_UNAVAIL: 258 case BOOKE_INTERRUPT_FP_UNAVAIL:
324 kvmppc_booke_queue_exception(vcpu, exit_nr); 259 kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_FP_UNAVAIL);
325 r = RESUME_GUEST; 260 r = RESUME_GUEST;
326 break; 261 break;
327 262
328 case BOOKE_INTERRUPT_DATA_STORAGE: 263 case BOOKE_INTERRUPT_DATA_STORAGE:
329 vcpu->arch.dear = vcpu->arch.fault_dear; 264 vcpu->arch.dear = vcpu->arch.fault_dear;
330 vcpu->arch.esr = vcpu->arch.fault_esr; 265 vcpu->arch.esr = vcpu->arch.fault_esr;
331 kvmppc_booke_queue_exception(vcpu, exit_nr); 266 kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_DATA_STORAGE);
332 vcpu->stat.dsi_exits++; 267 vcpu->stat.dsi_exits++;
333 r = RESUME_GUEST; 268 r = RESUME_GUEST;
334 break; 269 break;
335 270
336 case BOOKE_INTERRUPT_INST_STORAGE: 271 case BOOKE_INTERRUPT_INST_STORAGE:
337 vcpu->arch.esr = vcpu->arch.fault_esr; 272 vcpu->arch.esr = vcpu->arch.fault_esr;
338 kvmppc_booke_queue_exception(vcpu, exit_nr); 273 kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_INST_STORAGE);
339 vcpu->stat.isi_exits++; 274 vcpu->stat.isi_exits++;
340 r = RESUME_GUEST; 275 r = RESUME_GUEST;
341 break; 276 break;
342 277
343 case BOOKE_INTERRUPT_SYSCALL: 278 case BOOKE_INTERRUPT_SYSCALL:
344 kvmppc_booke_queue_exception(vcpu, exit_nr); 279 kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_SYSCALL);
345 vcpu->stat.syscall_exits++; 280 vcpu->stat.syscall_exits++;
346 r = RESUME_GUEST; 281 r = RESUME_GUEST;
347 break; 282 break;
@@ -355,7 +290,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
355 gtlbe = kvmppc_44x_dtlb_search(vcpu, eaddr); 290 gtlbe = kvmppc_44x_dtlb_search(vcpu, eaddr);
356 if (!gtlbe) { 291 if (!gtlbe) {
357 /* The guest didn't have a mapping for it. */ 292 /* The guest didn't have a mapping for it. */
358 kvmppc_booke_queue_exception(vcpu, exit_nr); 293 kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_DTLB_MISS);
359 vcpu->arch.dear = vcpu->arch.fault_dear; 294 vcpu->arch.dear = vcpu->arch.fault_dear;
360 vcpu->arch.esr = vcpu->arch.fault_esr; 295 vcpu->arch.esr = vcpu->arch.fault_esr;
361 vcpu->stat.dtlb_real_miss_exits++; 296 vcpu->stat.dtlb_real_miss_exits++;
@@ -398,7 +333,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
398 gtlbe = kvmppc_44x_itlb_search(vcpu, eaddr); 333 gtlbe = kvmppc_44x_itlb_search(vcpu, eaddr);
399 if (!gtlbe) { 334 if (!gtlbe) {
400 /* The guest didn't have a mapping for it. */ 335 /* The guest didn't have a mapping for it. */
401 kvmppc_booke_queue_exception(vcpu, exit_nr); 336 kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_ITLB_MISS);
402 vcpu->stat.itlb_real_miss_exits++; 337 vcpu->stat.itlb_real_miss_exits++;
403 break; 338 break;
404 } 339 }
@@ -418,7 +353,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
418 gtlbe->word2); 353 gtlbe->word2);
419 } else { 354 } else {
420 /* Guest mapped and leaped at non-RAM! */ 355 /* Guest mapped and leaped at non-RAM! */
421 kvmppc_booke_queue_exception(vcpu, BOOKE_INTERRUPT_MACHINE_CHECK); 356 kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_MACHINE_CHECK);
422 } 357 }
423 358
424 break; 359 break;