On 27.08.2011, at 01:31, Scott Wood wrote:
> From: Liu Yu <[email protected]>
>
> 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.
>
> Signed-off-by: Liu Yu <[email protected]>
> [scott: added dequeue in kvmppc_booke_irqprio_deliver, and dec stop-at-zero]
> Signed-off-by: Scott Wood <[email protected]>
> ---
> arch/powerpc/include/asm/kvm_host.h | 2 +-
> arch/powerpc/include/asm/kvm_ppc.h | 11 +++++
> arch/powerpc/kvm/book3s.c | 8 ++++
> arch/powerpc/kvm/booke.c | 80 +++++++++++++++++++++++++++--------
> arch/powerpc/kvm/booke.h | 4 ++
> arch/powerpc/kvm/booke_emulate.c | 11 ++++-
> arch/powerpc/kvm/emulate.c | 45 ++++++++-----------
> arch/powerpc/kvm/powerpc.c | 20 +--------
> 8 files changed, 114 insertions(+), 67 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/kvm_host.h
> b/arch/powerpc/include/asm/kvm_host.h
> index 3305af4..ea08c79 100644
> --- a/arch/powerpc/include/asm/kvm_host.h
> +++ b/arch/powerpc/include/asm/kvm_host.h
> @@ -334,7 +334,7 @@ struct kvm_vcpu_arch {
> u32 tbl;
> u32 tbu;
> u32 tcr;
> - u32 tsr;
> + ulong tsr; /* we need to perform set/clr_bits() which requires ulong */
> u32 ivor[64];
> ulong ivpr;
> u32 pvr;
> diff --git a/arch/powerpc/include/asm/kvm_ppc.h
> b/arch/powerpc/include/asm/kvm_ppc.h
> index bdaa6c8..ddaa615 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,
> extern int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu);
> extern void kvmppc_emulate_dec(struct kvm_vcpu *vcpu);
> extern u32 kvmppc_get_dec(struct kvm_vcpu *vcpu, u64 tb);
> +extern void kvmppc_decrementer_func(unsigned long data);
>
> /* Core-specific hooks */
>
> @@ -197,4 +198,14 @@ int kvm_vcpu_ioctl_config_tlb(struct kvm_vcpu *vcpu,
> int kvm_vcpu_ioctl_dirty_tlb(struct kvm_vcpu *vcpu,
> struct kvm_dirty_tlb *cfg);
>
> +static inline void kvmppc_wakeup_vcpu(struct kvm_vcpu *vcpu)
> +{
> + if (waitqueue_active(&vcpu->wq)) {
> + wake_up_interruptible(&vcpu->wq);
> + vcpu->stat.halt_wakeup++;
> + } else if (vcpu->cpu != -1) {
> + smp_send_reschedule(vcpu->cpu);
> + }
> +}
> +
> #endif /* __POWERPC_KVM_PPC_H__ */
> diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
> index f68a34d..b057856 100644
> --- a/arch/powerpc/kvm/book3s.c
> +++ b/arch/powerpc/kvm/book3s.c
> @@ -514,3 +514,11 @@ out:
> mutex_unlock(&kvm->slots_lock);
> return r;
> }
> +
> +void kvmppc_decrementer_func(unsigned long data)
> +{
> + struct kvm_vcpu *vcpu = (struct kvm_vcpu *)data;
> +
> + kvmppc_core_queue_dec(vcpu);
> + kvmppc_wakeup_vcpu(vcpu);
> +}
> diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
> index 0ed62c1..502f9ff 100644
> --- a/arch/powerpc/kvm/booke.c
> +++ b/arch/powerpc/kvm/booke.c
> @@ -205,7 +205,8 @@ void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu,
> static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
> unsigned int priority)
> {
> - int allowed = 0;
> + int allowed = 1;
> + int dequeue = 0;
> ulong uninitialized_var(msr_mask);
> bool update_esr = false, update_dear = false;
> ulong crit_raw = vcpu->arch.shared->critical;
> @@ -258,10 +259,15 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu
> *vcpu,
> allowed = vcpu->arch.shared->msr & MSR_ME;
> msr_mask = 0;
> break;
> - case BOOKE_IRQPRIO_EXTERNAL:
> case BOOKE_IRQPRIO_DECREMENTER:
> + if (!(vcpu->arch.tcr & TCR_DIE)) {
> + allowed = 0;
> + dequeue = 1;
> + }
> + /* fall through */
> + case BOOKE_IRQPRIO_EXTERNAL:
> case BOOKE_IRQPRIO_FIT:
> - allowed = vcpu->arch.shared->msr & MSR_EE;
> + allowed = allowed && vcpu->arch.shared->msr & MSR_EE;
> allowed = allowed && !crit;
> msr_mask = MSR_CE|MSR_ME|MSR_DE;
> break;
> @@ -269,6 +275,8 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu
> *vcpu,
> allowed = vcpu->arch.shared->msr & MSR_DE;
> msr_mask = MSR_ME;
> break;
> + default:
> + allowed = 0;
> }
>
> if (allowed) {
> @@ -283,6 +291,9 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu
> *vcpu,
>
> if (!keep_irq)
> clear_bit(priority, &vcpu->arch.pending_exceptions);
> + } else if (dequeue) {
> + /* Should only happen due to races with masking */
> + clear_bit(priority, &vcpu->arch.pending_exceptions);
> }
>
> return allowed;
> @@ -721,25 +732,16 @@ static int set_sregs_base(struct kvm_vcpu *vcpu,
> vcpu->arch.shared->esr = sregs->u.e.esr;
> vcpu->arch.shared->dar = sregs->u.e.dear;
> vcpu->arch.vrsave = sregs->u.e.vrsave;
> - vcpu->arch.tcr = sregs->u.e.tcr;
> + kvmppc_set_tcr(vcpu, sregs->u.e.tcr);
>
> - if (sregs->u.e.update_special & KVM_SREGS_E_UPDATE_DEC)
> + if (sregs->u.e.update_special & KVM_SREGS_E_UPDATE_DEC) {
> vcpu->arch.dec = sregs->u.e.dec;
> -
> - kvmppc_emulate_dec(vcpu);
> + kvmppc_emulate_dec(vcpu);
> + }
>
> if (sregs->u.e.update_special & KVM_SREGS_E_UPDATE_TSR) {
> - /*
> - * FIXME: existing KVM timer handling is incomplete.
> - * TSR cannot be read by the guest, and its value in
> - * vcpu->arch is always zero. For now, just handle
> - * the case where the caller is trying to inject a
> - * decrementer interrupt.
> - */
> -
> - if ((sregs->u.e.tsr & TSR_DIS) &&
> - (vcpu->arch.tcr & TCR_DIE))
> - kvmppc_core_queue_dec(vcpu);
> + kvmppc_clr_tsr_bits(vcpu, ~0);
> + kvmppc_set_tsr_bits(vcpu, sregs->u.e.tsr);
> }
>
> return 0;
> @@ -895,6 +897,48 @@ void kvmppc_core_destroy_vm(struct kvm *kvm)
> {
> }
>
> +void kvmppc_set_tcr(struct kvm_vcpu *vcpu, u32 new_tcr)
> +{
> + vcpu->arch.tcr = new_tcr;
> + smp_wmb();
> +
> + /*
> + * Since TCR changed, we need to check
> + * if blocked interrupts are deliverable.
> + */
> + if ((new_tcr & TCR_DIE) && (vcpu->arch.tsr & TSR_DIS)) {
> + kvmppc_core_queue_dec(vcpu);
> + kvmppc_wakeup_vcpu(vcpu);
> + }
> +}
> +
> +void kvmppc_set_tsr_bits(struct kvm_vcpu *vcpu, u32 tsr_bits)
> +{
> + set_bits(tsr_bits, &vcpu->arch.tsr);
I'm still missing the point why you need set_bits/clear_bits. Can't you just
use |= and &= ~ like everyone else? :)
> + smp_wmb();
> +
> + if ((tsr_bits & TSR_DIS) && (vcpu->arch.tcr & TCR_DIE)) {
> + kvmppc_core_queue_dec(vcpu);
> + kvmppc_wakeup_vcpu(vcpu);
> + }
Please combine into a function and call that for updating tsr and tcr.
Alex
--
To unsubscribe from this list: send the line "unsubscribe kvm-ppc" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html