Merge branch 'kvm-arm64/ptp' into kvmarm-master/next

Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
Marc Zyngier 2021-04-13 15:41:22 +01:00
commit d8f37d291c
25 changed files with 443 additions and 78 deletions

View file

@ -6737,3 +6737,13 @@ vcpu_info is set.
The KVM_XEN_HVM_CONFIG_RUNSTATE flag indicates that the runstate-related
features KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR/_CURRENT/_DATA/_ADJUST are
supported by the KVM_XEN_VCPU_SET_ATTR/KVM_XEN_VCPU_GET_ATTR ioctls.
8.31 KVM_CAP_PTP_KVM
--------------------
:Architectures: arm64
This capability indicates that the KVM virtual PTP service is
supported in the host. A VMM can check whether the service is
available to the guest on migration.

View file

@ -10,3 +10,4 @@ ARM
hyp-abi
psci
pvtime
ptp_kvm

View file

@ -0,0 +1,25 @@
.. SPDX-License-Identifier: GPL-2.0
PTP_KVM support for arm/arm64
=============================
PTP_KVM is used for high precision time sync between host and guests.
It relies on transferring the wall clock and counter value from the
host to the guest using a KVM-specific hypercall.
* ARM_SMCCC_HYP_KVM_PTP_FUNC_ID: 0x86000001
This hypercall uses the SMC32/HVC32 calling convention:
ARM_SMCCC_HYP_KVM_PTP_FUNC_ID
============== ======== =====================================
Function ID: (uint32) 0x86000001
Arguments: (uint32) KVM_PTP_VIRT_COUNTER(0)
KVM_PTP_PHYS_COUNTER(1)
Return Values: (int32) NOT_SUPPORTED(-1) on error, or
(uint32) Upper 32 bits of wall clock time (r0)
(uint32) Lower 32 bits of wall clock time (r1)
(uint32) Upper 32 bits of counter (r2)
(uint32) Lower 32 bits of counter (r3)
Endianness: No Restrictions.
============== ======== =====================================

View file

@ -4,4 +4,7 @@
#include <asm/xen/hypervisor.h>
void kvm_init_hyp_services(void);
bool kvm_arm_hyp_service_available(u32 func_id);
#endif

View file

@ -4,4 +4,7 @@
#include <asm/xen/hypervisor.h>
void kvm_init_hyp_services(void);
bool kvm_arm_hyp_service_available(u32 func_id);
#endif

View file

@ -206,6 +206,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_ARM_INJECT_EXT_DABT:
case KVM_CAP_SET_GUEST_DEBUG:
case KVM_CAP_VCPU_ATTRIBUTES:
case KVM_CAP_PTP_KVM:
r = 1;
break;
case KVM_CAP_ARM_SET_DEVICE_ADDR:

View file

@ -9,16 +9,65 @@
#include <kvm/arm_hypercalls.h>
#include <kvm/arm_psci.h>
static void kvm_ptp_get_time(struct kvm_vcpu *vcpu, u64 *val)
{
struct system_time_snapshot systime_snapshot;
u64 cycles = ~0UL;
u32 feature;
/*
* system time and counter value must captured at the same
* time to keep consistency and precision.
*/
ktime_get_snapshot(&systime_snapshot);
/*
* This is only valid if the current clocksource is the
* architected counter, as this is the only one the guest
* can see.
*/
if (systime_snapshot.cs_id != CSID_ARM_ARCH_COUNTER)
return;
/*
* The guest selects one of the two reference counters
* (virtual or physical) with the first argument of the SMCCC
* call. In case the identifier is not supported, error out.
*/
feature = smccc_get_arg1(vcpu);
switch (feature) {
case KVM_PTP_VIRT_COUNTER:
cycles = systime_snapshot.cycles - vcpu_read_sys_reg(vcpu, CNTVOFF_EL2);
break;
case KVM_PTP_PHYS_COUNTER:
cycles = systime_snapshot.cycles;
break;
default:
return;
}
/*
* This relies on the top bit of val[0] never being set for
* valid values of system time, because that is *really* far
* in the future (about 292 years from 1970, and at that stage
* nobody will give a damn about it).
*/
val[0] = upper_32_bits(systime_snapshot.real);
val[1] = lower_32_bits(systime_snapshot.real);
val[2] = upper_32_bits(cycles);
val[3] = lower_32_bits(cycles);
}
int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
{
u32 func_id = smccc_get_function(vcpu);
long val = SMCCC_RET_NOT_SUPPORTED;
u64 val[4] = {SMCCC_RET_NOT_SUPPORTED};
u32 feature;
gpa_t gpa;
switch (func_id) {
case ARM_SMCCC_VERSION_FUNC_ID:
val = ARM_SMCCC_VERSION_1_1;
val[0] = ARM_SMCCC_VERSION_1_1;
break;
case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
feature = smccc_get_arg1(vcpu);
@ -28,10 +77,10 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
case SPECTRE_VULNERABLE:
break;
case SPECTRE_MITIGATED:
val = SMCCC_RET_SUCCESS;
val[0] = SMCCC_RET_SUCCESS;
break;
case SPECTRE_UNAFFECTED:
val = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED;
val[0] = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED;
break;
}
break;
@ -54,22 +103,35 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
break;
fallthrough;
case SPECTRE_UNAFFECTED:
val = SMCCC_RET_NOT_REQUIRED;
val[0] = SMCCC_RET_NOT_REQUIRED;
break;
}
break;
case ARM_SMCCC_HV_PV_TIME_FEATURES:
val = SMCCC_RET_SUCCESS;
val[0] = SMCCC_RET_SUCCESS;
break;
}
break;
case ARM_SMCCC_HV_PV_TIME_FEATURES:
val = kvm_hypercall_pv_features(vcpu);
val[0] = kvm_hypercall_pv_features(vcpu);
break;
case ARM_SMCCC_HV_PV_TIME_ST:
gpa = kvm_init_stolen_time(vcpu);
if (gpa != GPA_INVALID)
val = gpa;
val[0] = gpa;
break;
case ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID:
val[0] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0;
val[1] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1;
val[2] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2;
val[3] = ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3;
break;
case ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID:
val[0] = BIT(ARM_SMCCC_KVM_FUNC_FEATURES);
val[0] |= BIT(ARM_SMCCC_KVM_FUNC_PTP);
break;
case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
kvm_ptp_get_time(vcpu, val);
break;
case ARM_SMCCC_TRNG_VERSION:
case ARM_SMCCC_TRNG_FEATURES:
@ -81,6 +143,6 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
return kvm_psci_call(vcpu);
}
smccc_set_retval(vcpu, val, 0, 0, 0);
smccc_set_retval(vcpu, val[0], val[1], val[2], val[3]);
return 1;
}

View file

@ -16,6 +16,7 @@
#include <linux/cpu_pm.h>
#include <linux/clockchips.h>
#include <linux/clocksource.h>
#include <linux/clocksource_ids.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
@ -24,6 +25,8 @@
#include <linux/sched/clock.h>
#include <linux/sched_clock.h>
#include <linux/acpi.h>
#include <linux/arm-smccc.h>
#include <linux/ptp_kvm.h>
#include <asm/arch_timer.h>
#include <asm/virt.h>
@ -191,6 +194,7 @@ static u64 arch_counter_read_cc(const struct cyclecounter *cc)
static struct clocksource clocksource_counter = {
.name = "arch_sys_counter",
.id = CSID_ARM_ARCH_COUNTER,
.rating = 400,
.read = arch_counter_read,
.mask = CLOCKSOURCE_MASK(56),
@ -1657,3 +1661,35 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
}
TIMER_ACPI_DECLARE(arch_timer, ACPI_SIG_GTDT, arch_timer_acpi_init);
#endif
int kvm_arch_ptp_get_crosststamp(u64 *cycle, struct timespec64 *ts,
struct clocksource **cs)
{
struct arm_smccc_res hvc_res;
u32 ptp_counter;
ktime_t ktime;
if (!IS_ENABLED(CONFIG_HAVE_ARM_SMCCC_DISCOVERY))
return -EOPNOTSUPP;
if (arch_timer_uses_ppi == ARCH_TIMER_VIRT_PPI)
ptp_counter = KVM_PTP_VIRT_COUNTER;
else
ptp_counter = KVM_PTP_PHYS_COUNTER;
arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID,
ptp_counter, &hvc_res);
if ((int)(hvc_res.a0) < 0)
return -EOPNOTSUPP;
ktime = (u64)hvc_res.a0 << 32 | hvc_res.a1;
*ts = ktime_to_timespec64(ktime);
if (cycle)
*cycle = (u64)hvc_res.a2 << 32 | hvc_res.a3;
if (cs)
*cs = &clocksource_counter;
return 0;
}
EXPORT_SYMBOL_GPL(kvm_arch_ptp_get_crosststamp);

View file

@ -23,6 +23,7 @@
#include <asm/cpuidle.h>
#include <asm/cputype.h>
#include <asm/hypervisor.h>
#include <asm/system_misc.h>
#include <asm/smp_plat.h>
#include <asm/suspend.h>
@ -498,6 +499,7 @@ static int __init psci_probe(void)
psci_init_cpu_suspend();
psci_init_system_suspend();
psci_init_system_reset2();
kvm_init_hyp_services();
}
return 0;

View file

@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
#
obj-$(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) += smccc.o
obj-$(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) += smccc.o kvm_guest.o
obj-$(CONFIG_ARM_SMCCC_SOC_ID) += soc_id.o

View file

@ -0,0 +1,50 @@
// SPDX-License-Identifier: GPL-2.0
#define pr_fmt(fmt) "smccc: KVM: " fmt
#include <linux/arm-smccc.h>
#include <linux/bitmap.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <asm/hypervisor.h>
static DECLARE_BITMAP(__kvm_arm_hyp_services, ARM_SMCCC_KVM_NUM_FUNCS) __ro_after_init = { };
void __init kvm_init_hyp_services(void)
{
struct arm_smccc_res res;
u32 val[4];
if (arm_smccc_1_1_get_conduit() != SMCCC_CONDUIT_HVC)
return;
arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID, &res);
if (res.a0 != ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0 ||
res.a1 != ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1 ||
res.a2 != ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2 ||
res.a3 != ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3)
return;
memset(&res, 0, sizeof(res));
arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID, &res);
val[0] = lower_32_bits(res.a0);
val[1] = lower_32_bits(res.a1);
val[2] = lower_32_bits(res.a2);
val[3] = lower_32_bits(res.a3);
bitmap_from_arr32(__kvm_arm_hyp_services, val, ARM_SMCCC_KVM_NUM_FUNCS);
pr_info("hypervisor services detected (0x%08lx 0x%08lx 0x%08lx 0x%08lx)\n",
res.a3, res.a2, res.a1, res.a0);
}
bool kvm_arm_hyp_service_available(u32 func_id)
{
if (func_id >= ARM_SMCCC_KVM_NUM_FUNCS)
return false;
return test_bit(func_id, __kvm_arm_hyp_services);
}
EXPORT_SYMBOL_GPL(kvm_arm_hyp_service_available);

View file

@ -8,6 +8,7 @@
#include <linux/cache.h>
#include <linux/init.h>
#include <linux/arm-smccc.h>
#include <linux/kernel.h>
#include <asm/archrandom.h>
static u32 smccc_version = ARM_SMCCC_VERSION_1_0;

View file

@ -108,7 +108,7 @@ config PTP_1588_CLOCK_PCH
config PTP_1588_CLOCK_KVM
tristate "KVM virtual PTP clock"
depends on PTP_1588_CLOCK
depends on KVM_GUEST && X86
depends on (KVM_GUEST && X86) || (HAVE_ARM_SMCCC_DISCOVERY && ARM_ARCH_TIMER)
default y
help
This driver adds support for using kvm infrastructure as a PTP

View file

@ -4,6 +4,8 @@
#
ptp-y := ptp_clock.o ptp_chardev.o ptp_sysfs.o
ptp_kvm-$(CONFIG_X86) := ptp_kvm_x86.o ptp_kvm_common.o
ptp_kvm-$(CONFIG_HAVE_ARM_SMCCC) := ptp_kvm_arm.o ptp_kvm_common.o
obj-$(CONFIG_PTP_1588_CLOCK) += ptp.o
obj-$(CONFIG_PTP_1588_CLOCK_DTE) += ptp_dte.o
obj-$(CONFIG_PTP_1588_CLOCK_INES) += ptp_ines.o

28
drivers/ptp/ptp_kvm_arm.c Normal file
View file

@ -0,0 +1,28 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Virtual PTP 1588 clock for use with KVM guests
* Copyright (C) 2019 ARM Ltd.
* All Rights Reserved
*/
#include <linux/arm-smccc.h>
#include <linux/ptp_kvm.h>
#include <asm/arch_timer.h>
#include <asm/hypervisor.h>
int kvm_arch_ptp_init(void)
{
int ret;
ret = kvm_arm_hyp_service_available(ARM_SMCCC_KVM_FUNC_PTP);
if (ret <= 0)
return -EOPNOTSUPP;
return 0;
}
int kvm_arch_ptp_get_clock(struct timespec64 *ts)
{
return kvm_arch_ptp_get_crosststamp(NULL, ts, NULL);
}

View file

@ -8,11 +8,11 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/ptp_kvm.h>
#include <uapi/linux/kvm_para.h>
#include <asm/kvm_para.h>
#include <asm/pvclock.h>
#include <asm/kvmclock.h>
#include <uapi/asm/kvm_para.h>
#include <linux/ptp_clock_kernel.h>
@ -24,56 +24,29 @@ struct kvm_ptp_clock {
static DEFINE_SPINLOCK(kvm_ptp_lock);
static struct pvclock_vsyscall_time_info *hv_clock;
static struct kvm_clock_pairing clock_pair;
static phys_addr_t clock_pair_gpa;
static int ptp_kvm_get_time_fn(ktime_t *device_time,
struct system_counterval_t *system_counter,
void *ctx)
{
unsigned long ret;
long ret;
u64 cycle;
struct timespec64 tspec;
unsigned version;
int cpu;
struct pvclock_vcpu_time_info *src;
struct clocksource *cs;
spin_lock(&kvm_ptp_lock);
preempt_disable_notrace();
cpu = smp_processor_id();
src = &hv_clock[cpu].pvti;
do {
/*
* We are using a TSC value read in the hosts
* kvm_hc_clock_pairing handling.
* So any changes to tsc_to_system_mul
* and tsc_shift or any other pvclock
* data invalidate that measurement.
*/
version = pvclock_read_begin(src);
ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING,
clock_pair_gpa,
KVM_CLOCK_PAIRING_WALLCLOCK);
if (ret != 0) {
pr_err_ratelimited("clock pairing hypercall ret %lu\n", ret);
spin_unlock(&kvm_ptp_lock);
preempt_enable_notrace();
return -EOPNOTSUPP;
}
tspec.tv_sec = clock_pair.sec;
tspec.tv_nsec = clock_pair.nsec;
ret = __pvclock_read_cycles(src, clock_pair.tsc);
} while (pvclock_read_retry(src, version));
ret = kvm_arch_ptp_get_crosststamp(&cycle, &tspec, &cs);
if (ret) {
spin_unlock(&kvm_ptp_lock);
preempt_enable_notrace();
return ret;
}
preempt_enable_notrace();
system_counter->cycles = ret;
system_counter->cs = &kvm_clock;
system_counter->cycles = cycle;
system_counter->cs = cs;
*device_time = timespec64_to_ktime(tspec);
@ -111,22 +84,17 @@ static int ptp_kvm_settime(struct ptp_clock_info *ptp,
static int ptp_kvm_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
{
unsigned long ret;
long ret;
struct timespec64 tspec;
spin_lock(&kvm_ptp_lock);
ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING,
clock_pair_gpa,
KVM_CLOCK_PAIRING_WALLCLOCK);
if (ret != 0) {
pr_err_ratelimited("clock offset hypercall ret %lu\n", ret);
ret = kvm_arch_ptp_get_clock(&tspec);
if (ret) {
spin_unlock(&kvm_ptp_lock);
return -EOPNOTSUPP;
return ret;
}
tspec.tv_sec = clock_pair.sec;
tspec.tv_nsec = clock_pair.nsec;
spin_unlock(&kvm_ptp_lock);
memcpy(ts, &tspec, sizeof(struct timespec64));
@ -168,19 +136,11 @@ static int __init ptp_kvm_init(void)
{
long ret;
if (!kvm_para_available())
return -ENODEV;
clock_pair_gpa = slow_virt_to_phys(&clock_pair);
hv_clock = pvclock_get_pvti_cpu0_va();
if (!hv_clock)
return -ENODEV;
ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING, clock_pair_gpa,
KVM_CLOCK_PAIRING_WALLCLOCK);
if (ret == -KVM_ENOSYS || ret == -KVM_EOPNOTSUPP)
return -ENODEV;
ret = kvm_arch_ptp_init();
if (ret) {
pr_err("fail to initialize ptp_kvm");
return ret;
}
kvm_ptp_clock.caps = ptp_kvm_caps;

97
drivers/ptp/ptp_kvm_x86.c Normal file
View file

@ -0,0 +1,97 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Virtual PTP 1588 clock for use with KVM guests
*
* Copyright (C) 2017 Red Hat Inc.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <asm/pvclock.h>
#include <asm/kvmclock.h>
#include <linux/module.h>
#include <uapi/asm/kvm_para.h>
#include <uapi/linux/kvm_para.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/ptp_kvm.h>
struct pvclock_vsyscall_time_info *hv_clock;
static phys_addr_t clock_pair_gpa;
static struct kvm_clock_pairing clock_pair;
int kvm_arch_ptp_init(void)
{
long ret;
if (!kvm_para_available())
return -ENODEV;
clock_pair_gpa = slow_virt_to_phys(&clock_pair);
hv_clock = pvclock_get_pvti_cpu0_va();
if (!hv_clock)
return -ENODEV;
ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING, clock_pair_gpa,
KVM_CLOCK_PAIRING_WALLCLOCK);
if (ret == -KVM_ENOSYS || ret == -KVM_EOPNOTSUPP)
return -ENODEV;
return 0;
}
int kvm_arch_ptp_get_clock(struct timespec64 *ts)
{
long ret;
ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING,
clock_pair_gpa,
KVM_CLOCK_PAIRING_WALLCLOCK);
if (ret != 0) {
pr_err_ratelimited("clock offset hypercall ret %lu\n", ret);
return -EOPNOTSUPP;
}
ts->tv_sec = clock_pair.sec;
ts->tv_nsec = clock_pair.nsec;
return 0;
}
int kvm_arch_ptp_get_crosststamp(u64 *cycle, struct timespec64 *tspec,
struct clocksource **cs)
{
struct pvclock_vcpu_time_info *src;
unsigned int version;
long ret;
int cpu;
cpu = smp_processor_id();
src = &hv_clock[cpu].pvti;
do {
/*
* We are using a TSC value read in the hosts
* kvm_hc_clock_pairing handling.
* So any changes to tsc_to_system_mul
* and tsc_shift or any other pvclock
* data invalidate that measurement.
*/
version = pvclock_read_begin(src);
ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING,
clock_pair_gpa,
KVM_CLOCK_PAIRING_WALLCLOCK);
if (ret != 0) {
pr_err_ratelimited("clock pairing hypercall ret %lu\n", ret);
return -EOPNOTSUPP;
}
tspec->tv_sec = clock_pair.sec;
tspec->tv_nsec = clock_pair.nsec;
*cycle = __pvclock_read_cycles(src, clock_pair.tsc);
} while (pvclock_read_retry(src, version));
*cs = &kvm_clock;
return 0;
}

View file

@ -55,6 +55,8 @@
#define ARM_SMCCC_OWNER_TRUSTED_OS 50
#define ARM_SMCCC_OWNER_TRUSTED_OS_END 63
#define ARM_SMCCC_FUNC_QUERY_CALL_UID 0xff01
#define ARM_SMCCC_QUIRK_NONE 0
#define ARM_SMCCC_QUIRK_QCOM_A6 1 /* Save/restore register a6 */
@ -87,8 +89,47 @@
ARM_SMCCC_SMC_32, \
0, 0x7fff)
#define ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID \
ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
ARM_SMCCC_SMC_32, \
ARM_SMCCC_OWNER_VENDOR_HYP, \
ARM_SMCCC_FUNC_QUERY_CALL_UID)
/* KVM UID value: 28b46fb6-2ec5-11e9-a9ca-4b564d003a74 */
#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_0 0xb66fb428U
#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_1 0xe911c52eU
#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_2 0x564bcaa9U
#define ARM_SMCCC_VENDOR_HYP_UID_KVM_REG_3 0x743a004dU
/* KVM "vendor specific" services */
#define ARM_SMCCC_KVM_FUNC_FEATURES 0
#define ARM_SMCCC_KVM_FUNC_PTP 1
#define ARM_SMCCC_KVM_FUNC_FEATURES_2 127
#define ARM_SMCCC_KVM_NUM_FUNCS 128
#define ARM_SMCCC_VENDOR_HYP_KVM_FEATURES_FUNC_ID \
ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
ARM_SMCCC_SMC_32, \
ARM_SMCCC_OWNER_VENDOR_HYP, \
ARM_SMCCC_KVM_FUNC_FEATURES)
#define SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED 1
/*
* ptp_kvm is a feature used for time sync between vm and host.
* ptp_kvm module in guest kernel will get service from host using
* this hypercall ID.
*/
#define ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID \
ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
ARM_SMCCC_SMC_32, \
ARM_SMCCC_OWNER_VENDOR_HYP, \
ARM_SMCCC_KVM_FUNC_PTP)
/* ptp_kvm counter type ID */
#define KVM_PTP_VIRT_COUNTER 0
#define KVM_PTP_PHYS_COUNTER 1
/* Paravirtualised time calls (defined by ARM DEN0057A) */
#define ARM_SMCCC_HV_PV_TIME_FEATURES \
ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \

View file

@ -17,6 +17,7 @@
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/clocksource_ids.h>
#include <asm/div64.h>
#include <asm/io.h>
@ -62,6 +63,10 @@ struct module;
* 400-499: Perfect
* The ideal clocksource. A must-use where
* available.
* @id: Defaults to CSID_GENERIC. The id value is captured
* in certain snapshot functions to allow callers to
* validate the clocksource from which the snapshot was
* taken.
* @flags: Flags describing special properties
* @enable: Optional function to enable the clocksource
* @disable: Optional function to disable the clocksource
@ -100,6 +105,7 @@ struct clocksource {
const char *name;
struct list_head list;
int rating;
enum clocksource_ids id;
enum vdso_clock_mode vdso_clock_mode;
unsigned long flags;

View file

@ -0,0 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_CLOCKSOURCE_IDS_H
#define _LINUX_CLOCKSOURCE_IDS_H
/* Enum to give clocksources a unique identifier */
enum clocksource_ids {
CSID_GENERIC = 0,
CSID_ARM_ARCH_COUNTER,
CSID_MAX,
};
#endif

19
include/linux/ptp_kvm.h Normal file
View file

@ -0,0 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Virtual PTP 1588 clock for use with KVM guests
*
* Copyright (C) 2017 Red Hat Inc.
*/
#ifndef _PTP_KVM_H_
#define _PTP_KVM_H_
struct timespec64;
struct clocksource;
int kvm_arch_ptp_init(void);
int kvm_arch_ptp_get_clock(struct timespec64 *ts);
int kvm_arch_ptp_get_crosststamp(u64 *cycle,
struct timespec64 *tspec, struct clocksource **cs);
#endif /* _PTP_KVM_H_ */

View file

@ -3,6 +3,7 @@
#define _LINUX_TIMEKEEPING_H
#include <linux/errno.h>
#include <linux/clocksource_ids.h>
/* Included from linux/ktime.h */
@ -243,11 +244,12 @@ struct ktime_timestamps {
* @cs_was_changed_seq: The sequence number of clocksource change events
*/
struct system_time_snapshot {
u64 cycles;
ktime_t real;
ktime_t raw;
unsigned int clock_was_set_seq;
u8 cs_was_changed_seq;
u64 cycles;
ktime_t real;
ktime_t raw;
enum clocksource_ids cs_id;
unsigned int clock_was_set_seq;
u8 cs_was_changed_seq;
};
/**

View file

@ -1078,6 +1078,7 @@ struct kvm_ppc_resize_hpt {
#define KVM_CAP_DIRTY_LOG_RING 192
#define KVM_CAP_X86_BUS_LOCK_EXIT 193
#define KVM_CAP_PPC_DAWR1 194
#define KVM_CAP_PTP_KVM 195
#ifdef KVM_CAP_IRQ_ROUTING

View file

@ -920,6 +920,8 @@ int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq)
clocksource_arch_init(cs);
if (WARN_ON_ONCE((unsigned int)cs->id >= CSID_MAX))
cs->id = CSID_GENERIC;
if (cs->vdso_clock_mode < 0 ||
cs->vdso_clock_mode >= VDSO_CLOCKMODE_MAX) {
pr_warn("clocksource %s registered with invalid VDSO mode %d. Disabling VDSO support.\n",

View file

@ -1048,6 +1048,7 @@ void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot)
do {
seq = read_seqcount_begin(&tk_core.seq);
now = tk_clock_read(&tk->tkr_mono);
systime_snapshot->cs_id = tk->tkr_mono.clock->id;
systime_snapshot->cs_was_changed_seq = tk->cs_was_changed_seq;
systime_snapshot->clock_was_set_seq = tk->clock_was_set_seq;
base_real = ktime_add(tk->tkr_mono.base,