|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v2 7/8] x86/xen/time: Use VCPUOP_register_{runstate,vcpu_time}_phys_area when available
Updating these area can be expensive when done through virtual addresses
(especially for runstate one), in particular for HVM/PVH guests.
Xen 4.18 introduced physical address alternatives to address those
short-commings, but they aren't used currently.
Fix it by using these alternatives when available (when reported in
XENFEAT_{runstate,vcpu_time}_phys_area.
Assisted-by: LLM
[guidance and testing]
Signed-off-by: Teddy Astie <teddy.astie@xxxxxxxxxx>
---
CC: Juergen Gross <jgross@xxxxxxxx>
CC: Boris Ostrovsky <boris.ostrovsky@xxxxxxxxxx>
CC: Stefano Stabellini <sstabellini@xxxxxxxxxx>
CC: Oleksandr Tyshchenko <oleksandr_tyshchenko@xxxxxxxx>
CC: David Woodhouse <dwmw2@xxxxxxxxxxxxx>
CC: George Dunlap <gwd@xxxxxxxxxxxxxx>
CC: x86@xxxxxxxxxx
CC: linux-kernel@xxxxxxxxxxxxxxx
For PV, this actually depends on
"x86/xen/pv: Don't setup runstate area too early"
When using phys_area ABI, the struct is not allowed to cross a page
boundary anymore, hence we need to be careful with per-cpu struct
alignment.
v2:
- Add PV domain support.
- Clarify xen_register_time_area()
- fold out &per_cpu(xen_runstate, cpu) in a separate variable
---
arch/x86/xen/time.c | 42 ++++++++++++++++++++------------
drivers/xen/time.c | 24 +++++++++++++-----
include/xen/interface/features.h | 9 +++++++
include/xen/interface/vcpu.h | 17 +++++++++++++
4 files changed, 71 insertions(+), 21 deletions(-)
diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
index 0d8643cc8159..5fa22925c0d5 100644
--- a/arch/x86/xen/time.c
+++ b/arch/x86/xen/time.c
@@ -21,6 +21,7 @@
#include <asm/cpuid/api.h>
#include <asm/pvclock.h>
#include <asm/timer.h>
+#include <asm/xen/page.h>
#include <asm/xen/hypervisor.h>
#include <asm/xen/hypercall.h>
#include <asm/xen/cpuid.h>
@@ -37,6 +38,28 @@
static u64 xen_sched_clock_offset __read_mostly;
+/*
+ * Register the vcpu time info for vCPU 0 to pvti.
+ * When NULL is passed, unregister the time area instead.
+ *
+ * Register using physical address when available (reported by
+ * XENFEAT_vcpu_time_phys_area), and use virtual address otherwise.
+ */
+static int xen_register_time_area(struct pvclock_vcpu_time_info *pvti)
+{
+ struct vcpu_register_time_memory_area t;
+ bool phys = xen_feature(XENFEAT_vcpu_time_phys_area);
+ int op = phys ? VCPUOP_register_vcpu_time_phys_area
+ : VCPUOP_register_vcpu_time_memory_area;
+
+ if (phys)
+ t.addr.p = pvti ? virt_to_guest(pvti).gaddr : ~0LLU;
+ else
+ t.addr.v = pvti;
+
+ return HYPERVISOR_vcpu_op(op, 0, &t);
+}
+
/* Get the TSC speed from Xen */
static unsigned long xen_tsc_khz(void)
{
@@ -395,7 +418,6 @@ static u64 xen_clock_value_saved;
void xen_save_time_memory_area(void)
{
- struct vcpu_register_time_memory_area t;
int ret;
xen_clock_value_saved = xen_clocksource_read() - xen_sched_clock_offset;
@@ -403,25 +425,20 @@ void xen_save_time_memory_area(void)
if (!xen_clock)
return;
- t.addr.v = NULL;
-
- ret = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_time_memory_area, 0, &t);
+ ret = xen_register_time_area(NULL);
if (ret != 0)
pr_notice("Cannot unregister vcpu_time_info (err %d)", ret);
}
void xen_restore_time_memory_area(void)
{
- struct vcpu_register_time_memory_area t;
int ret;
if (!xen_clock)
goto out;
memset(xen_clock, 0, sizeof(*xen_clock));
- t.addr.v = &xen_clock->pvti;
-
- ret = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_time_memory_area, 0, &t);
+ ret = xen_register_time_area(&xen_clock->pvti);
/*
* We don't disable VDSO_CLOCKMODE_PVCLOCK entirely if it fails to
@@ -444,7 +461,6 @@ void xen_restore_time_memory_area(void)
static void __init xen_setup_vsyscall_time_info(void)
{
- struct vcpu_register_time_memory_area t;
struct pvclock_vsyscall_time_info *ti;
int ret;
@@ -452,9 +468,7 @@ static void __init xen_setup_vsyscall_time_info(void)
if (!ti)
return;
- t.addr.v = &ti->pvti;
-
- ret = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_time_memory_area, 0, &t);
+ ret = xen_register_time_area(&ti->pvti);
if (ret) {
pr_notice("xen: VDSO_CLOCKMODE_PVCLOCK not supported (err
%d)\n", ret);
free_page((unsigned long)ti);
@@ -467,9 +481,7 @@ static void __init xen_setup_vsyscall_time_info(void)
* still check it in case hypervisor is buggy.
*/
if (!(ti->pvti.flags & PVCLOCK_TSC_STABLE_BIT)) {
- t.addr.v = NULL;
- ret = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_time_memory_area,
- 0, &t);
+ ret = xen_register_time_area(NULL);
if (!ret)
free_page((unsigned long)ti);
diff --git a/drivers/xen/time.c b/drivers/xen/time.c
index a2be0a4d45b0..49e61ad905d9 100644
--- a/drivers/xen/time.c
+++ b/drivers/xen/time.c
@@ -10,6 +10,7 @@
#include <linux/static_call.h>
#include <linux/sched/cputime.h>
+#include <asm/xen/page.h>
#include <asm/xen/hypervisor.h>
#include <asm/xen/hypercall.h>
@@ -19,8 +20,12 @@
#include <xen/interface/vcpu.h>
#include <xen/xen-ops.h>
-/* runstate info updated by Xen */
-static DEFINE_PER_CPU(struct vcpu_runstate_info, xen_runstate);
+/*
+ * Runstate info updated by Xen. The phys-area ABI doesn't allow it to cross
+ * a page boundary; the struct is 48 bytes, so 64 is the smallest alignment
+ * that guarantees this.
+ */
+static DEFINE_PER_CPU(struct vcpu_runstate_info, xen_runstate) __aligned(64);
static DEFINE_PER_CPU(u64[4], old_runstate_time);
@@ -152,11 +157,18 @@ u64 xen_steal_clock(int cpu)
void xen_setup_runstate_info(int cpu)
{
struct vcpu_register_runstate_memory_area area;
+ unsigned int op;
+ struct vcpu_runstate_info *cpu_runstate = &per_cpu(xen_runstate, cpu);
+
+ if (xen_feature(XENFEAT_runstate_phys_area)) {
+ op = VCPUOP_register_runstate_phys_area;
+ area.addr.p = percpu_to_gaddr(cpu_runstate).gaddr;
+ } else {
+ op = VCPUOP_register_runstate_memory_area;
+ area.addr.v = cpu_runstate;
+ }
- area.addr.v = &per_cpu(xen_runstate, cpu);
-
- if (HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area,
- xen_vcpu_nr(cpu), &area))
+ if (HYPERVISOR_vcpu_op(op, xen_vcpu_nr(cpu), &area))
BUG();
}
diff --git a/include/xen/interface/features.h b/include/xen/interface/features.h
index 53f760378e39..f00144a7c790 100644
--- a/include/xen/interface/features.h
+++ b/include/xen/interface/features.h
@@ -97,6 +97,15 @@
#define XENFEAT_not_direct_mapped 16
#define XENFEAT_direct_mapped 17
+/*
+ * Signal whether the domain is able to use the following hypercalls:
+ *
+ * VCPUOP_register_runstate_phys_area
+ * VCPUOP_register_vcpu_time_phys_area
+ */
+#define XENFEAT_runstate_phys_area 18
+#define XENFEAT_vcpu_time_phys_area 19
+
#define XENFEAT_NR_SUBMAPS 1
#endif /* __XEN_PUBLIC_FEATURES_H__ */
diff --git a/include/xen/interface/vcpu.h b/include/xen/interface/vcpu.h
index c7cc28ad8d63..d3858233c32f 100644
--- a/include/xen/interface/vcpu.h
+++ b/include/xen/interface/vcpu.h
@@ -203,4 +203,21 @@ struct vcpu_register_time_memory_area {
};
DEFINE_GUEST_HANDLE_STRUCT(vcpu_register_time_memory_area);
+/*
+ * Like the respective VCPUOP_register_*_memory_area, just using the "addr.p"
+ * field of the supplied struct as a guest physical address (i.e. in GFN
space).
+ * The respective area may not cross a page boundary. Pass ~0 to unregister an
+ * area. Note that as long as an area is registered by physical address, the
+ * linear address based area will not be serviced (updated) by the hypervisor.
+ *
+ * Note that the area registered via VCPUOP_register_runstate_phys_area will
+ * be updated in the same manner as the one registered via virtual address PLUS
+ * VMASST_TYPE_runstate_update_flag engaged by the domain.
+ *
+ * XENFEAT_{runstate,vcpu_time}_phys_area feature bits signal the availability
+ * of these ops.
+ */
+#define VCPUOP_register_runstate_phys_area 14
+#define VCPUOP_register_vcpu_time_phys_area 15
+
#endif /* __XEN_PUBLIC_VCPU_H__ */
--
2.56.0
--
Teddy Astie | Vates XCP-ng Developer
XCP-ng & Xen Orchestra - Vates solutions
web: https://vates.tech
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |