diff --git a/tools/packaging/kernel/patches/4.19.x/0001-4.19-enable-ptp_kvm-for-arm64-in-kata.patch b/tools/packaging/kernel/patches/4.19.x/0001-4.19-enable-ptp_kvm-for-arm64-in-kata.patch deleted file mode 100644 index 6aca37969..000000000 --- a/tools/packaging/kernel/patches/4.19.x/0001-4.19-enable-ptp_kvm-for-arm64-in-kata.patch +++ /dev/null @@ -1,457 +0,0 @@ -From bee1ae5587a7427dbb9e9e313f6d0a43a9e0ec2e Mon Sep 17 00:00:00 2001 -From: Jianyong Wu -Date: Mon, 30 Sep 2019 09:26:22 +0800 -Subject: [PATCH] 4.19: enable ptp_kvm for arm64 in kata - ---- - drivers/clocksource/arm_arch_timer.c | 25 ++++++ - drivers/ptp/Kconfig | 2 +- - drivers/ptp/Makefile | 1 + - drivers/ptp/ptp_kvm_arm64.c | 59 ++++++++++++++ - drivers/ptp/{ptp_kvm.c => ptp_kvm_common.c} | 89 +++++---------------- - drivers/ptp/ptp_kvm_x86.c | 87 ++++++++++++++++++++ - include/asm-generic/ptp_kvm.h | 12 +++ - include/linux/arm-smccc.h | 5 ++ - virt/kvm/arm/psci.c | 12 +++ - 9 files changed, 221 insertions(+), 71 deletions(-) - create mode 100644 drivers/ptp/ptp_kvm_arm64.c - rename drivers/ptp/{ptp_kvm.c => ptp_kvm_common.c} (56%) - create mode 100644 drivers/ptp/ptp_kvm_x86.c - create mode 100644 include/asm-generic/ptp_kvm.h - -diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c -index d8c7f5750cdb..84ba8f9e57be 100644 ---- a/drivers/clocksource/arm_arch_timer.c -+++ b/drivers/clocksource/arm_arch_timer.c -@@ -1571,3 +1571,28 @@ 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 -+ -+#if IS_ENABLED(CONFIG_PTP_1588_CLOCK_KVM) -+#include -+int kvm_arch_ptp_get_clock_fn(long *cycle, struct timespec64 *ts, -+ struct clocksource **cs) -+{ -+ struct arm_smccc_res hvc_res; -+ ktime_t ktime_overall; -+ struct arm_smccc_quirk hvc_quirk; -+ -+ __arm_smccc_hvc(ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID, 0, 0, 0, 0, 0, 0, 0, &hvc_res, &hvc_quirk); -+ -+ if ((long)(hvc_res.a0) < 0) -+ return -EOPNOTSUPP; -+ -+ ts->tv_sec = hvc_res.a0; -+ ts->tv_nsec = hvc_res.a1; -+ *cycle = hvc_res.a2 << 32 | hvc_res.a3; -+ *cs = &clocksource_counter; -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(kvm_arch_ptp_get_clock_fn); -+#endif -+ -diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig -index d137c480db46..318b3f5df1ea 100644 ---- a/drivers/ptp/Kconfig -+++ b/drivers/ptp/Kconfig -@@ -109,7 +109,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 || ARM64 - 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 19efa9cfa950..1bf4940a88a6 100644 ---- a/drivers/ptp/Makefile -+++ b/drivers/ptp/Makefile -@@ -4,6 +4,7 @@ - # - - ptp-y := ptp_clock.o ptp_chardev.o ptp_sysfs.o -+ptp_kvm-y := ptp_kvm_common.o ptp_kvm_$(ARCH).o - obj-$(CONFIG_PTP_1588_CLOCK) += ptp.o - obj-$(CONFIG_PTP_1588_CLOCK_DTE) += ptp_dte.o - obj-$(CONFIG_PTP_1588_CLOCK_IXP46X) += ptp_ixp46x.o -diff --git a/drivers/ptp/ptp_kvm_arm64.c b/drivers/ptp/ptp_kvm_arm64.c -new file mode 100644 -index 000000000000..fcd83324c7e1 ---- /dev/null -+++ b/drivers/ptp/ptp_kvm_arm64.c -@@ -0,0 +1,59 @@ -+// 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+void arm_smccc_1_1_invoke(u32 id, struct arm_smccc_res *res) -+{ -+ struct arm_smccc_quirk hvc_quirk; -+ -+ __arm_smccc_hvc(id, 0, 0, 0, 0, 0, 0, 0, res, &hvc_quirk); -+} -+ -+int kvm_arch_ptp_init(void) -+{ -+ struct arm_smccc_res hvc_res; -+ -+ arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID, -+ &hvc_res); -+ if ((long)(hvc_res.a0) < 0) -+ return -EOPNOTSUPP; -+ -+ return 0; -+} -+ -+int kvm_arch_ptp_get_clock_generic(struct timespec64 *ts, -+ struct arm_smccc_res *hvc_res) -+{ -+ arm_smccc_1_1_invoke(ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID, -+ hvc_res); -+ if ((long)(hvc_res->a0) < 0) -+ return -EOPNOTSUPP; -+ -+ ts->tv_sec = hvc_res->a0; -+ ts->tv_nsec = hvc_res->a1; -+ -+ return 0; -+} -+ -+int kvm_arch_ptp_get_clock(struct timespec64 *ts) -+{ -+ struct arm_smccc_res hvc_res; -+ -+ kvm_arch_ptp_get_clock_generic(ts, &hvc_res); -+ -+ return 0; -+} -diff --git a/drivers/ptp/ptp_kvm.c b/drivers/ptp/ptp_kvm_common.c -similarity index 56% -rename from drivers/ptp/ptp_kvm.c -rename to drivers/ptp/ptp_kvm_common.c -index c67dd11e08b1..c0b445fa6144 100644 ---- a/drivers/ptp/ptp_kvm.c -+++ b/drivers/ptp/ptp_kvm_common.c -@@ -1,29 +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. -- * -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License as published by -- * the Free Software Foundation; either version 2 of the License, or -- * (at your option) any later version. -- * -- * This program is distributed in the hope that it will be useful, -- * but WITHOUT ANY WARRANTY; without even the implied warranty of -- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- * GNU General Public License for more details. -- * - */ - #include - #include - #include - #include -+#include - #include - #include - #include --#include --#include - #include -+#include - - #include - -@@ -34,56 +24,29 @@ struct kvm_ptp_clock { - - 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; -+ unsigned long ret, 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_clock_fn(&cycle, &tspec, &cs); -+ if (ret != 0) { -+ pr_err_ratelimited("clock pairing hypercall ret %lu\n", ret); -+ spin_unlock(&kvm_ptp_lock); -+ preempt_enable_notrace(); -+ return -EOPNOTSUPP; -+ } - - 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); - -@@ -126,17 +89,13 @@ static int ptp_kvm_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) - - spin_lock(&kvm_ptp_lock); - -- ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING, -- clock_pair_gpa, -- KVM_CLOCK_PAIRING_WALLCLOCK); -+ ret = kvm_arch_ptp_get_clock(&tspec); - if (ret != 0) { - pr_err_ratelimited("clock offset hypercall ret %lu\n", ret); - spin_unlock(&kvm_ptp_lock); - return -EOPNOTSUPP; - } - -- tspec.tv_sec = clock_pair.sec; -- tspec.tv_nsec = clock_pair.nsec; - spin_unlock(&kvm_ptp_lock); - - memcpy(ts, &tspec, sizeof(struct timespec64)); -@@ -176,21 +135,11 @@ static void __exit ptp_kvm_exit(void) - - static int __init ptp_kvm_init(void) - { -- long ret; -- -- if (!kvm_para_available()) -- return -ENODEV; -+ int ret; - -- 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) -+ return -EOPNOTSUPP; - - 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 000000000000..a52cf1c2990c ---- /dev/null -+++ b/drivers/ptp/ptp_kvm_x86.c -@@ -0,0 +1,87 @@ -+// SPDX-License-Identifier: GPL-2.0-or-later -+/* -+ * Virtual PTP 1588 clock for use with KVM guests -+ * -+ * Copyright (C) 2017 Red Hat Inc. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+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) -+{ -+ int 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) -+ return -EOPNOTSUPP; -+ -+ ts->tv_sec = clock_pair.sec; -+ ts->tv_nsec = clock_pair.nsec; -+ -+ return 0; -+} -+ -+int kvm_arch_ptp_get_clock_fn(unsigned long *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); -+ 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/asm-generic/ptp_kvm.h b/include/asm-generic/ptp_kvm.h -new file mode 100644 -index 000000000000..883eea494a80 ---- /dev/null -+++ b/include/asm-generic/ptp_kvm.h -@@ -0,0 +1,12 @@ -+// SPDX-License-Identifier: GPL-2.0-only -+/* -+ * linux/drivers/clocksource/arm_arch_timer.c -+ * -+ * Copyright (C) 2019 ARM Ltd. -+ * All Rights Reserved -+ */ -+ -+int kvm_arch_ptp_init(void); -+int kvm_arch_ptp_get_clock(struct timespec64 *ts); -+int kvm_arch_ptp_get_clock_fn(unsigned long *cycle, -+ struct timespec64 *tspec, void *cs); -diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h -index 18863d56273c..10e99c82d098 100644 ---- a/include/linux/arm-smccc.h -+++ b/include/linux/arm-smccc.h -@@ -75,6 +75,11 @@ - ARM_SMCCC_SMC_32, \ - 0, 1) - -+#define ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID \ -+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ -+ ARM_SMCCC_SMC_32, \ -+ 0, 2) -+ - #define ARM_SMCCC_ARCH_WORKAROUND_1 \ - ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ - ARM_SMCCC_SMC_32, \ -diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c -index 9b73d3ad918a..9b9999bdeab7 100644 ---- a/virt/kvm/arm/psci.c -+++ b/virt/kvm/arm/psci.c -@@ -407,6 +407,9 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) - u32 func_id = smccc_get_function(vcpu); - u32 val = SMCCC_RET_NOT_SUPPORTED; - u32 feature; -+ struct timespec64 ts; -+ u64 cycles, cycle_high, cycle_low; -+ struct system_time_snapshot systime_snapshot; - - switch (func_id) { - case ARM_SMCCC_VERSION_FUNC_ID: -@@ -435,6 +438,15 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) - break; - } - break; -+ case ARM_SMCCC_VENDOR_HYP_KVM_PTP_FUNC_ID: -+ ktime_get_real_ts64(&ts); -+ ktime_get_snapshot(&systime_snapshot); -+ cycles = systime_snapshot.cycles - vcpu_vtimer(vcpu)->cntvoff; -+ cycle_high = cycles >> 32; -+ cycle_low = cycles << 32 >> 32; -+ -+ smccc_set_retval(vcpu, ts.tv_sec, ts.tv_nsec, cycle_high, cycle_low); -+ return 1; - default: - return kvm_psci_call(vcpu); - } --- -2.17.1 - diff --git a/tools/packaging/kernel/patches/4.19.x/0001-4.19.x-PTP_KVM-support-for-arm-arm64.patch b/tools/packaging/kernel/patches/4.19.x/0001-4.19.x-PTP_KVM-support-for-arm-arm64.patch new file mode 100644 index 000000000..483ff2159 --- /dev/null +++ b/tools/packaging/kernel/patches/4.19.x/0001-4.19.x-PTP_KVM-support-for-arm-arm64.patch @@ -0,0 +1,977 @@ +From f96a27de35d241a4f5909493ca99847512ec748a Mon Sep 17 00:00:00 2001 +From: Damon Kwok +Date: Thu, 24 Jun 2021 14:25:01 +0800 +Subject: [PATCH] 4.19.x: PTP_KVM support for arm/arm64 + +--- + arch/arm/kernel/setup.c | 2 + + arch/arm64/include/asm/kvm_host.h | 2 + + arch/arm64/kernel/setup.c | 3 + + drivers/clocksource/arm_arch_timer.c | 33 ++++++ + drivers/firmware/psci.c | 53 +++++++++ + drivers/ptp/Kconfig | 2 +- + drivers/ptp/Makefile | 2 + + drivers/ptp/ptp_kvm_arm.c | 28 +++++ + drivers/ptp/{ptp_kvm.c => ptp_kvm_common.c} | 99 ++++------------ + drivers/ptp/ptp_kvm_x86.c | 87 ++++++++++++++ + include/linux/arm-smccc.h | 125 ++++++++++++++++++++ + include/linux/clocksource.h | 6 + + include/linux/clocksource_ids.h | 13 ++ + include/linux/ptp_kvm.h | 19 +++ + include/linux/timekeeping.h | 2 + + include/uapi/linux/kvm.h | 1 + + kernel/time/clocksource.c | 3 + + kernel/time/timekeeping.c | 1 + + virt/kvm/arm/arm.c | 1 + + virt/kvm/arm/psci.c | 80 ++++++++++++- + 20 files changed, 481 insertions(+), 81 deletions(-) + create mode 100644 drivers/ptp/ptp_kvm_arm.c + rename drivers/ptp/{ptp_kvm.c => ptp_kvm_common.c} (53%) + 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/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c +index 7bbaa293a..137320130 100644 +--- a/arch/arm/kernel/setup.c ++++ b/arch/arm/kernel/setup.c +@@ -7,6 +7,7 @@ + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ ++ #include + #include + #include + #include +@@ -1137,6 +1138,7 @@ void __init setup_arch(char **cmdline_p) + + arm_dt_init_cpu_maps(); + psci_dt_init(); ++ kvm_init_hyp_services(); + #ifdef CONFIG_SMP + if (is_smp()) { + if (!mdesc->smp_init || !mdesc->smp_init()) { +diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h +index 5e720742d..ffc729a43 100644 +--- a/arch/arm64/include/asm/kvm_host.h ++++ b/arch/arm64/include/asm/kvm_host.h +@@ -145,6 +145,8 @@ enum vcpu_sysreg { + PMSWINC_EL0, /* Software Increment Register */ + PMUSERENR_EL0, /* User Enable Register */ + ++ CNTVOFF_EL2, ++ + /* 32bit specific registers. Keep them at the end of the range */ + DACR32_EL2, /* Domain Access Control Register */ + IFSR32_EL2, /* Instruction Fault Status Register */ +diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c +index b3354ff94..071f26ef4 100644 +--- a/arch/arm64/kernel/setup.c ++++ b/arch/arm64/kernel/setup.c +@@ -18,6 +18,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -334,6 +335,8 @@ void __init setup_arch(char **cmdline_p) + psci_dt_init(); + else + psci_acpi_init(); ++ ++ kvm_init_hyp_services(); + + cpu_read_bootcpu_ops(); + smp_init_cpus(); +diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c +index 0445ad7e5..b4e8a0a0b 100644 +--- a/drivers/clocksource/arm_arch_timer.c ++++ b/drivers/clocksource/arm_arch_timer.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -27,6 +28,8 @@ + #include + #include + #include ++#include ++#include + + #include + #include +@@ -173,6 +176,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), +@@ -1626,3 +1630,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/psci.c b/drivers/firmware/psci.c +index c80ec1d03..dc958d0b2 100644 +--- a/drivers/firmware/psci.c ++++ b/drivers/firmware/psci.c +@@ -15,6 +15,8 @@ + + #include + #include ++#include ++#include + #include + #include + #include +@@ -64,6 +66,57 @@ struct psci_operations psci_ops = { + .smccc_version = SMCCC_VERSION_1_0, + }; + ++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 (psci_ops.smccc_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); ++} ++ ++enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void) ++{ ++ if (psci_ops.smccc_version < SMCCC_VERSION_1_1) ++ return SMCCC_CONDUIT_NONE; ++ ++ switch (psci_ops.conduit) { ++ case PSCI_CONDUIT_SMC: ++ return SMCCC_CONDUIT_SMC; ++ case PSCI_CONDUIT_HVC: ++ return SMCCC_CONDUIT_HVC; ++ default: ++ return SMCCC_CONDUIT_NONE; ++ } ++} ++EXPORT_SYMBOL(arm_smccc_1_1_get_conduit); ++ + typedef unsigned long (psci_fn)(unsigned long, unsigned long, + unsigned long, unsigned long); + static psci_fn *invoke_psci_fn; +diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig +index d137c480d..7860ea3cb 100644 +--- a/drivers/ptp/Kconfig ++++ b/drivers/ptp/Kconfig +@@ -109,7 +109,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 || ((ARM || ARM64) && ARM_ARCH_TIMER && ARM_PSCI_FW) + 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 19efa9cfa..50a6fbd30 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_IXP46X) += ptp_ixp46x.o +diff --git a/drivers/ptp/ptp_kvm_arm.c b/drivers/ptp/ptp_kvm_arm.c +new file mode 100644 +index 000000000..b7d28c8df +--- /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 ++#include ++ ++#include ++#include ++ ++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 53% +rename from drivers/ptp/ptp_kvm.c +rename to drivers/ptp/ptp_kvm_common.c +index c67dd11e0..5c36e2fa0 100644 +--- a/drivers/ptp/ptp_kvm.c ++++ b/drivers/ptp/ptp_kvm_common.c +@@ -1,28 +1,18 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later + /* + * Virtual PTP 1588 clock for use with KVM guests + * + * Copyright (C) 2017 Red Hat Inc. +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * + */ + #include + #include + #include + #include ++#include + #include ++#include + #include + #include +-#include +-#include + #include + + #include +@@ -32,58 +22,31 @@ struct kvm_ptp_clock { + struct ptp_clock_info caps; + }; + +-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 DEFINE_SPINLOCK(kvm_ptp_lock); + + 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); + +@@ -121,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)); +@@ -178,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 000000000..4add42ae3 +--- /dev/null ++++ b/drivers/ptp/ptp_kvm_x86.c +@@ -0,0 +1,87 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Virtual PTP 1588 clock for use with KVM guests ++ * ++ * Copyright (C) 2017 Red Hat Inc. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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) ++{ ++ int 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) ++ 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); ++ 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 18863d562..af78262d4 100644 +--- a/include/linux/arm-smccc.h ++++ b/include/linux/arm-smccc.h +@@ -1,3 +1,4 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ + /* + * Copyright (c) 2015, Linaro Limited + * +@@ -14,6 +15,7 @@ + #ifndef __LINUX_ARM_SMCCC_H + #define __LINUX_ARM_SMCCC_H + ++#include + #include + + /* +@@ -54,11 +56,15 @@ + #define ARM_SMCCC_OWNER_SIP 2 + #define ARM_SMCCC_OWNER_OEM 3 + #define ARM_SMCCC_OWNER_STANDARD 4 ++#define ARM_SMCCC_OWNER_STANDARD_HYP 5 ++#define ARM_SMCCC_OWNER_VENDOR_HYP 6 + #define ARM_SMCCC_OWNER_TRUSTED_APP 48 + #define ARM_SMCCC_OWNER_TRUSTED_APP_END 49 + #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 */ + +@@ -84,11 +90,67 @@ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + 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 + + #ifndef __ASSEMBLY__ + + #include + #include ++ ++enum arm_smccc_conduit { ++ SMCCC_CONDUIT_NONE, ++ SMCCC_CONDUIT_SMC, ++ SMCCC_CONDUIT_HVC, ++}; ++ ++/** ++ * arm_smccc_1_1_get_conduit() ++ * ++ * Returns the conduit to be used for SMCCCv1.1 or later. ++ * ++ * When SMCCCv1.1 is not present, returns SMCCC_CONDUIT_NONE. ++ */ ++enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void); ++ + /** + * struct arm_smccc_res - Result from SMC/HVC call + * @a0-a3 result values from registers 0 to 3 +@@ -311,5 +373,68 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1, + #define SMCCC_RET_NOT_SUPPORTED -1 + #define SMCCC_RET_NOT_REQUIRED -2 + ++/* ++ * Like arm_smccc_1_1* but always returns SMCCC_RET_NOT_SUPPORTED. ++ * Used when the SMCCC conduit is not defined. The empty asm statement ++ * avoids compiler warnings about unused variables. ++ */ ++#define __fail_smccc_1_1(...) \ ++ do { \ ++ __declare_args(__count_args(__VA_ARGS__), __VA_ARGS__); \ ++ asm ("" __constraints(__count_args(__VA_ARGS__))); \ ++ if (___res) \ ++ ___res->a0 = SMCCC_RET_NOT_SUPPORTED; \ ++ } while (0) ++ ++/* ++ * arm_smccc_1_1_invoke() - make an SMCCC v1.1 compliant call ++ * ++ * This is a variadic macro taking one to eight source arguments, and ++ * an optional return structure. ++ * ++ * @a0-a7: arguments passed in registers 0 to 7 ++ * @res: result values from registers 0 to 3 ++ * ++ * This macro will make either an HVC call or an SMC call depending on the ++ * current SMCCC conduit. If no valid conduit is available then -1 ++ * (SMCCC_RET_NOT_SUPPORTED) is returned in @res.a0 (if supplied). ++ * ++ * The return value also provides the conduit that was used. ++ */ ++#define arm_smccc_1_1_invoke(...) ({ \ ++ int method = arm_smccc_1_1_get_conduit(); \ ++ switch (method) { \ ++ case SMCCC_CONDUIT_HVC: \ ++ arm_smccc_1_1_hvc(__VA_ARGS__); \ ++ break; \ ++ case SMCCC_CONDUIT_SMC: \ ++ arm_smccc_1_1_smc(__VA_ARGS__); \ ++ break; \ ++ default: \ ++ __fail_smccc_1_1(__VA_ARGS__); \ ++ method = SMCCC_CONDUIT_NONE; \ ++ break; \ ++ } \ ++ 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 ++#include ++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 308918928..043967d3f 100644 +--- a/include/linux/clocksource.h ++++ b/include/linux/clocksource.h +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -49,6 +50,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. + * @read: returns a cycle value, passes clocksource as argument + * @enable: optional function to enable the clocksource + * @disable: optional function to disable the clocksource +@@ -91,6 +96,7 @@ struct clocksource { + const char *name; + struct list_head list; + int rating; ++ enum clocksource_ids id; + int (*enable)(struct clocksource *cs); + void (*disable)(struct clocksource *cs); + unsigned long flags; +diff --git a/include/linux/clocksource_ids.h b/include/linux/clocksource_ids.h +new file mode 100644 +index 000000000..93bec8426 +--- /dev/null ++++ b/include/linux/clocksource_ids.h +@@ -0,0 +1,13 @@ ++/* 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 000000000..f960a719f +--- /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 a5a3cfc3c..24808479f 100644 +--- a/include/linux/timekeeping.h ++++ b/include/linux/timekeeping.h +@@ -2,6 +2,7 @@ + #ifndef _LINUX_TIMEKEEPING_H + #define _LINUX_TIMEKEEPING_H + ++#include + #include + + /* Included from linux/ktime.h */ +@@ -207,6 +208,7 @@ struct system_time_snapshot { + 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 c297abc4e..e5962ad27 100644 +--- a/include/uapi/linux/kvm.h ++++ b/include/uapi/linux/kvm.h +@@ -956,6 +956,7 @@ struct kvm_ppc_resize_hpt { + #define KVM_CAP_NESTED_STATE 157 + #define KVM_CAP_ARM_INJECT_SERROR_ESR 158 + #define KVM_CAP_MSR_PLATFORM_INFO 159 ++#define KVM_CAP_ARM_KVM_PTP 160 + + #ifdef KVM_CAP_IRQ_ROUTING + +diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c +index f80bb104c..6b3a072a1 100644 +--- a/kernel/time/clocksource.c ++++ b/kernel/time/clocksource.c +@@ -944,6 +944,9 @@ int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq) + { + unsigned long flags; + ++ if (WARN_ON_ONCE((unsigned int)cs->id >= CSID_MAX)) ++ cs->id = CSID_GENERIC; ++ + /* Initialize mult/shift and max_idle_ns */ + __clocksource_update_freq_scale(cs, scale, freq); + +diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c +index c66fd11d9..348ea7de1 100644 +--- a/kernel/time/timekeeping.c ++++ b/kernel/time/timekeeping.c +@@ -978,6 +978,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, +diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c +index d982650de..716b9c7e8 100644 +--- a/virt/kvm/arm/arm.c ++++ b/virt/kvm/arm/arm.c +@@ -212,6 +212,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) + case KVM_CAP_READONLY_MEM: + case KVM_CAP_MP_STATE: + case KVM_CAP_IMMEDIATE_EXIT: ++ case KVM_CAP_ARM_KVM_PTP: + r = 1; + break; + case KVM_CAP_ARM_SET_DEVICE_ADDR: +diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c +index 34d08ee63..0f35819ba 100644 +--- a/virt/kvm/arm/psci.c ++++ b/virt/kvm/arm/psci.c +@@ -398,22 +398,65 @@ static int kvm_psci_call(struct kvm_vcpu *vcpu) + }; + } + ++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); +- u32 val = SMCCC_RET_NOT_SUPPORTED; ++ u64 val[4] = {SMCCC_RET_NOT_SUPPORTED}; + u32 feature; + + 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); + switch(feature) { + case ARM_SMCCC_ARCH_WORKAROUND_1: + if (kvm_arm_harden_branch_predictor()) +- val = SMCCC_RET_SUCCESS; ++ val[0] = SMCCC_RET_SUCCESS; + break; + case ARM_SMCCC_ARCH_WORKAROUND_2: + switch (kvm_arm_have_ssbd()) { +@@ -421,21 +464,46 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) + case KVM_SSBD_UNKNOWN: + break; + case KVM_SSBD_KERNEL: +- val = SMCCC_RET_SUCCESS; ++ val[0] = SMCCC_RET_SUCCESS; + break; + case KVM_SSBD_FORCE_ENABLE: + case KVM_SSBD_MITIGATED: +- val = SMCCC_RET_NOT_REQUIRED; ++ val[0] = SMCCC_RET_NOT_REQUIRED; + break; + } + break; + } + 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; + } + +-- +2.32.0 + diff --git a/tools/packaging/kernel/patches/5.10.x/0001-5.10.x-PTP_KVM-support-for-arm-arm64.patch b/tools/packaging/kernel/patches/5.10.x/0001-5.10.x-PTP_KVM-support-for-arm-arm64.patch new file mode 100644 index 000000000..973678293 --- /dev/null +++ b/tools/packaging/kernel/patches/5.10.x/0001-5.10.x-PTP_KVM-support-for-arm-arm64.patch @@ -0,0 +1,974 @@ +From 772e627bb2aa29a6d006f08bdf7bc1492671d1fe Mon Sep 17 00:00:00 2001 +From: Damon Kwok +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 + #include + ++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 + #include + #include ++#include + #include + #include + #include +@@ -24,6 +25,8 @@ + #include + #include + #include ++#include ++#include + + #include + #include +@@ -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 + #include ++#include ++#include + + 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 ++#include ++ ++#include ++#include ++ ++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 + #include + #include ++#include + #include ++#include + #include + #include +-#include +-#include + #include + + #include +@@ -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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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 ++#include ++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 + #include + #include ++#include + #include + #include + +@@ -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 ++#include + + /* 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 + diff --git a/tools/packaging/kernel/patches/5.4.x/0003-5.4.x-PTP_KVM-support-for-arm-arm64.patch b/tools/packaging/kernel/patches/5.4.x/0003-5.4.x-PTP_KVM-support-for-arm-arm64.patch new file mode 100644 index 000000000..d5ae151ae --- /dev/null +++ b/tools/packaging/kernel/patches/5.4.x/0003-5.4.x-PTP_KVM-support-for-arm-arm64.patch @@ -0,0 +1,1004 @@ +From 0ce25a5ea295ce9406c68b826cd440c56a818c74 Mon Sep 17 00:00:00 2001 +From: Damon Kwok +Date: Thu, 24 Jun 2021 14:54:29 +0800 +Subject: [PATCH] 5.4.x: PTP_KVM support for arm/arm64 + +--- + arch/arm/kernel/setup.c | 2 + + arch/arm64/include/asm/kvm_host.h | 2 + + arch/arm64/kernel/setup.c | 3 + + arch/x86/include/asm/pvclock-abi.h | 2 + + arch/x86/include/asm/pvclock.h | 1 + + drivers/clocksource/arm_arch_timer.c | 33 ++++++ + drivers/firmware/psci/psci.c | 53 +++++++++ + drivers/ptp/Kconfig | 2 +- + drivers/ptp/Makefile | 2 + + drivers/ptp/ptp_kvm_arm.c | 28 +++++ + drivers/ptp/{ptp_kvm.c => ptp_kvm_common.c} | 87 ++++---------- + drivers/ptp/ptp_kvm_x86.c | 87 ++++++++++++++ + include/linux/arm-smccc.h | 124 ++++++++++++++++++++ + include/linux/clocksource.h | 6 + + include/linux/clocksource_ids.h | 13 ++ + include/linux/ptp_kvm.h | 19 +++ + include/linux/timekeeping.h | 12 +- + include/uapi/linux/kvm.h | 1 + + kernel/time/clocksource.c | 3 + + kernel/time/timekeeping.c | 1 + + virt/kvm/arm/arm.c | 1 + + virt/kvm/arm/psci.c | 83 +++++++++++-- + 22 files changed, 489 insertions(+), 76 deletions(-) + 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/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c +index d0a464e..43fc6bb 100644 +--- a/arch/arm/kernel/setup.c ++++ b/arch/arm/kernel/setup.c +@@ -4,6 +4,7 @@ + * + * Copyright (C) 1995-2001 Russell King + */ ++#include + #include + #include + #include +@@ -1139,6 +1140,7 @@ void __init setup_arch(char **cmdline_p) + + arm_dt_init_cpu_maps(); + psci_dt_init(); ++ kvm_init_hyp_services(); + #ifdef CONFIG_SMP + if (is_smp()) { + if (!mdesc->smp_init || !mdesc->smp_init()) { +diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h +index 0c3bd6a..8ff7203 100644 +--- a/arch/arm64/include/asm/kvm_host.h ++++ b/arch/arm64/include/asm/kvm_host.h +@@ -161,6 +161,8 @@ enum vcpu_sysreg { + APDBKEYHI_EL1, + APGAKEYLO_EL1, + APGAKEYHI_EL1, ++ ++ CNTVOFF_EL2, + + /* 32bit specific registers. Keep them at the end of the range */ + DACR32_EL2, /* Domain Access Control Register */ +diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c +index 56f6645..0586edb 100644 +--- a/arch/arm64/kernel/setup.c ++++ b/arch/arm64/kernel/setup.c +@@ -7,6 +7,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -337,6 +338,8 @@ void __init setup_arch(char **cmdline_p) + else + psci_acpi_init(); + ++ kvm_init_hyp_services(); ++ + cpu_read_bootcpu_ops(); + smp_init_cpus(); + smp_build_mpidr_hash(); +diff --git a/arch/x86/include/asm/pvclock-abi.h b/arch/x86/include/asm/pvclock-abi.h +index 1436226..5f96264 100644 +--- a/arch/x86/include/asm/pvclock-abi.h ++++ b/arch/x86/include/asm/pvclock-abi.h +@@ -3,6 +3,8 @@ + #define _ASM_X86_PVCLOCK_ABI_H + #ifndef __ASSEMBLY__ + ++#include ++ + /* + * These structs MUST NOT be changed. + * They are the ABI between hypervisor and guest OS. +diff --git a/arch/x86/include/asm/pvclock.h b/arch/x86/include/asm/pvclock.h +index 19b695f..b6d3da6 100644 +--- a/arch/x86/include/asm/pvclock.h ++++ b/arch/x86/include/asm/pvclock.h +@@ -4,6 +4,7 @@ + + #include + #include ++#include + + /* some helper functions for xen and kvm pv clock sources */ + u64 pvclock_clocksource_read(struct pvclock_vcpu_time_info *src); +diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c +index 4be83b4..ae1d2ce 100644 +--- a/drivers/clocksource/arm_arch_timer.c ++++ b/drivers/clocksource/arm_arch_timer.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -24,6 +25,8 @@ + #include + #include + #include ++#include ++#include + + #include + #include +@@ -187,6 +190,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), +@@ -1634,3 +1638,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/psci/psci.c b/drivers/firmware/psci/psci.c +index 84f4ff3..19932f1 100644 +--- a/drivers/firmware/psci/psci.c ++++ b/drivers/firmware/psci/psci.c +@@ -8,6 +8,8 @@ + + #include + #include ++#include ++#include + #include + #include + #include +@@ -57,6 +59,57 @@ struct psci_operations psci_ops = { + .smccc_version = SMCCC_VERSION_1_0, + }; + ++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 (psci_ops.smccc_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); ++} ++ ++enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void) ++{ ++ if (psci_ops.smccc_version < SMCCC_VERSION_1_1) ++ return SMCCC_CONDUIT_NONE; ++ ++ switch (psci_ops.conduit) { ++ case PSCI_CONDUIT_SMC: ++ return SMCCC_CONDUIT_SMC; ++ case PSCI_CONDUIT_HVC: ++ return SMCCC_CONDUIT_HVC; ++ default: ++ return SMCCC_CONDUIT_NONE; ++ } ++} ++EXPORT_SYMBOL(arm_smccc_1_1_get_conduit); ++ + typedef unsigned long (psci_fn)(unsigned long, unsigned long, + unsigned long, unsigned long); + static psci_fn *invoke_psci_fn; +diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig +index 0517272..f647a2f 100644 +--- a/drivers/ptp/Kconfig ++++ b/drivers/ptp/Kconfig +@@ -110,7 +110,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 || ((ARM || ARM64) && ARM_ARCH_TIMER && ARM_PSCI_FW) + 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 677d1d1..052645a 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_IXP46X) += ptp_ixp46x.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 ++#include ++ ++#include ++#include ++ ++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 fc7d0b7..5c36e2f 100644 +--- a/drivers/ptp/ptp_kvm.c ++++ b/drivers/ptp/ptp_kvm_common.c +@@ -8,11 +8,11 @@ + #include + #include + #include ++#include + #include ++#include + #include + #include +-#include +-#include + #include + + #include +@@ -22,58 +22,31 @@ struct kvm_ptp_clock { + struct ptp_clock_info caps; + }; + +-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 DEFINE_SPINLOCK(kvm_ptp_lock); + + 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..4add42a +--- /dev/null ++++ b/drivers/ptp/ptp_kvm_x86.c +@@ -0,0 +1,87 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Virtual PTP 1588 clock for use with KVM guests ++ * ++ * Copyright (C) 2017 Red Hat Inc. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++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) ++{ ++ int 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) ++ 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); ++ 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 080012a..784ebf6 100644 +--- a/include/linux/arm-smccc.h ++++ b/include/linux/arm-smccc.h +@@ -5,6 +5,7 @@ + #ifndef __LINUX_ARM_SMCCC_H + #define __LINUX_ARM_SMCCC_H + ++#include + #include + + /* +@@ -45,11 +46,15 @@ + #define ARM_SMCCC_OWNER_SIP 2 + #define ARM_SMCCC_OWNER_OEM 3 + #define ARM_SMCCC_OWNER_STANDARD 4 ++#define ARM_SMCCC_OWNER_STANDARD_HYP 5 ++#define ARM_SMCCC_OWNER_VENDOR_HYP 6 + #define ARM_SMCCC_OWNER_TRUSTED_APP 48 + #define ARM_SMCCC_OWNER_TRUSTED_APP_END 49 + #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 */ + +@@ -75,11 +80,67 @@ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + 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 + + #ifndef __ASSEMBLY__ + + #include + #include ++ ++enum arm_smccc_conduit { ++ SMCCC_CONDUIT_NONE, ++ SMCCC_CONDUIT_SMC, ++ SMCCC_CONDUIT_HVC, ++}; ++ ++/** ++ * arm_smccc_1_1_get_conduit() ++ * ++ * Returns the conduit to be used for SMCCCv1.1 or later. ++ * ++ * When SMCCCv1.1 is not present, returns SMCCC_CONDUIT_NONE. ++ */ ++enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void); ++ + /** + * struct arm_smccc_res - Result from SMC/HVC call + * @a0-a3 result values from registers 0 to 3 +@@ -302,5 +363,68 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1, + #define SMCCC_RET_NOT_SUPPORTED -1 + #define SMCCC_RET_NOT_REQUIRED -2 + ++/* ++ * Like arm_smccc_1_1* but always returns SMCCC_RET_NOT_SUPPORTED. ++ * Used when the SMCCC conduit is not defined. The empty asm statement ++ * avoids compiler warnings about unused variables. ++ */ ++#define __fail_smccc_1_1(...) \ ++ do { \ ++ __declare_args(__count_args(__VA_ARGS__), __VA_ARGS__); \ ++ asm ("" __constraints(__count_args(__VA_ARGS__))); \ ++ if (___res) \ ++ ___res->a0 = SMCCC_RET_NOT_SUPPORTED; \ ++ } while (0) ++ ++/* ++ * arm_smccc_1_1_invoke() - make an SMCCC v1.1 compliant call ++ * ++ * This is a variadic macro taking one to eight source arguments, and ++ * an optional return structure. ++ * ++ * @a0-a7: arguments passed in registers 0 to 7 ++ * @res: result values from registers 0 to 3 ++ * ++ * This macro will make either an HVC call or an SMC call depending on the ++ * current SMCCC conduit. If no valid conduit is available then -1 ++ * (SMCCC_RET_NOT_SUPPORTED) is returned in @res.a0 (if supplied). ++ * ++ * The return value also provides the conduit that was used. ++ */ ++#define arm_smccc_1_1_invoke(...) ({ \ ++ int method = arm_smccc_1_1_get_conduit(); \ ++ switch (method) { \ ++ case SMCCC_CONDUIT_HVC: \ ++ arm_smccc_1_1_hvc(__VA_ARGS__); \ ++ break; \ ++ case SMCCC_CONDUIT_SMC: \ ++ arm_smccc_1_1_smc(__VA_ARGS__); \ ++ break; \ ++ default: \ ++ __fail_smccc_1_1(__VA_ARGS__); \ ++ method = SMCCC_CONDUIT_NONE; \ ++ break; \ ++ } \ ++ 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 ++#include ++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 b21db53..96e85b6 100644 +--- a/include/linux/clocksource.h ++++ b/include/linux/clocksource.h +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -49,6 +50,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. + * @read: returns a cycle value, passes clocksource as argument + * @enable: optional function to enable the clocksource + * @disable: optional function to disable the clocksource +@@ -91,6 +96,7 @@ struct clocksource { + const char *name; + struct list_head list; + int rating; ++ enum clocksource_ids id; + int (*enable)(struct clocksource *cs); + void (*disable)(struct clocksource *cs); + unsigned long flags; +diff --git a/include/linux/clocksource_ids.h b/include/linux/clocksource_ids.h +new file mode 100644 +index 0000000..93bec84 +--- /dev/null ++++ b/include/linux/clocksource_ids.h +@@ -0,0 +1,13 @@ ++/* 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 b27e2ff..4ecc32a 100644 +--- a/include/linux/timekeeping.h ++++ b/include/linux/timekeeping.h +@@ -2,6 +2,7 @@ + #ifndef _LINUX_TIMEKEEPING_H + #define _LINUX_TIMEKEEPING_H + ++#include + #include + + /* Included from linux/ktime.h */ +@@ -232,11 +233,12 @@ extern void timekeeping_inject_sleeptime64(const struct timespec64 *delta); + * @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 e735bc4..8bee40d 100644 +--- a/include/uapi/linux/kvm.h ++++ b/include/uapi/linux/kvm.h +@@ -1002,6 +1002,7 @@ struct kvm_ppc_resize_hpt { + #define KVM_CAP_PMU_EVENT_FILTER 173 + #define KVM_CAP_ARM_IRQ_LINE_LAYOUT_2 174 + #define KVM_CAP_HYPERV_DIRECT_TLBFLUSH 175 ++#define KVM_CAP_ARM_KVM_PTP 176 + + #ifdef KVM_CAP_IRQ_ROUTING + +diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c +index 428beb6..ae683f7 100644 +--- a/kernel/time/clocksource.c ++++ b/kernel/time/clocksource.c +@@ -928,6 +928,9 @@ 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; ++ + /* Initialize mult/shift and max_idle_ns */ + __clocksource_update_freq_scale(cs, scale, freq); + +diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c +index ca69290..a8b3783 100644 +--- a/kernel/time/timekeeping.c ++++ b/kernel/time/timekeeping.c +@@ -979,6 +979,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, +diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c +index 986fbc3..2764360 100644 +--- a/virt/kvm/arm/arm.c ++++ b/virt/kvm/arm/arm.c +@@ -197,6 +197,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) + case KVM_CAP_IMMEDIATE_EXIT: + case KVM_CAP_VCPU_EVENTS: + case KVM_CAP_ARM_IRQ_LINE_LAYOUT_2: ++ case KVM_CAP_ARM_KVM_PTP: + r = 1; + break; + case KVM_CAP_ARM_SET_DEVICE_ADDR: +diff --git a/virt/kvm/arm/psci.c b/virt/kvm/arm/psci.c +index 87927f7..621979b 100644 +--- a/virt/kvm/arm/psci.c ++++ b/virt/kvm/arm/psci.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -387,15 +388,58 @@ static int kvm_psci_call(struct kvm_vcpu *vcpu) + }; + } + ++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); +- u32 val = SMCCC_RET_NOT_SUPPORTED; ++ u64 val[4] = {SMCCC_RET_NOT_SUPPORTED}; + u32 feature; + + 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); +@@ -405,10 +449,10 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) + case KVM_BP_HARDEN_UNKNOWN: + break; + case KVM_BP_HARDEN_WA_NEEDED: +- val = SMCCC_RET_SUCCESS; ++ val[0] = SMCCC_RET_SUCCESS; + break; + case KVM_BP_HARDEN_NOT_REQUIRED: +- val = SMCCC_RET_NOT_REQUIRED; ++ val[0] = SMCCC_RET_NOT_REQUIRED; + break; + } + break; +@@ -418,21 +462,46 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) + case KVM_SSBD_UNKNOWN: + break; + case KVM_SSBD_KERNEL: +- val = SMCCC_RET_SUCCESS; ++ val[0] = SMCCC_RET_SUCCESS; + break; + case KVM_SSBD_FORCE_ENABLE: + case KVM_SSBD_MITIGATED: +- val = SMCCC_RET_NOT_REQUIRED; ++ val[0] = SMCCC_RET_NOT_REQUIRED; + break; + } + break; + } + 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; + } + +-- +2.32.0 + diff --git a/tools/packaging/kernel/patches/5.4.x/0003-arm-arm64-Provide-a-wrapper-for-SMCCC-1.1-calls.patch b/tools/packaging/kernel/patches/5.4.x/0003-arm-arm64-Provide-a-wrapper-for-SMCCC-1.1-calls.patch deleted file mode 100644 index 02125e83e..000000000 --- a/tools/packaging/kernel/patches/5.4.x/0003-arm-arm64-Provide-a-wrapper-for-SMCCC-1.1-calls.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 3d1d7f8922ed2f080f6d8e08df0d51e22f9590ec Mon Sep 17 00:00:00 2001 -From: Jianyong Wu -Date: Wed, 1 Apr 2020 15:19:29 +0800 -Subject: [PATCH 1/9] arm/arm64: Provide a wrapper for SMCCC 1.1 calls - -From: Steven Price - -SMCCC 1.1 calls may use either HVC or SMC depending on the PSCI -conduit. Rather than coding this in every call site, provide a macro -which uses the correct instruction. The macro also handles the case -where no conduit is configured/available returning a not supported error -in res, along with returning the conduit used for the call. - -This allow us to remove some duplicated code and will be useful later -when adding paravirtualized time hypervisor calls. - -Signed-off-by: Steven Price -Acked-by: Will Deacon -Signed-off-by: Marc Zyngier ---- - include/linux/arm-smccc.h | 45 +++++++++++++++++++++++++++++++++++++++ - 1 file changed, 45 insertions(+) - -diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h -index 080012a6f025..131edde5d37e 100644 ---- a/include/linux/arm-smccc.h -+++ b/include/linux/arm-smccc.h -@@ -302,5 +302,50 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1, - #define SMCCC_RET_NOT_SUPPORTED -1 - #define SMCCC_RET_NOT_REQUIRED -2 - -+/* -+ * Like arm_smccc_1_1* but always returns SMCCC_RET_NOT_SUPPORTED. -+ * Used when the SMCCC conduit is not defined. The empty asm statement -+ * avoids compiler warnings about unused variables. -+ */ -+#define __fail_smccc_1_1(...) \ -+ do { \ -+ __declare_args(__count_args(__VA_ARGS__), __VA_ARGS__); \ -+ asm ("" __constraints(__count_args(__VA_ARGS__))); \ -+ if (___res) \ -+ ___res->a0 = SMCCC_RET_NOT_SUPPORTED; \ -+ } while (0) -+ -+/* -+ * arm_smccc_1_1_invoke() - make an SMCCC v1.1 compliant call -+ * -+ * This is a variadic macro taking one to eight source arguments, and -+ * an optional return structure. -+ * -+ * @a0-a7: arguments passed in registers 0 to 7 -+ * @res: result values from registers 0 to 3 -+ * -+ * This macro will make either an HVC call or an SMC call depending on the -+ * current SMCCC conduit. If no valid conduit is available then -1 -+ * (SMCCC_RET_NOT_SUPPORTED) is returned in @res.a0 (if supplied). -+ * -+ * The return value also provides the conduit that was used. -+ */ -+#define arm_smccc_1_1_invoke(...) ({ \ -+ int method = arm_smccc_1_1_get_conduit(); \ -+ switch (method) { \ -+ case SMCCC_CONDUIT_HVC: \ -+ arm_smccc_1_1_hvc(__VA_ARGS__); \ -+ break; \ -+ case SMCCC_CONDUIT_SMC: \ -+ arm_smccc_1_1_smc(__VA_ARGS__); \ -+ break; \ -+ default: \ -+ __fail_smccc_1_1(__VA_ARGS__); \ -+ method = SMCCC_CONDUIT_NONE; \ -+ break; \ -+ } \ -+ method; \ -+ }) -+ - #endif /*__ASSEMBLY__*/ - #endif /*__LINUX_ARM_SMCCC_H*/ --- -2.17.1 - diff --git a/tools/packaging/kernel/patches/5.4.x/0004-arm-arm64-smccc-psci-add-arm_smccc_1_1_get_conduit.patch b/tools/packaging/kernel/patches/5.4.x/0004-arm-arm64-smccc-psci-add-arm_smccc_1_1_get_conduit.patch deleted file mode 100644 index 3e18036a0..000000000 --- a/tools/packaging/kernel/patches/5.4.x/0004-arm-arm64-smccc-psci-add-arm_smccc_1_1_get_conduit.patch +++ /dev/null @@ -1,81 +0,0 @@ -From b830806f5cd02119be9b25812b3ea56d97cd08f3 Mon Sep 17 00:00:00 2001 -From: Mark Rutland -Date: Fri, 9 Aug 2019 14:22:40 +0100 -Subject: [PATCH 2/9] arm/arm64: smccc/psci: add arm_smccc_1_1_get_conduit() - -SMCCC callers are currently amassing a collection of enums for the SMCCC -conduit, and are having to dig into the PSCI driver's internals in order -to figure out what to do. - -Let's clean this up, with common SMCCC_CONDUIT_* definitions, and an -arm_smccc_1_1_get_conduit() helper that abstracts the PSCI driver's -internal state. - -We can kill off the PSCI_CONDUIT_* definitions once we've migrated users -over to the new interface. - -Signed-off-by: Mark Rutland -Acked-by: Lorenzo Pieralisi -Acked-by: Will Deacon -Signed-off-by: Catalin Marinas ---- - drivers/firmware/psci/psci.c | 15 +++++++++++++++ - include/linux/arm-smccc.h | 16 ++++++++++++++++ - 2 files changed, 31 insertions(+) - -diff --git a/drivers/firmware/psci/psci.c b/drivers/firmware/psci/psci.c -index 84f4ff351c62..eb797081d159 100644 ---- a/drivers/firmware/psci/psci.c -+++ b/drivers/firmware/psci/psci.c -@@ -57,6 +57,21 @@ struct psci_operations psci_ops = { - .smccc_version = SMCCC_VERSION_1_0, - }; - -+enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void) -+{ -+ if (psci_ops.smccc_version < SMCCC_VERSION_1_1) -+ return SMCCC_CONDUIT_NONE; -+ -+ switch (psci_ops.conduit) { -+ case PSCI_CONDUIT_SMC: -+ return SMCCC_CONDUIT_SMC; -+ case PSCI_CONDUIT_HVC: -+ return SMCCC_CONDUIT_HVC; -+ default: -+ return SMCCC_CONDUIT_NONE; -+ } -+} -+ - typedef unsigned long (psci_fn)(unsigned long, unsigned long, - unsigned long, unsigned long); - static psci_fn *invoke_psci_fn; -diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h -index 131edde5d37e..e6d4cb4f61f1 100644 ---- a/include/linux/arm-smccc.h -+++ b/include/linux/arm-smccc.h -@@ -80,6 +80,22 @@ - - #include - #include -+ -+enum arm_smccc_conduit { -+ SMCCC_CONDUIT_NONE, -+ SMCCC_CONDUIT_SMC, -+ SMCCC_CONDUIT_HVC, -+}; -+ -+/** -+ * arm_smccc_1_1_get_conduit() -+ * -+ * Returns the conduit to be used for SMCCCv1.1 or later. -+ * -+ * When SMCCCv1.1 is not present, returns SMCCC_CONDUIT_NONE. -+ */ -+enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void); -+ - /** - * struct arm_smccc_res - Result from SMC/HVC call - * @a0-a3 result values from registers 0 to 3 --- -2.17.1 -