diff options
| author | Paolo Bonzini <pbonzini@redhat.com> | 2021-04-23 07:41:17 -0400 | 
|---|---|---|
| committer | Paolo Bonzini <pbonzini@redhat.com> | 2021-04-23 07:41:17 -0400 | 
| commit | c4f71901d53b6d8a4703389459d9f99fbd80ffd2 (patch) | |
| tree | af8a0c33cec6dfb8a5d5cd7fcef245ab02b12691 /drivers/ptp | |
| parent | fd49e8ee70b306a003323a17bbcc0633f322c135 (diff) | |
| parent | 9a8aae605b80fc0a830cdce747eed48e11acc067 (diff) | |
| download | linux-c4f71901d53b6d8a4703389459d9f99fbd80ffd2.tar.bz2 | |
Merge tag 'kvmarm-5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD
KVM/arm64 updates for Linux 5.13
New features:
- Stage-2 isolation for the host kernel when running in protected mode
- Guest SVE support when running in nVHE mode
- Force W^X hypervisor mappings in nVHE mode
- ITS save/restore for guests using direct injection with GICv4.1
- nVHE panics now produce readable backtraces
- Guest support for PTP using the ptp_kvm driver
- Performance improvements in the S2 fault handler
- Alexandru is now a reviewer (not really a new feature...)
Fixes:
- Proper emulation of the GICR_TYPER register
- Handle the complete set of relocation in the nVHE EL2 object
- Get rid of the oprofile dependency in the PMU code (and of the
  oprofile body parts at the same time)
- Debug and SPE fixes
- Fix vcpu reset
Diffstat (limited to 'drivers/ptp')
| -rw-r--r-- | drivers/ptp/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/ptp/Makefile | 2 | ||||
| -rw-r--r-- | drivers/ptp/ptp_kvm_arm.c | 28 | ||||
| -rw-r--r-- | drivers/ptp/ptp_kvm_common.c (renamed from drivers/ptp/ptp_kvm.c) | 85 | ||||
| -rw-r--r-- | drivers/ptp/ptp_kvm_x86.c | 97 | 
5 files changed, 151 insertions, 63 deletions
| diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig index f2edef0df40f..8c20e524e9ad 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 (KVM_GUEST && 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 db5aef3bddc6..8673d1743faa 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 000000000000..b7d28c8dfb84 --- /dev/null +++ b/drivers/ptp/ptp_kvm_arm.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + *  Virtual PTP 1588 clock for use with KVM guests + *  Copyright (C) 2019 ARM Ltd. + *  All Rights Reserved + */ + +#include <linux/arm-smccc.h> +#include <linux/ptp_kvm.h> + +#include <asm/arch_timer.h> +#include <asm/hypervisor.h> + +int kvm_arch_ptp_init(void) +{ +	int ret; + +	ret = kvm_arm_hyp_service_available(ARM_SMCCC_KVM_FUNC_PTP); +	if (ret <= 0) +		return -EOPNOTSUPP; + +	return 0; +} + +int kvm_arch_ptp_get_clock(struct timespec64 *ts) +{ +	return kvm_arch_ptp_get_crosststamp(NULL, ts, NULL); +} diff --git a/drivers/ptp/ptp_kvm.c b/drivers/ptp/ptp_kvm_common.c index 658d33fc3195..fcae32f56f25 100644 --- a/drivers/ptp/ptp_kvm.c +++ b/drivers/ptp/ptp_kvm_common.c @@ -8,11 +8,11 @@  #include <linux/err.h>  #include <linux/init.h>  #include <linux/kernel.h> +#include <linux/slab.h>  #include <linux/module.h> +#include <linux/ptp_kvm.h>  #include <uapi/linux/kvm_para.h>  #include <asm/kvm_para.h> -#include <asm/pvclock.h> -#include <asm/kvmclock.h>  #include <uapi/asm/kvm_para.h>  #include <linux/ptp_clock_kernel.h> @@ -24,56 +24,29 @@ struct kvm_ptp_clock {  static DEFINE_SPINLOCK(kvm_ptp_lock); -static struct pvclock_vsyscall_time_info *hv_clock; - -static struct kvm_clock_pairing clock_pair; -static phys_addr_t clock_pair_gpa; -  static int ptp_kvm_get_time_fn(ktime_t *device_time,  			       struct system_counterval_t *system_counter,  			       void *ctx)  { -	unsigned long ret; +	long ret; +	u64 cycle;  	struct timespec64 tspec; -	unsigned version; -	int cpu; -	struct pvclock_vcpu_time_info *src; +	struct clocksource *cs;  	spin_lock(&kvm_ptp_lock);  	preempt_disable_notrace(); -	cpu = smp_processor_id(); -	src = &hv_clock[cpu].pvti; - -	do { -		/* -		 * We are using a TSC value read in the hosts -		 * kvm_hc_clock_pairing handling. -		 * So any changes to tsc_to_system_mul -		 * and tsc_shift or any other pvclock -		 * data invalidate that measurement. -		 */ -		version = pvclock_read_begin(src); - -		ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING, -				     clock_pair_gpa, -				     KVM_CLOCK_PAIRING_WALLCLOCK); -		if (ret != 0) { -			pr_err_ratelimited("clock pairing hypercall ret %lu\n", ret); -			spin_unlock(&kvm_ptp_lock); -			preempt_enable_notrace(); -			return -EOPNOTSUPP; -		} - -		tspec.tv_sec = clock_pair.sec; -		tspec.tv_nsec = clock_pair.nsec; -		ret = __pvclock_read_cycles(src, clock_pair.tsc); -	} while (pvclock_read_retry(src, version)); +	ret = kvm_arch_ptp_get_crosststamp(&cycle, &tspec, &cs); +	if (ret) { +		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 000000000000..3dd519dfc473 --- /dev/null +++ b/drivers/ptp/ptp_kvm_x86.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Virtual PTP 1588 clock for use with KVM guests + * + * Copyright (C) 2017 Red Hat Inc. + */ + +#include <linux/device.h> +#include <linux/kernel.h> +#include <asm/pvclock.h> +#include <asm/kvmclock.h> +#include <linux/module.h> +#include <uapi/asm/kvm_para.h> +#include <uapi/linux/kvm_para.h> +#include <linux/ptp_clock_kernel.h> +#include <linux/ptp_kvm.h> + +struct pvclock_vsyscall_time_info *hv_clock; + +static phys_addr_t clock_pair_gpa; +static struct kvm_clock_pairing clock_pair; + +int kvm_arch_ptp_init(void) +{ +	long ret; + +	if (!kvm_para_available()) +		return -ENODEV; + +	clock_pair_gpa = slow_virt_to_phys(&clock_pair); +	hv_clock = pvclock_get_pvti_cpu0_va(); +	if (!hv_clock) +		return -ENODEV; + +	ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING, clock_pair_gpa, +			     KVM_CLOCK_PAIRING_WALLCLOCK); +	if (ret == -KVM_ENOSYS || ret == -KVM_EOPNOTSUPP) +		return -ENODEV; + +	return 0; +} + +int kvm_arch_ptp_get_clock(struct timespec64 *ts) +{ +	long ret; + +	ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING, +			     clock_pair_gpa, +			     KVM_CLOCK_PAIRING_WALLCLOCK); +	if (ret != 0) { +		pr_err_ratelimited("clock offset hypercall ret %lu\n", ret); +		return -EOPNOTSUPP; +	} + +	ts->tv_sec = clock_pair.sec; +	ts->tv_nsec = clock_pair.nsec; + +	return 0; +} + +int kvm_arch_ptp_get_crosststamp(u64 *cycle, struct timespec64 *tspec, +			      struct clocksource **cs) +{ +	struct pvclock_vcpu_time_info *src; +	unsigned int version; +	long ret; +	int cpu; + +	cpu = smp_processor_id(); +	src = &hv_clock[cpu].pvti; + +	do { +		/* +		 * We are using a TSC value read in the hosts +		 * kvm_hc_clock_pairing handling. +		 * So any changes to tsc_to_system_mul +		 * and tsc_shift or any other pvclock +		 * data invalidate that measurement. +		 */ +		version = pvclock_read_begin(src); + +		ret = kvm_hypercall2(KVM_HC_CLOCK_PAIRING, +				     clock_pair_gpa, +				     KVM_CLOCK_PAIRING_WALLCLOCK); +		if (ret != 0) { +			pr_err_ratelimited("clock pairing hypercall ret %lu\n", ret); +			return -EOPNOTSUPP; +		} +		tspec->tv_sec = clock_pair.sec; +		tspec->tv_nsec = clock_pair.nsec; +		*cycle = __pvclock_read_cycles(src, clock_pair.tsc); +	} while (pvclock_read_retry(src, version)); + +	*cs = &kvm_clock; + +	return 0; +} |