aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2011-11-17 07:39:59 -0500
committerAvi Kivity <avi@redhat.com>2012-03-05 07:52:27 -0500
commitdfd4d47e9a71c5a35eb67a44cd311efbe1846b7e (patch)
tree1115128a884dabf7d853466b82c553561e4f7b27
parentb59049720dd95021dfe0d9f4e1fa9458a67cfe29 (diff)
KVM: PPC: booke: Improve timer register emulation
Decrementers are now properly driven by TCR/TSR, and the guest has full read/write access to these registers. The decrementer keeps ticking (and setting the TSR bit) regardless of whether the interrupts are enabled with TCR. The decrementer stops at zero, rather than going negative. Decrementers (and FITs, once implemented) are delivered as level-triggered interrupts -- dequeued when the TSR bit is cleared, not on delivery. Signed-off-by: Liu Yu <yu.liu@freescale.com> [scottwood@freescale.com: significant changes] Signed-off-by: Scott Wood <scottwood@freescale.com> Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--arch/powerpc/include/asm/kvm_host.h2
-rw-r--r--arch/powerpc/include/asm/kvm_ppc.h1
-rw-r--r--arch/powerpc/kvm/book3s.c8
-rw-r--r--arch/powerpc/kvm/booke.c67
-rw-r--r--arch/powerpc/kvm/booke.h4
-rw-r--r--arch/powerpc/kvm/booke_emulate.c11
-rw-r--r--arch/powerpc/kvm/emulate.c59
-rw-r--r--arch/powerpc/kvm/powerpc.c33
8 files changed, 115 insertions, 70 deletions
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index bfd0c9912da5..66c75cddaec6 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -330,7 +330,7 @@ struct kvm_vcpu_arch {
330 u32 tbl; 330 u32 tbl;
331 u32 tbu; 331 u32 tbu;
332 u32 tcr; 332 u32 tcr;
333 u32 tsr; 333 ulong tsr; /* we need to perform set/clr_bits() which requires ulong */
334 u32 ivor[64]; 334 u32 ivor[64];
335 ulong ivpr; 335 ulong ivpr;
336 u32 pvr; 336 u32 pvr;
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index c089927f64cc..5192c2e70583 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -66,6 +66,7 @@ extern int kvmppc_emulate_instruction(struct kvm_run *run,
66extern int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu); 66extern int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu);
67extern void kvmppc_emulate_dec(struct kvm_vcpu *vcpu); 67extern void kvmppc_emulate_dec(struct kvm_vcpu *vcpu);
68extern u32 kvmppc_get_dec(struct kvm_vcpu *vcpu, u64 tb); 68extern u32 kvmppc_get_dec(struct kvm_vcpu *vcpu, u64 tb);
69extern void kvmppc_decrementer_func(unsigned long data);
69extern int kvmppc_sanity_check(struct kvm_vcpu *vcpu); 70extern int kvmppc_sanity_check(struct kvm_vcpu *vcpu);
70 71
71/* Core-specific hooks */ 72/* Core-specific hooks */
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
index 5398744cd773..6bf7e0582c5a 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -515,3 +515,11 @@ out:
515 mutex_unlock(&kvm->slots_lock); 515 mutex_unlock(&kvm->slots_lock);
516 return r; 516 return r;
517} 517}
518
519void kvmppc_decrementer_func(unsigned long data)
520{
521 struct kvm_vcpu *vcpu = (struct kvm_vcpu *)data;
522
523 kvmppc_core_queue_dec(vcpu);
524 kvm_vcpu_kick(vcpu);
525}
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index 50803dd0b8f2..9e41f45d07ed 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -252,9 +252,11 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
252 allowed = vcpu->arch.shared->msr & MSR_ME; 252 allowed = vcpu->arch.shared->msr & MSR_ME;
253 msr_mask = 0; 253 msr_mask = 0;
254 break; 254 break;
255 case BOOKE_IRQPRIO_EXTERNAL:
256 case BOOKE_IRQPRIO_DECREMENTER: 255 case BOOKE_IRQPRIO_DECREMENTER:
257 case BOOKE_IRQPRIO_FIT: 256 case BOOKE_IRQPRIO_FIT:
257 keep_irq = true;
258 /* fall through */
259 case BOOKE_IRQPRIO_EXTERNAL:
258 allowed = vcpu->arch.shared->msr & MSR_EE; 260 allowed = vcpu->arch.shared->msr & MSR_EE;
259 allowed = allowed && !crit; 261 allowed = allowed && !crit;
260 msr_mask = MSR_CE|MSR_ME|MSR_DE; 262 msr_mask = MSR_CE|MSR_ME|MSR_DE;
@@ -282,11 +284,26 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
282 return allowed; 284 return allowed;
283} 285}
284 286
287static void update_timer_ints(struct kvm_vcpu *vcpu)
288{
289 if ((vcpu->arch.tcr & TCR_DIE) && (vcpu->arch.tsr & TSR_DIS))
290 kvmppc_core_queue_dec(vcpu);
291 else
292 kvmppc_core_dequeue_dec(vcpu);
293}
294
285static void kvmppc_core_check_exceptions(struct kvm_vcpu *vcpu) 295static void kvmppc_core_check_exceptions(struct kvm_vcpu *vcpu)
286{ 296{
287 unsigned long *pending = &vcpu->arch.pending_exceptions; 297 unsigned long *pending = &vcpu->arch.pending_exceptions;
288 unsigned int priority; 298 unsigned int priority;
289 299
300 if (vcpu->requests) {
301 if (kvm_check_request(KVM_REQ_PENDING_TIMER, vcpu)) {
302 smp_mb();
303 update_timer_ints(vcpu);
304 }
305 }
306
290 priority = __ffs(*pending); 307 priority = __ffs(*pending);
291 while (priority <= BOOKE_IRQPRIO_MAX) { 308 while (priority <= BOOKE_IRQPRIO_MAX) {
292 if (kvmppc_booke_irqprio_deliver(vcpu, priority)) 309 if (kvmppc_booke_irqprio_deliver(vcpu, priority))
@@ -749,25 +766,16 @@ static int set_sregs_base(struct kvm_vcpu *vcpu,
749 vcpu->arch.shared->esr = sregs->u.e.esr; 766 vcpu->arch.shared->esr = sregs->u.e.esr;
750 vcpu->arch.shared->dar = sregs->u.e.dear; 767 vcpu->arch.shared->dar = sregs->u.e.dear;
751 vcpu->arch.vrsave = sregs->u.e.vrsave; 768 vcpu->arch.vrsave = sregs->u.e.vrsave;
752 vcpu->arch.tcr = sregs->u.e.tcr; 769 kvmppc_set_tcr(vcpu, sregs->u.e.tcr);
753 770
754 if (sregs->u.e.update_special & KVM_SREGS_E_UPDATE_DEC) 771 if (sregs->u.e.update_special & KVM_SREGS_E_UPDATE_DEC) {
755 vcpu->arch.dec = sregs->u.e.dec; 772 vcpu->arch.dec = sregs->u.e.dec;
756 773 kvmppc_emulate_dec(vcpu);
757 kvmppc_emulate_dec(vcpu); 774 }
758 775
759 if (sregs->u.e.update_special & KVM_SREGS_E_UPDATE_TSR) { 776 if (sregs->u.e.update_special & KVM_SREGS_E_UPDATE_TSR) {
760 /* 777 vcpu->arch.tsr = sregs->u.e.tsr;
761 * FIXME: existing KVM timer handling is incomplete. 778 update_timer_ints(vcpu);
762 * TSR cannot be read by the guest, and its value in
763 * vcpu->arch is always zero. For now, just handle
764 * the case where the caller is trying to inject a
765 * decrementer interrupt.
766 */
767
768 if ((sregs->u.e.tsr & TSR_DIS) &&
769 (vcpu->arch.tcr & TCR_DIE))
770 kvmppc_core_queue_dec(vcpu);
771 } 779 }
772 780
773 return 0; 781 return 0;
@@ -923,6 +931,33 @@ void kvmppc_core_destroy_vm(struct kvm *kvm)
923{ 931{
924} 932}
925 933
934void kvmppc_set_tcr(struct kvm_vcpu *vcpu, u32 new_tcr)
935{
936 vcpu->arch.tcr = new_tcr;
937 update_timer_ints(vcpu);
938}
939
940void kvmppc_set_tsr_bits(struct kvm_vcpu *vcpu, u32 tsr_bits)
941{
942 set_bits(tsr_bits, &vcpu->arch.tsr);
943 smp_wmb();
944 kvm_make_request(KVM_REQ_PENDING_TIMER, vcpu);
945 kvm_vcpu_kick(vcpu);
946}
947
948void kvmppc_clr_tsr_bits(struct kvm_vcpu *vcpu, u32 tsr_bits)
949{
950 clear_bits(tsr_bits, &vcpu->arch.tsr);
951 update_timer_ints(vcpu);
952}
953
954void kvmppc_decrementer_func(unsigned long data)
955{
956 struct kvm_vcpu *vcpu = (struct kvm_vcpu *)data;
957
958 kvmppc_set_tsr_bits(vcpu, TSR_DIS);
959}
960
926int __init kvmppc_booke_init(void) 961int __init kvmppc_booke_init(void)
927{ 962{
928 unsigned long ivor[16]; 963 unsigned long ivor[16];
diff --git a/arch/powerpc/kvm/booke.h b/arch/powerpc/kvm/booke.h
index 8e1fe33d64e5..2fe202705a3f 100644
--- a/arch/powerpc/kvm/booke.h
+++ b/arch/powerpc/kvm/booke.h
@@ -55,6 +55,10 @@ extern unsigned long kvmppc_booke_handlers;
55void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr); 55void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr);
56void kvmppc_mmu_msr_notify(struct kvm_vcpu *vcpu, u32 old_msr); 56void kvmppc_mmu_msr_notify(struct kvm_vcpu *vcpu, u32 old_msr);
57 57
58void kvmppc_set_tcr(struct kvm_vcpu *vcpu, u32 new_tcr);
59void kvmppc_set_tsr_bits(struct kvm_vcpu *vcpu, u32 tsr_bits);
60void kvmppc_clr_tsr_bits(struct kvm_vcpu *vcpu, u32 tsr_bits);
61
58int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, 62int kvmppc_booke_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
59 unsigned int inst, int *advance); 63 unsigned int inst, int *advance);
60int kvmppc_booke_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt); 64int kvmppc_booke_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt);
diff --git a/arch/powerpc/kvm/booke_emulate.c b/arch/powerpc/kvm/booke_emulate.c
index bae9288ac1e1..3e652da36534 100644
--- a/arch/powerpc/kvm/booke_emulate.c
+++ b/arch/powerpc/kvm/booke_emulate.c
@@ -13,6 +13,7 @@
13 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 13 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
14 * 14 *
15 * Copyright IBM Corp. 2008 15 * Copyright IBM Corp. 2008
16 * Copyright 2011 Freescale Semiconductor, Inc.
16 * 17 *
17 * Authors: Hollis Blanchard <hollisb@us.ibm.com> 18 * Authors: Hollis Blanchard <hollisb@us.ibm.com>
18 */ 19 */
@@ -115,10 +116,10 @@ int kvmppc_booke_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
115 case SPRN_DBSR: 116 case SPRN_DBSR:
116 vcpu->arch.dbsr &= ~spr_val; break; 117 vcpu->arch.dbsr &= ~spr_val; break;
117 case SPRN_TSR: 118 case SPRN_TSR:
118 vcpu->arch.tsr &= ~spr_val; break; 119 kvmppc_clr_tsr_bits(vcpu, spr_val);
120 break;
119 case SPRN_TCR: 121 case SPRN_TCR:
120 vcpu->arch.tcr = spr_val; 122 kvmppc_set_tcr(vcpu, spr_val);
121 kvmppc_emulate_dec(vcpu);
122 break; 123 break;
123 124
124 /* Note: SPRG4-7 are user-readable. These values are 125 /* Note: SPRG4-7 are user-readable. These values are
@@ -209,6 +210,10 @@ int kvmppc_booke_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
209 kvmppc_set_gpr(vcpu, rt, vcpu->arch.dbcr1); break; 210 kvmppc_set_gpr(vcpu, rt, vcpu->arch.dbcr1); break;
210 case SPRN_DBSR: 211 case SPRN_DBSR:
211 kvmppc_set_gpr(vcpu, rt, vcpu->arch.dbsr); break; 212 kvmppc_set_gpr(vcpu, rt, vcpu->arch.dbsr); break;
213 case SPRN_TSR:
214 kvmppc_set_gpr(vcpu, rt, vcpu->arch.tsr); break;
215 case SPRN_TCR:
216 kvmppc_set_gpr(vcpu, rt, vcpu->arch.tcr); break;
212 217
213 case SPRN_IVOR0: 218 case SPRN_IVOR0:
214 kvmppc_set_gpr(vcpu, rt, vcpu->arch.ivor[BOOKE_IRQPRIO_CRITICAL]); 219 kvmppc_set_gpr(vcpu, rt, vcpu->arch.ivor[BOOKE_IRQPRIO_CRITICAL]);
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c
index bda052e2264b..968f40101883 100644
--- a/arch/powerpc/kvm/emulate.c
+++ b/arch/powerpc/kvm/emulate.c
@@ -13,6 +13,7 @@
13 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 13 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
14 * 14 *
15 * Copyright IBM Corp. 2007 15 * Copyright IBM Corp. 2007
16 * Copyright 2011 Freescale Semiconductor, Inc.
16 * 17 *
17 * Authors: Hollis Blanchard <hollisb@us.ibm.com> 18 * Authors: Hollis Blanchard <hollisb@us.ibm.com>
18 */ 19 */
@@ -69,57 +70,55 @@
69#define OP_STH 44 70#define OP_STH 44
70#define OP_STHU 45 71#define OP_STHU 45
71 72
72#ifdef CONFIG_PPC_BOOK3S
73static int kvmppc_dec_enabled(struct kvm_vcpu *vcpu)
74{
75 return 1;
76}
77#else
78static int kvmppc_dec_enabled(struct kvm_vcpu *vcpu)
79{
80 /* On BOOKE, DEC = 0 is as good as decrementer not enabled */
81 return (vcpu->arch.tcr & TCR_DIE) && vcpu->arch.dec;
82}
83#endif
84
85void kvmppc_emulate_dec(struct kvm_vcpu *vcpu) 73void kvmppc_emulate_dec(struct kvm_vcpu *vcpu)
86{ 74{
87 unsigned long dec_nsec; 75 unsigned long dec_nsec;
88 unsigned long long dec_time; 76 unsigned long long dec_time;
89 77
90 pr_debug("mtDEC: %x\n", vcpu->arch.dec); 78 pr_debug("mtDEC: %x\n", vcpu->arch.dec);
79 hrtimer_try_to_cancel(&vcpu->arch.dec_timer);
80
91#ifdef CONFIG_PPC_BOOK3S 81#ifdef CONFIG_PPC_BOOK3S
92 /* mtdec lowers the interrupt line when positive. */ 82 /* mtdec lowers the interrupt line when positive. */
93 kvmppc_core_dequeue_dec(vcpu); 83 kvmppc_core_dequeue_dec(vcpu);
94 84
95 /* POWER4+ triggers a dec interrupt if the value is < 0 */ 85 /* POWER4+ triggers a dec interrupt if the value is < 0 */
96 if (vcpu->arch.dec & 0x80000000) { 86 if (vcpu->arch.dec & 0x80000000) {
97 hrtimer_try_to_cancel(&vcpu->arch.dec_timer);
98 kvmppc_core_queue_dec(vcpu); 87 kvmppc_core_queue_dec(vcpu);
99 return; 88 return;
100 } 89 }
101#endif 90#endif
102 if (kvmppc_dec_enabled(vcpu)) { 91
103 /* The decrementer ticks at the same rate as the timebase, so 92#ifdef CONFIG_BOOKE
104 * that's how we convert the guest DEC value to the number of 93 /* On BOOKE, DEC = 0 is as good as decrementer not enabled */
105 * host ticks. */ 94 if (vcpu->arch.dec == 0)
106 95 return;
107 hrtimer_try_to_cancel(&vcpu->arch.dec_timer); 96#endif
108 dec_time = vcpu->arch.dec; 97
109 dec_time *= 1000; 98 /*
110 do_div(dec_time, tb_ticks_per_usec); 99 * The decrementer ticks at the same rate as the timebase, so
111 dec_nsec = do_div(dec_time, NSEC_PER_SEC); 100 * that's how we convert the guest DEC value to the number of
112 hrtimer_start(&vcpu->arch.dec_timer, 101 * host ticks.
113 ktime_set(dec_time, dec_nsec), HRTIMER_MODE_REL); 102 */
114 vcpu->arch.dec_jiffies = get_tb(); 103
115 } else { 104 dec_time = vcpu->arch.dec;
116 hrtimer_try_to_cancel(&vcpu->arch.dec_timer); 105 dec_time *= 1000;
117 } 106 do_div(dec_time, tb_ticks_per_usec);
107 dec_nsec = do_div(dec_time, NSEC_PER_SEC);
108 hrtimer_start(&vcpu->arch.dec_timer,
109 ktime_set(dec_time, dec_nsec), HRTIMER_MODE_REL);
110 vcpu->arch.dec_jiffies = get_tb();
118} 111}
119 112
120u32 kvmppc_get_dec(struct kvm_vcpu *vcpu, u64 tb) 113u32 kvmppc_get_dec(struct kvm_vcpu *vcpu, u64 tb)
121{ 114{
122 u64 jd = tb - vcpu->arch.dec_jiffies; 115 u64 jd = tb - vcpu->arch.dec_jiffies;
116
117#ifdef CONFIG_BOOKE
118 if (vcpu->arch.dec < jd)
119 return 0;
120#endif
121
123 return vcpu->arch.dec - jd; 122 return vcpu->arch.dec - jd;
124} 123}
125 124
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index d02e4c84e213..fd8d3b16eaf3 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -39,7 +39,8 @@
39int kvm_arch_vcpu_runnable(struct kvm_vcpu *v) 39int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
40{ 40{
41 return !(v->arch.shared->msr & MSR_WE) || 41 return !(v->arch.shared->msr & MSR_WE) ||
42 !!(v->arch.pending_exceptions); 42 !!(v->arch.pending_exceptions) ||
43 v->requests;
43} 44}
44 45
45int kvmppc_kvm_pv(struct kvm_vcpu *vcpu) 46int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
@@ -311,18 +312,6 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
311 return kvmppc_core_pending_dec(vcpu); 312 return kvmppc_core_pending_dec(vcpu);
312} 313}
313 314
314static void kvmppc_decrementer_func(unsigned long data)
315{
316 struct kvm_vcpu *vcpu = (struct kvm_vcpu *)data;
317
318 kvmppc_core_queue_dec(vcpu);
319
320 if (waitqueue_active(vcpu->arch.wqp)) {
321 wake_up_interruptible(vcpu->arch.wqp);
322 vcpu->stat.halt_wakeup++;
323 }
324}
325
326/* 315/*
327 * low level hrtimer wake routine. Because this runs in hardirq context 316 * low level hrtimer wake routine. Because this runs in hardirq context
328 * we schedule a tasklet to do the real work. 317 * we schedule a tasklet to do the real work.
@@ -567,6 +556,16 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
567 return r; 556 return r;
568} 557}
569 558
559void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
560{
561 if (waitqueue_active(&vcpu->wq)) {
562 wake_up_interruptible(vcpu->arch.wqp);
563 vcpu->stat.halt_wakeup++;
564 } else if (vcpu->cpu != -1) {
565 smp_send_reschedule(vcpu->cpu);
566 }
567}
568
570int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq) 569int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq)
571{ 570{
572 if (irq->irq == KVM_INTERRUPT_UNSET) { 571 if (irq->irq == KVM_INTERRUPT_UNSET) {
@@ -575,13 +574,7 @@ int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq)
575 } 574 }
576 575
577 kvmppc_core_queue_external(vcpu, irq); 576 kvmppc_core_queue_external(vcpu, irq);
578 577 kvm_vcpu_kick(vcpu);
579 if (waitqueue_active(vcpu->arch.wqp)) {
580 wake_up_interruptible(vcpu->arch.wqp);
581 vcpu->stat.halt_wakeup++;
582 } else if (vcpu->cpu != -1) {
583 smp_send_reschedule(vcpu->cpu);
584 }
585 578
586 return 0; 579 return 0;
587} 580}