162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2012 ARM Ltd.
462306a36Sopenharmony_ci * Author: Marc Zyngier <marc.zyngier@arm.com>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#ifndef __ASM_ARM_KVM_ARCH_TIMER_H
862306a36Sopenharmony_ci#define __ASM_ARM_KVM_ARCH_TIMER_H
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/clocksource.h>
1162306a36Sopenharmony_ci#include <linux/hrtimer.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cienum kvm_arch_timers {
1462306a36Sopenharmony_ci	TIMER_PTIMER,
1562306a36Sopenharmony_ci	TIMER_VTIMER,
1662306a36Sopenharmony_ci	NR_KVM_EL0_TIMERS,
1762306a36Sopenharmony_ci	TIMER_HVTIMER = NR_KVM_EL0_TIMERS,
1862306a36Sopenharmony_ci	TIMER_HPTIMER,
1962306a36Sopenharmony_ci	NR_KVM_TIMERS
2062306a36Sopenharmony_ci};
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cienum kvm_arch_timer_regs {
2362306a36Sopenharmony_ci	TIMER_REG_CNT,
2462306a36Sopenharmony_ci	TIMER_REG_CVAL,
2562306a36Sopenharmony_ci	TIMER_REG_TVAL,
2662306a36Sopenharmony_ci	TIMER_REG_CTL,
2762306a36Sopenharmony_ci	TIMER_REG_VOFF,
2862306a36Sopenharmony_ci};
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistruct arch_timer_offset {
3162306a36Sopenharmony_ci	/*
3262306a36Sopenharmony_ci	 * If set, pointer to one of the offsets in the kvm's offset
3362306a36Sopenharmony_ci	 * structure. If NULL, assume a zero offset.
3462306a36Sopenharmony_ci	 */
3562306a36Sopenharmony_ci	u64	*vm_offset;
3662306a36Sopenharmony_ci	/*
3762306a36Sopenharmony_ci	 * If set, pointer to one of the offsets in the vcpu's sysreg
3862306a36Sopenharmony_ci	 * array. If NULL, assume a zero offset.
3962306a36Sopenharmony_ci	 */
4062306a36Sopenharmony_ci	u64	*vcpu_offset;
4162306a36Sopenharmony_ci};
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistruct arch_timer_vm_data {
4462306a36Sopenharmony_ci	/* Offset applied to the virtual timer/counter */
4562306a36Sopenharmony_ci	u64	voffset;
4662306a36Sopenharmony_ci	/* Offset applied to the physical timer/counter */
4762306a36Sopenharmony_ci	u64	poffset;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	/* The PPI for each timer, global to the VM */
5062306a36Sopenharmony_ci	u8	ppi[NR_KVM_TIMERS];
5162306a36Sopenharmony_ci};
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistruct arch_timer_context {
5462306a36Sopenharmony_ci	struct kvm_vcpu			*vcpu;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	/* Emulated Timer (may be unused) */
5762306a36Sopenharmony_ci	struct hrtimer			hrtimer;
5862306a36Sopenharmony_ci	u64				ns_frac;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	/* Offset for this counter/timer */
6162306a36Sopenharmony_ci	struct arch_timer_offset	offset;
6262306a36Sopenharmony_ci	/*
6362306a36Sopenharmony_ci	 * We have multiple paths which can save/restore the timer state onto
6462306a36Sopenharmony_ci	 * the hardware, so we need some way of keeping track of where the
6562306a36Sopenharmony_ci	 * latest state is.
6662306a36Sopenharmony_ci	 */
6762306a36Sopenharmony_ci	bool				loaded;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	/* Output level of the timer IRQ */
7062306a36Sopenharmony_ci	struct {
7162306a36Sopenharmony_ci		bool			level;
7262306a36Sopenharmony_ci	} irq;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	/* Duplicated state from arch_timer.c for convenience */
7562306a36Sopenharmony_ci	u32				host_timer_irq;
7662306a36Sopenharmony_ci};
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistruct timer_map {
7962306a36Sopenharmony_ci	struct arch_timer_context *direct_vtimer;
8062306a36Sopenharmony_ci	struct arch_timer_context *direct_ptimer;
8162306a36Sopenharmony_ci	struct arch_timer_context *emul_vtimer;
8262306a36Sopenharmony_ci	struct arch_timer_context *emul_ptimer;
8362306a36Sopenharmony_ci};
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_civoid get_timer_map(struct kvm_vcpu *vcpu, struct timer_map *map);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistruct arch_timer_cpu {
8862306a36Sopenharmony_ci	struct arch_timer_context timers[NR_KVM_TIMERS];
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	/* Background timer used when the guest is not running */
9162306a36Sopenharmony_ci	struct hrtimer			bg_timer;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	/* Is the timer enabled */
9462306a36Sopenharmony_ci	bool			enabled;
9562306a36Sopenharmony_ci};
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ciint __init kvm_timer_hyp_init(bool has_gic);
9862306a36Sopenharmony_ciint kvm_timer_enable(struct kvm_vcpu *vcpu);
9962306a36Sopenharmony_ciint kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu);
10062306a36Sopenharmony_civoid kvm_timer_vcpu_init(struct kvm_vcpu *vcpu);
10162306a36Sopenharmony_civoid kvm_timer_sync_user(struct kvm_vcpu *vcpu);
10262306a36Sopenharmony_cibool kvm_timer_should_notify_user(struct kvm_vcpu *vcpu);
10362306a36Sopenharmony_civoid kvm_timer_update_run(struct kvm_vcpu *vcpu);
10462306a36Sopenharmony_civoid kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu);
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_civoid kvm_timer_init_vm(struct kvm *kvm);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ciu64 kvm_arm_timer_get_reg(struct kvm_vcpu *, u64 regid);
10962306a36Sopenharmony_ciint kvm_arm_timer_set_reg(struct kvm_vcpu *, u64 regid, u64 value);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ciint kvm_arm_timer_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);
11262306a36Sopenharmony_ciint kvm_arm_timer_get_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);
11362306a36Sopenharmony_ciint kvm_arm_timer_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ciu64 kvm_phys_timer_read(void);
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_civoid kvm_timer_vcpu_load(struct kvm_vcpu *vcpu);
11862306a36Sopenharmony_civoid kvm_timer_vcpu_put(struct kvm_vcpu *vcpu);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_civoid kvm_timer_init_vhe(void);
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci#define vcpu_timer(v)	(&(v)->arch.timer_cpu)
12362306a36Sopenharmony_ci#define vcpu_get_timer(v,t)	(&vcpu_timer(v)->timers[(t)])
12462306a36Sopenharmony_ci#define vcpu_vtimer(v)	(&(v)->arch.timer_cpu.timers[TIMER_VTIMER])
12562306a36Sopenharmony_ci#define vcpu_ptimer(v)	(&(v)->arch.timer_cpu.timers[TIMER_PTIMER])
12662306a36Sopenharmony_ci#define vcpu_hvtimer(v)	(&(v)->arch.timer_cpu.timers[TIMER_HVTIMER])
12762306a36Sopenharmony_ci#define vcpu_hptimer(v)	(&(v)->arch.timer_cpu.timers[TIMER_HPTIMER])
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci#define arch_timer_ctx_index(ctx)	((ctx) - vcpu_timer((ctx)->vcpu)->timers)
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci#define timer_vm_data(ctx)		(&(ctx)->vcpu->kvm->arch.timer_data)
13262306a36Sopenharmony_ci#define timer_irq(ctx)			(timer_vm_data(ctx)->ppi[arch_timer_ctx_index(ctx)])
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ciu64 kvm_arm_timer_read_sysreg(struct kvm_vcpu *vcpu,
13562306a36Sopenharmony_ci			      enum kvm_arch_timers tmr,
13662306a36Sopenharmony_ci			      enum kvm_arch_timer_regs treg);
13762306a36Sopenharmony_civoid kvm_arm_timer_write_sysreg(struct kvm_vcpu *vcpu,
13862306a36Sopenharmony_ci				enum kvm_arch_timers tmr,
13962306a36Sopenharmony_ci				enum kvm_arch_timer_regs treg,
14062306a36Sopenharmony_ci				u64 val);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci/* Needed for tracing */
14362306a36Sopenharmony_ciu32 timer_get_ctl(struct arch_timer_context *ctxt);
14462306a36Sopenharmony_ciu64 timer_get_cval(struct arch_timer_context *ctxt);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci/* CPU HP callbacks */
14762306a36Sopenharmony_civoid kvm_timer_cpu_up(void);
14862306a36Sopenharmony_civoid kvm_timer_cpu_down(void);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic inline bool has_cntpoff(void)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	return (has_vhe() && cpus_have_final_cap(ARM64_HAS_ECV_CNTPOFF));
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci#endif
156