Skip to content

Commit

Permalink
ARM: KVM: Allow host virt timer irq to be different from guest timer …
Browse files Browse the repository at this point in the history
…virt irq

The arch_timer irq numbers (or PPI numbers) are implementation dependent,
so the host virtual timer irq number can be different from guest virtual
timer irq number.

This patch ensures that host virtual timer irq number is read from DTB and
guest virtual timer irq is determined based on vcpu target type.

Signed-off-by: Anup Patel <[email protected]>
Signed-off-by: Pranavkumar Sawargaonkar <[email protected]>
Signed-off-by: Christoffer Dall <[email protected]>
  • Loading branch information
Anup Patel authored and chazy committed Jun 26, 2013
1 parent 87d41fb commit 5ae7f87
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 9 deletions.
12 changes: 12 additions & 0 deletions arch/arm/kvm/reset.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
#include <asm/kvm_arm.h>
#include <asm/kvm_coproc.h>

#include <kvm/arm_arch_timer.h>

/******************************************************************************
* Cortex-A15 Reset Values
*/
Expand All @@ -37,6 +39,11 @@ static struct kvm_regs a15_regs_reset = {
.usr_regs.ARM_cpsr = SVC_MODE | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT,
};

static const struct kvm_irq_level a15_vtimer_irq = {
.irq = 27,
.level = 1,
};


/*******************************************************************************
* Exported reset function
Expand All @@ -52,13 +59,15 @@ static struct kvm_regs a15_regs_reset = {
int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
{
struct kvm_regs *cpu_reset;
const struct kvm_irq_level *cpu_vtimer_irq;

switch (vcpu->arch.target) {
case KVM_ARM_TARGET_CORTEX_A15:
if (vcpu->vcpu_id > a15_max_cpu_idx)
return -EINVAL;
cpu_reset = &a15_regs_reset;
vcpu->arch.midr = read_cpuid_id();
cpu_vtimer_irq = &a15_vtimer_irq;
break;
default:
return -ENODEV;
Expand All @@ -70,5 +79,8 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
/* Reset CP15 registers */
kvm_reset_coprocs(vcpu);

/* Reset arch_timer context */
kvm_timer_vcpu_reset(vcpu, cpu_vtimer_irq);

return 0;
}
4 changes: 4 additions & 0 deletions include/kvm/arm_arch_timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ struct arch_timer_cpu {
#ifdef CONFIG_KVM_ARM_TIMER
int kvm_timer_hyp_init(void);
int kvm_timer_init(struct kvm *kvm);
void kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
const struct kvm_irq_level *irq);
void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu);
void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu);
void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu);
Expand All @@ -76,6 +78,8 @@ static inline int kvm_timer_init(struct kvm *kvm)
return 0;
}

static inline void kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
const struct kvm_irq_level *irq) {}
static inline void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu) {}
static inline void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu) {}
static inline void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu) {}
Expand Down
29 changes: 20 additions & 9 deletions virt/kvm/arm/arch_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@

static struct timecounter *timecounter;
static struct workqueue_struct *wqueue;
static struct kvm_irq_level timer_irq = {
.level = 1,
};
static unsigned int host_vtimer_irq;

static cycle_t kvm_phys_timer_read(void)
{
Expand Down Expand Up @@ -67,8 +65,8 @@ static void kvm_timer_inject_irq(struct kvm_vcpu *vcpu)

timer->cntv_ctl |= ARCH_TIMER_CTRL_IT_MASK;
kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id,
vcpu->arch.timer_cpu.irq->irq,
vcpu->arch.timer_cpu.irq->level);
timer->irq->irq,
timer->irq->level);
}

static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
Expand Down Expand Up @@ -156,19 +154,32 @@ void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
timer_arm(timer, ns);
}

void kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu,
const struct kvm_irq_level *irq)
{
struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;

/*
* The vcpu timer irq number cannot be determined in
* kvm_timer_vcpu_init() because it is called much before
* kvm_vcpu_set_target(). To handle this, we determine
* vcpu timer irq number when the vcpu is reset.
*/
timer->irq = irq;
}

void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu)
{
struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;

INIT_WORK(&timer->expired, kvm_timer_inject_irq_work);
hrtimer_init(&timer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
timer->timer.function = kvm_timer_expire;
timer->irq = &timer_irq;
}

static void kvm_timer_init_interrupt(void *info)
{
enable_percpu_irq(timer_irq.irq, 0);
enable_percpu_irq(host_vtimer_irq, 0);
}


Expand All @@ -182,7 +193,7 @@ static int kvm_timer_cpu_notify(struct notifier_block *self,
break;
case CPU_DYING:
case CPU_DYING_FROZEN:
disable_percpu_irq(timer_irq.irq);
disable_percpu_irq(host_vtimer_irq);
break;
}

Expand Down Expand Up @@ -229,7 +240,7 @@ int kvm_timer_hyp_init(void)
goto out;
}

timer_irq.irq = ppi;
host_vtimer_irq = ppi;

err = register_cpu_notifier(&kvm_timer_cpu_nb);
if (err) {
Expand Down

0 comments on commit 5ae7f87

Please sign in to comment.