Commit bee038a6 authored by Christoffer Dall's avatar Christoffer Dall Committed by Marc Zyngier

KVM: arm/arm64: Rework the timer code to use a timer_map

We are currently emulating two timers in two different ways.  When we
add support for nested virtualization in the future, we are going to be
emulating either two timers in two diffferent ways, or four timers in a
single way.

We need a unified data structure to keep track of how we map virtual
state to physical state and we need to cleanup some of the timer code to
operate more independently on a struct arch_timer_context instead of
trying to consider the global state of the VCPU and recomputing all
state.

Co-written with Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
Signed-off-by: default avatarChristoffer Dall <christoffer.dall@arm.com>
parent 9e01dc76
...@@ -51,11 +51,24 @@ struct arch_timer_context { ...@@ -51,11 +51,24 @@ struct arch_timer_context {
/* Emulated Timer (may be unused) */ /* Emulated Timer (may be unused) */
struct hrtimer hrtimer; struct hrtimer hrtimer;
/*
* We have multiple paths which can save/restore the timer state onto
* the hardware, so we need some way of keeping track of where the
* latest state is.
*/
bool loaded;
/* Duplicated state from arch_timer.c for convenience */ /* Duplicated state from arch_timer.c for convenience */
u32 host_timer_irq; u32 host_timer_irq;
u32 host_timer_irq_flags; u32 host_timer_irq_flags;
}; };
struct timer_map {
struct arch_timer_context *direct_vtimer;
struct arch_timer_context *direct_ptimer;
struct arch_timer_context *emul_ptimer;
};
struct arch_timer_cpu { struct arch_timer_cpu {
struct arch_timer_context timers[NR_KVM_TIMERS]; struct arch_timer_context timers[NR_KVM_TIMERS];
...@@ -64,16 +77,6 @@ struct arch_timer_cpu { ...@@ -64,16 +77,6 @@ struct arch_timer_cpu {
/* Is the timer enabled */ /* Is the timer enabled */
bool enabled; bool enabled;
/*
* We have multiple paths which can save/restore the timer state
* onto the hardware, so we need some way of keeping track of
* where the latest state is.
*
* loaded == true: State is loaded on the hardware registers.
* loaded == false: State is stored in memory.
*/
bool loaded;
}; };
int kvm_timer_hyp_init(bool); int kvm_timer_hyp_init(bool);
......
This diff is collapsed.
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#if !defined(_TRACE_KVM_H) || defined(TRACE_HEADER_MULTI_READ) #if !defined(_TRACE_KVM_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_KVM_H #define _TRACE_KVM_H
#include <kvm/arm_arch_timer.h>
#include <linux/tracepoint.h> #include <linux/tracepoint.h>
#undef TRACE_SYSTEM #undef TRACE_SYSTEM
...@@ -262,6 +263,110 @@ TRACE_EVENT(kvm_timer_update_irq, ...@@ -262,6 +263,110 @@ TRACE_EVENT(kvm_timer_update_irq,
__entry->vcpu_id, __entry->irq, __entry->level) __entry->vcpu_id, __entry->irq, __entry->level)
); );
TRACE_EVENT(kvm_get_timer_map,
TP_PROTO(unsigned long vcpu_id, struct timer_map *map),
TP_ARGS(vcpu_id, map),
TP_STRUCT__entry(
__field( unsigned long, vcpu_id )
__field( int, direct_vtimer )
__field( int, direct_ptimer )
__field( int, emul_ptimer )
),
TP_fast_assign(
__entry->vcpu_id = vcpu_id;
__entry->direct_vtimer = arch_timer_ctx_index(map->direct_vtimer);
__entry->direct_ptimer =
(map->direct_ptimer) ? arch_timer_ctx_index(map->direct_ptimer) : -1;
__entry->emul_ptimer =
(map->emul_ptimer) ? arch_timer_ctx_index(map->emul_ptimer) : -1;
),
TP_printk("VCPU: %ld, dv: %d, dp: %d, ep: %d",
__entry->vcpu_id,
__entry->direct_vtimer,
__entry->direct_ptimer,
__entry->emul_ptimer)
);
TRACE_EVENT(kvm_timer_save_state,
TP_PROTO(struct arch_timer_context *ctx),
TP_ARGS(ctx),
TP_STRUCT__entry(
__field( unsigned long, ctl )
__field( unsigned long long, cval )
__field( int, timer_idx )
),
TP_fast_assign(
__entry->ctl = ctx->cnt_ctl;
__entry->cval = ctx->cnt_cval;
__entry->timer_idx = arch_timer_ctx_index(ctx);
),
TP_printk(" CTL: %#08lx CVAL: %#16llx arch_timer_ctx_index: %d",
__entry->ctl,
__entry->cval,
__entry->timer_idx)
);
TRACE_EVENT(kvm_timer_restore_state,
TP_PROTO(struct arch_timer_context *ctx),
TP_ARGS(ctx),
TP_STRUCT__entry(
__field( unsigned long, ctl )
__field( unsigned long long, cval )
__field( int, timer_idx )
),
TP_fast_assign(
__entry->ctl = ctx->cnt_ctl;
__entry->cval = ctx->cnt_cval;
__entry->timer_idx = arch_timer_ctx_index(ctx);
),
TP_printk("CTL: %#08lx CVAL: %#16llx arch_timer_ctx_index: %d",
__entry->ctl,
__entry->cval,
__entry->timer_idx)
);
TRACE_EVENT(kvm_timer_hrtimer_expire,
TP_PROTO(struct arch_timer_context *ctx),
TP_ARGS(ctx),
TP_STRUCT__entry(
__field( int, timer_idx )
),
TP_fast_assign(
__entry->timer_idx = arch_timer_ctx_index(ctx);
),
TP_printk("arch_timer_ctx_index: %d", __entry->timer_idx)
);
TRACE_EVENT(kvm_timer_emulate,
TP_PROTO(struct arch_timer_context *ctx, bool should_fire),
TP_ARGS(ctx, should_fire),
TP_STRUCT__entry(
__field( int, timer_idx )
__field( bool, should_fire )
),
TP_fast_assign(
__entry->timer_idx = arch_timer_ctx_index(ctx);
__entry->should_fire = should_fire;
),
TP_printk("arch_timer_ctx_index: %d (should_fire: %d)",
__entry->timer_idx, __entry->should_fire)
);
#endif /* _TRACE_KVM_H */ #endif /* _TRACE_KVM_H */
#undef TRACE_INCLUDE_PATH #undef TRACE_INCLUDE_PATH
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment