mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-09-15 22:08:47 +00:00
kernel: PTP_KVM support for arm/arm64 in Kata
This work patched the 4.19, 5.4 and 5.10 kernels, and now ptp_kvm can work correctly when the host and guest use different kernel versions.. Fixes: #2123 Signed-off-by: Damon Kwok <damon-kwok@outlook.com>
This commit is contained in:
@@ -0,0 +1,974 @@
|
||||
From 772e627bb2aa29a6d006f08bdf7bc1492671d1fe Mon Sep 17 00:00:00 2001
|
||||
From: Damon Kwok <damon-kwok@outlook.com>
|
||||
Date: Thu, 24 Jun 2021 15:04:19 +0800
|
||||
Subject: [PATCH] 5.10.x: PTP_KVM support for arm/arm64
|
||||
|
||||
---
|
||||
Documentation/virt/kvm/api.rst | 9 ++
|
||||
Documentation/virt/kvm/arm/index.rst | 1 +
|
||||
Documentation/virt/kvm/arm/ptp_kvm.rst | 31 +++++++
|
||||
Documentation/virt/kvm/timekeeping.rst | 35 ++++++++
|
||||
arch/arm/kernel/setup.c | 5 ++
|
||||
arch/arm64/kernel/setup.c | 1 +
|
||||
arch/arm64/kvm/hypercalls.c | 86 ++++++++++++++++--
|
||||
arch/arm64/kvm/reset.c | 1 +
|
||||
drivers/clocksource/arm_arch_timer.c | 33 +++++++
|
||||
drivers/firmware/smccc/smccc.c | 37 ++++++++
|
||||
drivers/ptp/Kconfig | 2 +-
|
||||
drivers/ptp/Makefile | 2 +
|
||||
drivers/ptp/ptp_kvm_arm.c | 28 ++++++
|
||||
drivers/ptp/{ptp_kvm.c => ptp_kvm_common.c} | 85 +++++-------------
|
||||
drivers/ptp/ptp_kvm_x86.c | 96 +++++++++++++++++++++
|
||||
include/linux/arm-smccc.h | 59 +++++++++++++
|
||||
include/linux/clocksource.h | 6 ++
|
||||
include/linux/clocksource_ids.h | 12 +++
|
||||
include/linux/ptp_kvm.h | 19 ++++
|
||||
include/linux/timekeeping.h | 12 +--
|
||||
include/uapi/linux/kvm.h | 1 +
|
||||
kernel/time/clocksource.c | 2 +
|
||||
kernel/time/timekeeping.c | 1 +
|
||||
23 files changed, 487 insertions(+), 77 deletions(-)
|
||||
create mode 100644 Documentation/virt/kvm/arm/ptp_kvm.rst
|
||||
create mode 100644 drivers/ptp/ptp_kvm_arm.c
|
||||
rename drivers/ptp/{ptp_kvm.c => ptp_kvm_common.c} (60%)
|
||||
create mode 100644 drivers/ptp/ptp_kvm_x86.c
|
||||
create mode 100644 include/linux/clocksource_ids.h
|
||||
create mode 100644 include/linux/ptp_kvm.h
|
||||
|
||||
diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
|
||||
index cd8a585..4b97c22 100644
|
||||
--- a/Documentation/virt/kvm/api.rst
|
||||
+++ b/Documentation/virt/kvm/api.rst
|
||||
@@ -6398,3 +6398,12 @@ When enabled, KVM will disable paravirtual features provided to the
|
||||
guest according to the bits in the KVM_CPUID_FEATURES CPUID leaf
|
||||
(0x40000001). Otherwise, a guest may use the paravirtual features
|
||||
regardless of what has actually been exposed through the CPUID leaf.
|
||||
+
|
||||
+8.27 KVM_CAP_PTP_KVM
|
||||
+--------------------
|
||||
+
|
||||
+:Architectures: arm64
|
||||
+
|
||||
+This capability indicates that KVM virtual PTP service is supported in host.
|
||||
+It must company with the implementation of KVM virtual PTP service in host
|
||||
+so VMM can probe if there is the service in host by checking this capability.
|
||||
diff --git a/Documentation/virt/kvm/arm/index.rst b/Documentation/virt/kvm/arm/index.rst
|
||||
index 3e2b2ab..78a9b67 100644
|
||||
--- a/Documentation/virt/kvm/arm/index.rst
|
||||
+++ b/Documentation/virt/kvm/arm/index.rst
|
||||
@@ -10,3 +10,4 @@ ARM
|
||||
hyp-abi
|
||||
psci
|
||||
pvtime
|
||||
+ ptp_kvm
|
||||
diff --git a/Documentation/virt/kvm/arm/ptp_kvm.rst b/Documentation/virt/kvm/arm/ptp_kvm.rst
|
||||
new file mode 100644
|
||||
index 0000000..7be7e65
|
||||
--- /dev/null
|
||||
+++ b/Documentation/virt/kvm/arm/ptp_kvm.rst
|
||||
@@ -0,0 +1,31 @@
|
||||
+.. SPDX-License-Identifier: GPL-2.0
|
||||
+
|
||||
+PTP_KVM support for arm/arm64
|
||||
+=============================
|
||||
+
|
||||
+PTP_KVM is used for time sync between guest and host in a high precision.
|
||||
+It needs to get the wall time and counter value from the host and transfer these
|
||||
+to guest via hypercall service. So one more hypercall service has been added.
|
||||
+
|
||||
+This new SMCCC hypercall is defined as:
|
||||
+
|
||||
+* ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID: 0x86000001
|
||||
+
|
||||
+As both 32 and 64-bits ptp_kvm client should be supported, we choose SMC32/HVC32
|
||||
+calling convention.
|
||||
+
|
||||
+ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
|
||||
+
|
||||
+ ============= ========== ==========
|
||||
+ Function ID: (uint32) 0x86000001
|
||||
+ Arguments: (uint32) ARM_PTP_PHY_COUNTER(1) or ARM_PTP_VIRT_COUNTER(0)
|
||||
+ which indicate acquiring physical counter or
|
||||
+ virtual counter respectively.
|
||||
+ Return Value: val0(uint32) NOT_SUPPORTED(-1) or upper 32 bits of wall clock time(64-bits).
|
||||
+ val1(uint32) Lower 32 bits of wall clock time.
|
||||
+ val2(uint32) Upper 32 bits of counter cycle(64-bits).
|
||||
+ val3(uint32) Lower 32 bits of counter cycle.
|
||||
+ Endianness: No Restrictions.
|
||||
+ ============= ========== ==========
|
||||
+
|
||||
+More info see section 5 in Documentation/virt/kvm/timekeeping.rst.
|
||||
diff --git a/Documentation/virt/kvm/timekeeping.rst b/Documentation/virt/kvm/timekeeping.rst
|
||||
index 21ae7ef..c81383e 100644
|
||||
--- a/Documentation/virt/kvm/timekeeping.rst
|
||||
+++ b/Documentation/virt/kvm/timekeeping.rst
|
||||
@@ -13,6 +13,7 @@ Timekeeping Virtualization for X86-Based Architectures
|
||||
2) Timing Devices
|
||||
3) TSC Hardware
|
||||
4) Virtualization Problems
|
||||
+ 5) KVM virtual PTP clock
|
||||
|
||||
1. Overview
|
||||
===========
|
||||
@@ -643,3 +644,37 @@ by using CPU utilization itself as a signalling channel. Preventing such
|
||||
problems would require completely isolated virtual time which may not track
|
||||
real time any longer. This may be useful in certain security or QA contexts,
|
||||
but in general isn't recommended for real-world deployment scenarios.
|
||||
+
|
||||
+5. KVM virtual PTP clock
|
||||
+========================
|
||||
+
|
||||
+NTP (Network Time Protocol) is often used to sync time in a VM. Unfortunately,
|
||||
+the precision of NTP is limited due to unknown delays in the network.
|
||||
+
|
||||
+KVM virtual PTP clock (PTP_KVM) offers another way to sync time in VM; use the
|
||||
+host's clock rather than one from a remote machine. Having a synchronization
|
||||
+mechanism for the virtualization environment allows us to keep all the guests
|
||||
+running on the same host in sync.
|
||||
+In general, the delay of communication between host and guest is quite
|
||||
+small, so ptp_kvm can offer time sync precision up to in order of nanoseconds.
|
||||
+Please keep in mind that ptp_kvm just limits itself to be a channel which
|
||||
+transmits the remote clock from host to guest. An application, eg. chrony, is
|
||||
+needed in usersapce of VM in order to set the guest time.
|
||||
+
|
||||
+After ptp_kvm is initialized, there will be a new device node under /dev called
|
||||
+ptp%d. A guest userspace service, like chrony, can use this device to get host
|
||||
+walltime, sometimes also counter cycle, which depends on the service it calls.
|
||||
+Then this guest userspace service can use those data to do the time sync for
|
||||
+the guest.
|
||||
+The following is the work flow of ptp_kvm:
|
||||
+
|
||||
+a) time sync service in guest userspace call ioctl on ptp device /dev/ptp%d.
|
||||
+b) ptp_kvm module in guest receives this request then invokes hypercall to
|
||||
+ route into host kernel to request host's walltime/counter cycle.
|
||||
+c) ptp_kvm hypercall service on the host responds to the request and sends data
|
||||
+ back.
|
||||
+d) ptp in guest copies the data to userspace.
|
||||
+
|
||||
+ptp_kvm consists of components running on the guest and host. Step 2 consists of
|
||||
+a guest driver making a hypercall whilst step 3 involves the hypervisor responding
|
||||
+with information.
|
||||
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
|
||||
index f90479d..472daea 100644
|
||||
--- a/arch/arm/kernel/setup.c
|
||||
+++ b/arch/arm/kernel/setup.c
|
||||
@@ -1154,6 +1154,11 @@ void __init setup_arch(char **cmdline_p)
|
||||
|
||||
arm_dt_init_cpu_maps();
|
||||
psci_dt_init();
|
||||
+
|
||||
+#ifdef CONFIG_HAVE_ARM_SMCCC_DISCOVERY
|
||||
+ kvm_init_hyp_services();
|
||||
+#endif
|
||||
+
|
||||
#ifdef CONFIG_SMP
|
||||
if (is_smp()) {
|
||||
if (!mdesc->smp_init || !mdesc->smp_init()) {
|
||||
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
|
||||
index 133257f..d1dbe41 100644
|
||||
--- a/arch/arm64/kernel/setup.c
|
||||
+++ b/arch/arm64/kernel/setup.c
|
||||
@@ -353,6 +353,7 @@ void __init __no_sanitize_address setup_arch(char **cmdline_p)
|
||||
else
|
||||
psci_acpi_init();
|
||||
|
||||
+ kvm_init_hyp_services();
|
||||
init_bootcpu_ops();
|
||||
smp_init_cpus();
|
||||
smp_build_mpidr_hash();
|
||||
diff --git a/arch/arm64/kvm/hypercalls.c b/arch/arm64/kvm/hypercalls.c
|
||||
index 25ea4ec..9a48345 100644
|
||||
--- a/arch/arm64/kvm/hypercalls.c
|
||||
+++ b/arch/arm64/kvm/hypercalls.c
|
||||
@@ -9,16 +9,59 @@
|
||||
#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 in the same
|
||||
+ * time to keep consistency and precision.
|
||||
+ */
|
||||
+ ktime_get_snapshot(&systime_snapshot);
|
||||
+
|
||||
+ // binding ptp_kvm clocksource to arm_arch_counter
|
||||
+ if (systime_snapshot.cs_id != CSID_ARM_ARCH_COUNTER)
|
||||
+ return;
|
||||
+
|
||||
+ val[0] = upper_32_bits(systime_snapshot.real);
|
||||
+ val[1] = lower_32_bits(systime_snapshot.real);
|
||||
+
|
||||
+ /*
|
||||
+ * which of virtual counter or physical counter being
|
||||
+ * asked for is decided by the r1 value of SMCCC
|
||||
+ * call. If no invalid r1 value offered, default cycle
|
||||
+ * value(-1) will be returned.
|
||||
+ * Note: keep in mind that feature is u32 and smccc_get_arg1
|
||||
+ * will return u64, so need auto cast here.
|
||||
+ */
|
||||
+ feature = smccc_get_arg1(vcpu);
|
||||
+ switch (feature) {
|
||||
+ case ARM_PTP_VIRT_COUNTER:
|
||||
+ cycles = systime_snapshot.cycles - vcpu_read_sys_reg(vcpu, CNTVOFF_EL2);
|
||||
+ break;
|
||||
+ case ARM_PTP_PHY_COUNTER:
|
||||
+ cycles = systime_snapshot.cycles;
|
||||
+ break;
|
||||
+ default:
|
||||
+ val[0] = SMCCC_RET_NOT_SUPPORTED;
|
||||
+ break;
|
||||
+ }
|
||||
+ 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 +71,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,27 +97,52 @@ 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;
|
||||
+ /*
|
||||
+ * This serves virtual kvm_ptp.
|
||||
+ * Four values will be passed back.
|
||||
+ * reg0 stores high 32-bits of host ktime;
|
||||
+ * reg1 stores low 32-bits of host ktime;
|
||||
+ * For ARM_PTP_VIRT_COUNTER:
|
||||
+ * reg2 stores high 32-bits of difference of host cycles and cntvoff;
|
||||
+ * reg3 stores low 32-bits of difference of host cycles and cntvoff.
|
||||
+ * For ARM_PTP_PHY_COUNTER:
|
||||
+ * reg2 stores the high 32-bits of host cycles;
|
||||
+ * reg3 stores the low 32-bits of host cycles.
|
||||
+ */
|
||||
+ case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID:
|
||||
+ kvm_ptp_get_time(vcpu, val);
|
||||
break;
|
||||
default:
|
||||
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;
|
||||
}
|
||||
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
|
||||
index b969c21..77fae02 100644
|
||||
--- a/arch/arm64/kvm/reset.c
|
||||
+++ b/arch/arm64/kvm/reset.c
|
||||
@@ -75,6 +75,7 @@ int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
||||
break;
|
||||
case KVM_CAP_SET_GUEST_DEBUG:
|
||||
case KVM_CAP_VCPU_ATTRIBUTES:
|
||||
+ case KVM_CAP_PTP_KVM:
|
||||
r = 1;
|
||||
break;
|
||||
case KVM_CAP_ARM_VM_IPA_SIZE:
|
||||
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
|
||||
index d017782..7cbb9fa 100644
|
||||
--- a/drivers/clocksource/arm_arch_timer.c
|
||||
+++ b/drivers/clocksource/arm_arch_timer.c
|
||||
@@ -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,32 @@ 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;
|
||||
+ ktime_t ktime;
|
||||
+ u32 ptp_counter;
|
||||
+
|
||||
+ if (arch_timer_uses_ppi == ARCH_TIMER_VIRT_PPI)
|
||||
+ ptp_counter = ARM_PTP_VIRT_COUNTER;
|
||||
+ else
|
||||
+ ptp_counter = ARM_PTP_PHY_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);
|
||||
diff --git a/drivers/firmware/smccc/smccc.c b/drivers/firmware/smccc/smccc.c
|
||||
index 00c88b8..e153c71 100644
|
||||
--- a/drivers/firmware/smccc/smccc.c
|
||||
+++ b/drivers/firmware/smccc/smccc.c
|
||||
@@ -7,10 +7,47 @@
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/arm-smccc.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/string.h>
|
||||
|
||||
static u32 smccc_version = ARM_SMCCC_VERSION_1_0;
|
||||
static enum arm_smccc_conduit smccc_conduit = SMCCC_CONDUIT_NONE;
|
||||
|
||||
+DECLARE_BITMAP(__kvm_arm_hyp_services, ARM_SMCCC_KVM_NUM_FUNCS) = { };
|
||||
+EXPORT_SYMBOL_GPL(__kvm_arm_hyp_services);
|
||||
+
|
||||
+void __init kvm_init_hyp_services(void)
|
||||
+{
|
||||
+ int i;
|
||||
+ struct arm_smccc_res res;
|
||||
+
|
||||
+ if (arm_smccc_get_version() == ARM_SMCCC_VERSION_1_0)
|
||||
+ 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);
|
||||
+ for (i = 0; i < 32; ++i) {
|
||||
+ if (res.a0 & (i))
|
||||
+ set_bit(i + (32 * 0), __kvm_arm_hyp_services);
|
||||
+ if (res.a1 & (i))
|
||||
+ set_bit(i + (32 * 1), __kvm_arm_hyp_services);
|
||||
+ if (res.a2 & (i))
|
||||
+ set_bit(i + (32 * 2), __kvm_arm_hyp_services);
|
||||
+ if (res.a3 & (i))
|
||||
+ set_bit(i + (32 * 3), __kvm_arm_hyp_services);
|
||||
+ }
|
||||
+
|
||||
+ pr_info("KVM hypervisor services detected (0x%08lx 0x%08lx 0x%08lx 0x%08lx)\n",
|
||||
+ res.a3, res.a2, res.a1, res.a0);
|
||||
+}
|
||||
+
|
||||
void __init arm_smccc_version_init(u32 version, enum arm_smccc_conduit conduit)
|
||||
{
|
||||
smccc_version = version;
|
||||
diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig
|
||||
index deb429a..5523f96 100644
|
||||
--- a/drivers/ptp/Kconfig
|
||||
+++ b/drivers/ptp/Kconfig
|
||||
@@ -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 X86 || (HAVE_ARM_SMCCC_DISCOVERY && ARM_ARCH_TIMER)
|
||||
default y
|
||||
help
|
||||
This driver adds support for using kvm infrastructure as a PTP
|
||||
diff --git a/drivers/ptp/Makefile b/drivers/ptp/Makefile
|
||||
index 7aff75f..9fa5ede 100644
|
||||
--- a/drivers/ptp/Makefile
|
||||
+++ b/drivers/ptp/Makefile
|
||||
@@ -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
|
||||
diff --git a/drivers/ptp/ptp_kvm_arm.c b/drivers/ptp/ptp_kvm_arm.c
|
||||
new file mode 100644
|
||||
index 0000000..b7d28c8
|
||||
--- /dev/null
|
||||
+++ b/drivers/ptp/ptp_kvm_arm.c
|
||||
@@ -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);
|
||||
+}
|
||||
diff --git a/drivers/ptp/ptp_kvm.c b/drivers/ptp/ptp_kvm_common.c
|
||||
similarity index 60%
|
||||
rename from drivers/ptp/ptp_kvm.c
|
||||
rename to drivers/ptp/ptp_kvm_common.c
|
||||
index 658d33f..5c36e2f 100644
|
||||
--- a/drivers/ptp/ptp_kvm.c
|
||||
+++ b/drivers/ptp/ptp_kvm_common.c
|
||||
@@ -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!=0) {
|
||||
+ 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,12 @@ 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) {
|
||||
+ if (ret != -EOPNOTSUPP)
|
||||
+ pr_err("fail to initialize ptp_kvm");
|
||||
+ return ret;
|
||||
+ }
|
||||
|
||||
kvm_ptp_clock.caps = ptp_kvm_caps;
|
||||
|
||||
diff --git a/drivers/ptp/ptp_kvm_x86.c b/drivers/ptp/ptp_kvm_x86.c
|
||||
new file mode 100644
|
||||
index 0000000..e011d69
|
||||
--- /dev/null
|
||||
+++ b/drivers/ptp/ptp_kvm_x86.c
|
||||
@@ -0,0 +1,96 @@
|
||||
+// 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>
|
||||
+
|
||||
+phys_addr_t clock_pair_gpa;
|
||||
+struct kvm_clock_pairing clock_pair;
|
||||
+struct pvclock_vsyscall_time_info *hv_clock;
|
||||
+
|
||||
+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)
|
||||
+{
|
||||
+ unsigned 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)
|
||||
+{
|
||||
+ unsigned long ret;
|
||||
+ unsigned int version;
|
||||
+ int cpu;
|
||||
+ struct pvclock_vcpu_time_info *src;
|
||||
+
|
||||
+ 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;
|
||||
+}
|
||||
diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
|
||||
index f860645..92b46cb 100644
|
||||
--- a/include/linux/arm-smccc.h
|
||||
+++ b/include/linux/arm-smccc.h
|
||||
@@ -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 ARM_PTP_VIRT_COUNTER 0
|
||||
+#define ARM_PTP_PHY_COUNTER 1
|
||||
+
|
||||
/* Paravirtualised time calls (defined by ARM DEN0057A) */
|
||||
#define ARM_SMCCC_HV_PV_TIME_FEATURES \
|
||||
ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
|
||||
@@ -391,5 +432,23 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1,
|
||||
method; \
|
||||
})
|
||||
|
||||
+void __init kvm_init_hyp_services(void);
|
||||
+
|
||||
+/*
|
||||
+ * This helper will be called in guest. We put it here then both arm and arm64
|
||||
+ * guest can touch it.
|
||||
+ */
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/err.h>
|
||||
+static inline bool kvm_arm_hyp_service_available(u32 func_id)
|
||||
+{
|
||||
+ extern DECLARE_BITMAP(__kvm_arm_hyp_services, ARM_SMCCC_KVM_NUM_FUNCS);
|
||||
+
|
||||
+ if (func_id >= ARM_SMCCC_KVM_NUM_FUNCS)
|
||||
+ return false;
|
||||
+
|
||||
+ return test_bit(func_id, __kvm_arm_hyp_services);
|
||||
+}
|
||||
+
|
||||
#endif /*__ASSEMBLY__*/
|
||||
#endif /*__LINUX_ARM_SMCCC_H*/
|
||||
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
|
||||
index 86d143d..1290d0d 100644
|
||||
--- a/include/linux/clocksource.h
|
||||
+++ b/include/linux/clocksource.h
|
||||
@@ -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;
|
||||
|
||||
diff --git a/include/linux/clocksource_ids.h b/include/linux/clocksource_ids.h
|
||||
new file mode 100644
|
||||
index 0000000..16775d7
|
||||
--- /dev/null
|
||||
+++ b/include/linux/clocksource_ids.h
|
||||
@@ -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
|
||||
diff --git a/include/linux/ptp_kvm.h b/include/linux/ptp_kvm.h
|
||||
new file mode 100644
|
||||
index 0000000..f960a71
|
||||
--- /dev/null
|
||||
+++ b/include/linux/ptp_kvm.h
|
||||
@@ -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_ */
|
||||
diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h
|
||||
index 7f7e4a3..2ee0535 100644
|
||||
--- a/include/linux/timekeeping.h
|
||||
+++ b/include/linux/timekeeping.h
|
||||
@@ -3,6 +3,7 @@
|
||||
#define _LINUX_TIMEKEEPING_H
|
||||
|
||||
#include <linux/errno.h>
|
||||
+#include <linux/clocksource_ids.h>
|
||||
|
||||
/* Included from linux/ktime.h */
|
||||
|
||||
@@ -244,11 +245,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;
|
||||
};
|
||||
|
||||
/**
|
||||
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
|
||||
index ca41220..797c40b 100644
|
||||
--- a/include/uapi/linux/kvm.h
|
||||
+++ b/include/uapi/linux/kvm.h
|
||||
@@ -1053,6 +1053,7 @@ struct kvm_ppc_resize_hpt {
|
||||
#define KVM_CAP_X86_USER_SPACE_MSR 188
|
||||
#define KVM_CAP_X86_MSR_FILTER 189
|
||||
#define KVM_CAP_ENFORCE_PV_FEATURE_CPUID 190
|
||||
+#define KVM_CAP_PTP_KVM 191
|
||||
|
||||
#ifdef KVM_CAP_IRQ_ROUTING
|
||||
|
||||
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
|
||||
index 02441ea..6b38d49 100644
|
||||
--- a/kernel/time/clocksource.c
|
||||
+++ b/kernel/time/clocksource.c
|
||||
@@ -928,6 +928,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",
|
||||
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
|
||||
index 6858a31..eb04a2d 100644
|
||||
--- a/kernel/time/timekeeping.c
|
||||
+++ b/kernel/time/timekeeping.c
|
||||
@@ -1053,6 +1053,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,
|
||||
--
|
||||
2.32.0
|
||||
|
Reference in New Issue
Block a user