Hyper-V: paravirtualized remote TLB flushing and hypercall improvements
Subsystems (3)
v9 cover Hyper-V: paravirtualized remote TLB flushing and hypercall improvements
It seems the series missed 4.13 merge window, rebase and resend.
Changes since v8:
- Rebase to the current char-misc tree (mostly to account for the newly added struct flush_tlb_info in tlb flush interfaces).
- PATCH07: drop hv_tmpcpumap as we have global infrastructure now.
- PATCH08: make fill_gva_list() return 'gva_n - offset' as we were doing too many REPs before (offset is the size of variable header, we don't need to include it in REP count when doing hypercall).
- PATCH08/09: add setup_clear_cpu_cap(X86_FEATURE_PCID) to future proof the code if PCID feature appears in Hyper-V guests.
- Add Andy's/Stephen's Reviewed-by: to all patches (hopefully they stand with the above mentioned changes).
P.S. I'm traveling next two weeks, my responses will probably be delayed.
Original description:
Hyper-V supports hypercalls for doing local and remote TLB flushing and gives its guests hints when using hypercall is preferred. While doing hypercalls for local TLB flushes is probably not practical (and is not being suggested by modern Hyper-V versions) remote TLB flush with a hypercall brings significant improvement.
To test the series I wrote a special 'TLB trasher': on a 16 vCPU guest I was creating 32 threads which were doing 100000 mmap/munmaps each on some big file. Here are the results:
Before:
# time ./pthread_mmap ./randfile real 3m33.118s user 0m3.698s sys 3m16.624s
After:
# time ./pthread_mmap ./randfile real 2m19.920s user 0m2.662s sys 2m9.948s
This series brings a number of small improvements along the way: fast hypercall implementation and using it for event signaling, rep hypercalls implementation, hyperv tracing subsystem (which only traces the newly added remote TLB flush for now).
Vitaly Kuznetsov (10):
x86/hyper-v: include hyperv/ only when CONFIG_HYPERV is set x86/hyper-v: stash the max number of virtual/logical processor x86/hyper-v: make hv_do_hypercall() inline x86/hyper-v: fast hypercall implementation
hyper-v: use fast hypercall for HVCALL_SIGNAL_EVENT x86/hyper-v: implement rep hypercalls
hyper-v: globalize vp_index
x86/hyper-v: use hypercall for remote TLB flush x86/hyper-v: support extended CPU ranges for TLB flush hypercalls tracing/hyper-v: trace hyperv_mmu_flush_tlb_others()
MAINTAINERS | 1 + arch/x86/Kbuild | 2 +- arch/x86/hyperv/Makefile | 2 +- arch/x86/hyperv/hv_init.c | 90 ++++++------ arch/x86/hyperv/mmu.c | 270 ++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/mshyperv.h | 148 +++++++++++++++++++- arch/x86/include/asm/trace/hyperv.h | 40 ++++++ arch/x86/include/uapi/asm/hyperv.h | 17 +++ arch/x86/kernel/cpu/mshyperv.c | 13 +- drivers/hv/channel_mgmt.c | 20 +-- drivers/hv/connection.c | 7 +- drivers/hv/hv.c | 9 -- drivers/hv/hyperv_vmbus.h | 11 -- drivers/hv/vmbus_drv.c | 17 --- drivers/pci/host/pci-hyperv.c | 54 +------- include/linux/hyperv.h | 17 +-- 16 files changed, 541 insertions(+), 177 deletions(-) create mode 100644 arch/x86/hyperv/mmu.c create mode 100644 arch/x86/include/asm/trace/hyperv.h
Signature · 1 line
2.13.0
PATCH v9 1/10 x86/hyper-v: include hyperv/ only when CONFIG_HYPERV is set
Code is arch/x86/hyperv/ is only needed when CONFIG_HYPERV is set, the 'basic' support and detection lives in arch/x86/kernel/cpu/mshyperv.c which is included when CONFIG_HYPERVISOR_GUEST is set.
--- arch/x86/Kbuild | 2 +- arch/x86/include/asm/mshyperv.h | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-)
arch/x86/Kbuild +1 -1
@@ -8,7 +8,7 @@ obj-$(CONFIG_KVM) += kvm/ obj-$(CONFIG_XEN) += xen/ # Hyper-V paravirtualization support -obj-$(CONFIG_HYPERVISOR_GUEST) += hyperv/ +obj-$(subst m,y,$(CONFIG_HYPERV)) += hyperv/ # lguest paravirtualization support obj-$(CONFIG_LGUEST_GUEST) += lguest/
arch/x86/include/asm/mshyperv.h +6 -1
@@ -173,7 +173,12 @@ void hyperv_init(void);void hyperv_report_panic (struct pt_regs *regs);bool hv_is_hypercall_page_setup (void );void hyperv_cleanup (void ); -#endif +#else /* CONFIG_HYPERV */ +static inline void hyperv_init (void ) {} +static inline bool hv_is_hypercall_page_setup (void ) {return false; } +static inline hyperv_cleanup (void) {} +#endif /* CONFIG_HYPERV */ +#ifdef CONFIG_HYPERV_TSCPAGE struct ms_hyperv_tsc_page *hv_get_tsc_page (void );static inline u64 hv_read_tsc_page (const struct ms_hyperv_tsc_page *tsc_pg)
Signature · 1 line
2.13.0
PATCH v9 2/10 x86/hyper-v: stash the max number of virtual/logical processor
In reply to Vitaly KuznetsovMax virtual processor will be needed for 'extended' hypercalls supporting more than 64 vCPUs. While on it, unify on 'Hyper-V' in mshyperv.c as we currently have a mix, report acquired misc features as well.
--- arch/x86/include/asm/mshyperv.h | 2 ++ arch/x86/kernel/cpu/mshyperv.c | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-)
arch/x86/include/asm/mshyperv.h +2 -0
@@ -28,6 +28,8 @@ struct ms_hyperv_info {u32 features;u32 misc_features;u32 hints; +u32 max_vp_index; +u32 max_lp_index; };extern struct ms_hyperv_info ms_hyperv;
arch/x86/kernel/cpu/mshyperv.c +9 -3
@@ -184,9 +184,15 @@ static void __init ms_hyperv_init_platform(void) ms_hyperv.misc_features =cpuid_edx (HYPERV_CPUID_FEATURES ); ms_hyperv.hints =cpuid_eax (HYPERV_CPUID_ENLIGHTMENT_INFO ); -pr_info ("HyperV: features 0x%x, hints 0x%x\n" , +pr_info ("Hyper-V: features 0x%x, hints 0x%x\n" , ms_hyperv.features, ms_hyperv.hints); + ms_hyperv.max_vp_index =cpuid_eax (HVCPUID_IMPLEMENTATION_LIMITS ); + ms_hyperv.max_lp_index =cpuid_ebx (HVCPUID_IMPLEMENTATION_LIMITS ); + +pr_debug ("Hyper-V: max %u virtual processors, %u logical processors\n" , + ms_hyperv.max_vp_index, ms_hyperv.max_lp_index); +/* * Extract host information. */
@@ -219,7 +225,7 @@ static void __init ms_hyperv_init_platform(void)rdmsrl (HV_X64_MSR_APIC_FREQUENCY , hv_lapic_frequency); hv_lapic_frequency =div_u64 (hv_lapic_frequency,HZ ); lapic_timer_frequency = hv_lapic_frequency; -pr_info ("HyperV: LAPIC Timer Frequency: %#x\n" , +pr_info ("Hyper-V: LAPIC Timer Frequency: %#x\n" , lapic_timer_frequency); }
@@ -253,7 +259,7 @@ static void __init ms_hyperv_init_platform(void) }const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = { - .name ="Microsoft HyperV" , + .name ="Microsoft Hyper-V" , .detect = ms_hyperv_platform, .init_platform = ms_hyperv_init_platform, };
Signature · 1 line
2.13.0
PATCH v9 3/10 x86/hyper-v: make hv_do_hypercall() inline
In reply to Vitaly KuznetsovWe have only three call sites for hv_do_hypercall() and we're going to change HVCALL_SIGNAL_EVENT to doing fast hypercall so we can inline this function for optimization.
Hyper-V top level functional specification states that r9-r11 registers and flags may be clobbered by the hypervisor during hypercall and with inlining this is somewhat important, add the clobbers.
--- arch/x86/hyperv/hv_init.c | 54 ++++------------------------------------- arch/x86/include/asm/mshyperv.h | 39 +++++++++++++++++++++++++++++ drivers/hv/connection.c | 2 ++ include/linux/hyperv.h | 1 - 4 files changed, 46 insertions(+), 50 deletions(-)
arch/x86/hyperv/hv_init.c +5 -49
@@ -75,7 +75,8 @@ static struct clocksource hyperv_cs_msr = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -static void *hypercall_pg; +void *hv_hypercall_pg; +EXPORT_SYMBOL_GPL (hv_hypercall_pg);struct clocksource *hyperv_cs;EXPORT_SYMBOL_GPL (hyperv_cs);
@@ -102,15 +103,15 @@ void hyperv_init(void) guest_id =generate_guest_id (0 ,LINUX_VERSION_CODE ,0 );wrmsrl (HV_X64_MSR_GUEST_OS_ID , guest_id); - hypercall_pg =__vmalloc (PAGE_SIZE ,GFP_KERNEL ,PAGE_KERNEL_RX ); -if (hypercall_pg ==NULL ) { + hv_hypercall_pg =__vmalloc (PAGE_SIZE ,GFP_KERNEL ,PAGE_KERNEL_RX ); +if (hv_hypercall_pg ==NULL ) {wrmsrl (HV_X64_MSR_GUEST_OS_ID ,0 );return ; }rdmsrl (HV_X64_MSR_HYPERCALL , hypercall_msr.as_uint64); hypercall_msr.enable =1 ; - hypercall_msr.guest_physical_address =vmalloc_to_pfn (hypercall_pg); + hypercall_msr.guest_physical_address =vmalloc_to_pfn (hv_hypercall_pg);wrmsrl (HV_X64_MSR_HYPERCALL , hypercall_msr.as_uint64);/*
@@ -170,51 +171,6 @@ void hyperv_cleanup(void) }EXPORT_SYMBOL_GPL (hyperv_cleanup); -/* -* hv_do_hypercall- Invoke the specified hypercall -*/ -u64 hv_do_hypercall (u64 control,void *input,void *output) -{ -u64 input_address = (input) ?virt_to_phys (input) :0 ; -u64 output_address = (output) ?virt_to_phys (output) :0 ; -#ifdef CONFIG_X86_64 -u64 hv_status =0 ; - -if (!hypercall_pg) -return (u64 )ULLONG_MAX ; - - __asm__ __volatile__("mov %0, %%r8" : :"r" (output_address) :"r8" ); - __asm__ __volatile__("call *%3" :"=a" (hv_status) : -"c" (control),"d" (input_address), -"m" (hypercall_pg)); - -return hv_status; - -#else - -u32 control_hi = control >>32 ; -u32 control_lo = control &0xFFFFFFFF ; -u32 hv_status_hi =1 ; -u32 hv_status_lo =1 ; -u32 input_address_hi = input_address >>32 ; -u32 input_address_lo = input_address &0xFFFFFFFF ; -u32 output_address_hi = output_address >>32 ; -u32 output_address_lo = output_address &0xFFFFFFFF ; - -if (!hypercall_pg) -return (u64 )ULLONG_MAX ; - - __asm__ __volatile__ ("call *%8" :"=d" (hv_status_hi), -"=a" (hv_status_lo) :"d" (control_hi), -"a" (control_lo),"b" (input_address_hi), -"c" (input_address_lo),"D" (output_address_hi), -"S" (output_address_lo),"m" (hypercall_pg)); - -return hv_status_lo | ((u64 )hv_status_hi <<32 ); -#endif /* !x86_64 */ -} -EXPORT_SYMBOL_GPL (hv_do_hypercall); -void hyperv_report_panic (struct pt_regs *regs) {static bool panic_reported;
arch/x86/include/asm/mshyperv.h +39 -0
@@ -170,6 +170,45 @@ void hv_remove_crash_handler(void);#if IS_ENABLED (CONFIG_HYPERV )extern struct clocksource *hyperv_cs; +extern void *hv_hypercall_pg; + +static inline u64 hv_do_hypercall (u64 control,void *input,void *output) +{ +u64 input_address = input ?virt_to_phys (input) :0 ; +u64 output_address = output ?virt_to_phys (output) :0 ; +u64 hv_status; + register void *__sp asm(_ASM_SP); + +#ifdef CONFIG_X86_64 +if (!hv_hypercall_pg) +return U64_MAX ; + + __asm__ __volatile__("mov %4, %%r8\n" +"call *%5" + :"=a" (hv_status),"+r" (__sp), +"+c" (control),"+d" (input_address) + :"r" (output_address),"m" (hv_hypercall_pg) + :"cc" ,"memory" ,"r8" ,"r9" ,"r10" ,"r11" ); +#else +u32 input_address_hi =upper_32_bits (input_address); +u32 input_address_lo =lower_32_bits (input_address); +u32 output_address_hi =upper_32_bits (output_address); +u32 output_address_lo =lower_32_bits (output_address); + +if (!hv_hypercall_pg) +return U64_MAX ; + + __asm__ __volatile__("call *%7" + :"=A" (hv_status), +"+c" (input_address_lo),"+r" (__sp) + :"A" (control), +"b" (input_address_hi), +"D" (output_address_hi),"S" (output_address_lo), +"m" (hv_hypercall_pg) + :"cc" ,"memory" ); +#endif /* !x86_64 */ +return hv_status; +}void hyperv_init (void );void hyperv_report_panic (struct pt_regs *regs);
drivers/hv/connection.c +2 -0
@@ -32,6 +32,8 @@#include <linux/hyperv.h> #include <linux/export.h> #include <asm/hyperv.h> +#include <asm/mshyperv.h> +#include "hyperv_vmbus.h"
include/linux/hyperv.h +0 -1
@@ -1187,7 +1187,6 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj, bool fb_overlap_ok);void vmbus_free_mmio (resource_size_t start,resource_size_t size);int vmbus_cpu_number_to_vp_number (int cpu_number); -u64 hv_do_hypercall (u64 control,void *input,void *output);/* * GUID definitions of various offer types - services offered to the guest.
Signature · 1 line
2.13.0
kbuild test robot
build botRe: [PATCH v9 03/10] x86/hyper-v: make hv_do_hypercall() inline
url: https://github.com/0day-ci/linux/commits/Vitaly-Kuznetsov/Hyper-V-paravirtualized-remote-TLB-flushing-and-hypercall-improvements/20170715-023027 config: x86_64-rhel (attached as .config)…
Hi Vitaly,
[auto build test ERROR on linus/master]
[also build test ERROR on v4.13-rc1 next-20170717]
[cannot apply to tip/x86/core]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Vitaly-Kuznetsov/Hyper-V-paravirtualized-remote-TLB-flushing-and-hypercall-improvements/20170715-023027
config: x86_64-rhel (attached as .config)
compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901 reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64 Note: the linux-review/Vitaly-Kuznetsov/Hyper-V-paravirtualized-remote-TLB-flushing-and-hypercall-improvements/20170715-023027 HEAD ac9354b5afdbfbc99257e73a7b3af517ea8ebb91 builds fine.
It only hurts bisectibility.
All errors (new ones prefixed by >>):
In file included from arch/x86/hyperv/hv_init.c:23:0:
arch/x86/include/asm/mshyperv.h: In function 'hv_do_hypercall':
>> arch/x86/include/asm/mshyperv.h:177:30: error: implicit declaration of function 'virt_to_phys' [-Werror=implicit-function-declaration]
u64 input_address = input ? virt_to_phys(input) : 0;
^~~~~~~~~~~~
In file included from arch/x86/include/asm/realmode.h:5:0,
from arch/x86/include/asm/acpi.h:33,
from arch/x86/include/asm/fixmap.h:19,
from arch/x86/include/asm/apic.h:10,
from arch/x86/include/asm/smp.h:12,
from arch/x86/include/asm/mmzone_64.h:10,
from arch/x86/include/asm/mmzone.h:4,
from include/linux/mmzone.h:912,
from include/linux/gfp.h:5,
from include/linux/mm.h:9,
from arch/x86/hyperv/hv_init.c:26:
arch/x86/include/asm/io.h: At top level:
>> arch/x86/include/asm/io.h:118:27: error: conflicting types for 'virt_to_phys'
static inline phys_addr_t virt_to_phys(volatile void *address)
^~~~~~~~~~~~
In file included from arch/x86/hyperv/hv_init.c:23:0:
arch/x86/include/asm/mshyperv.h:177:30: note: previous implicit declaration of 'virt_to_phys' was here
u64 input_address = input ? virt_to_phys(input) : 0;
^~~~~~~~~~~~cc1: some warnings being treated as errors
vim +/virt_to_phys +177 arch/x86/include/asm/mshyperv.h
174
175 static inline u64 hv_do_hypercall(u64 control, void *input, void *output)
176 {
> 177 u64 input_address = input ? virt_to_phys(input) : 0;
178 u64 output_address = output ? virt_to_phys(output) : 0;
179 u64 hv_status;
180 register void *__sp asm(_ASM_SP);
181
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
PATCH v9 4/10 x86/hyper-v: fast hypercall implementation
In reply to Vitaly KuznetsovHyper-V supports 'fast' hypercalls when all parameters are passed through registers. Implement an inline version of a simpliest of these calls:
hypercall with one 8-byte input and no output.
--- arch/x86/include/asm/mshyperv.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+)
arch/x86/include/asm/mshyperv.h +34 -0
@@ -210,6 +210,40 @@ static inline u64 hv_do_hypercall(u64 control, void *input, void *output)return hv_status; } +#define HV_HYPERCALL_FAST_BIT BIT(16) + +/* Fast hypercall with 8 bytes of input and no output */ +static inline u64 hv_do_fast_hypercall8 (u16 code,u64 input1) +{ +u64 hv_status, control = (u64 )code |HV_HYPERCALL_FAST_BIT ; + register void *__sp asm(_ASM_SP); + +#ifdef CONFIG_X86_64 + { + __asm__ __volatile__("call *%4" + :"=a" (hv_status),"+r" (__sp), +"+c" (control),"+d" (input1) + :"m" (hv_hypercall_pg) + :"cc" ,"r8" ,"r9" ,"r10" ,"r11" ); + } +#else + { +u32 input1_hi =upper_32_bits (input1); +u32 input1_lo =lower_32_bits (input1); + + __asm__ __volatile__ ("call *%5" + :"=A" (hv_status), +"+c" (input1_lo), +"+r" (__sp) + :"A" (control), +"b" (input1_hi), +"m" (hv_hypercall_pg) + :"cc" ,"edi" ,"esi" ); + } +#endif +return hv_status; +} +void hyperv_init (void );void hyperv_report_panic (struct pt_regs *regs);bool hv_is_hypercall_page_setup (void );
Signature · 1 line
2.13.0
PATCH v9 5/10 hyper-v: use fast hypercall for HVCALL_SIGNAL_EVENT
In reply to Vitaly KuznetsovWe need to pass only 8 bytes of input for HvSignalEvent which makes it a perfect fit for fast hypercall. hv_input_signal_event_buffer is not needed any more and hv_input_signal_event is converted to union for convenience.
--- drivers/hv/channel_mgmt.c | 13 ++----------- drivers/hv/connection.c | 2 +- include/linux/hyperv.h | 15 +-------------- 3 files changed, 4 insertions(+), 26 deletions(-)
drivers/hv/channel_mgmt.c +2 -11
@@ -805,21 +805,12 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)/* * Setup state for signalling the host. */ - newchannel->sig_event = (struct hv_input_signal_event *) - (ALIGN ((unsigned long ) - &newchannel->sig_buf, -HV_HYPERCALL_PARAM_ALIGN )); - - newchannel->sig_event->connectionid.asu32 =0 ; - newchannel->sig_event->connectionid.u.id =VMBUS_EVENT_CONNECTION_ID ; - newchannel->sig_event->flag_number =0 ; - newchannel->sig_event->rsvdz =0 ; + newchannel->sig_event =VMBUS_EVENT_CONNECTION_ID ;if (vmbus_proto_version !=VERSION_WS2008 ) { newchannel->is_dedicated_interrupt = (offer->is_dedicated_interrupt !=0 ); - newchannel->sig_event->connectionid.u.id = - offer->connection_id; + newchannel->sig_event = offer->connection_id; } memcpy(&newchannel->offermsg, offer,
drivers/hv/connection.c +1 -1
@@ -408,6 +408,6 @@ void vmbus_set_event(struct vmbus_channel *channel)if (!channel->is_dedicated_interrupt)vmbus_send_interrupt (child_relid); -hv_do_hypercall (HVCALL_SIGNAL_EVENT , channel->sig_event,NULL ); +hv_do_fast_hypercall8 (HVCALL_SIGNAL_EVENT , channel->sig_event); }EXPORT_SYMBOL_GPL (vmbus_set_event);
include/linux/hyperv.h +1 -14
@@ -677,18 +677,6 @@ union hv_connection_id { } u; }; -/* Definition of the hv_signal_event hypercall input structure. */ -struct hv_input_signal_event { -union hv_connection_id connectionid; -u16 flag_number; -u16 rsvdz; -}; - -struct hv_input_signal_event_buffer { -u64 align8; -struct hv_input_signal_event event; -}; -enum hv_numa_policy {HV_BALANCED =0 ,HV_LOCALIZED ,
@@ -770,8 +758,7 @@ struct vmbus_channel { } callback_mode;bool is_dedicated_interrupt; -struct hv_input_signal_event_buffer sig_buf; -struct hv_input_signal_event *sig_event; +u64 sig_event;/* * Starting with win8, this field will be used to specify
Signature · 1 line
2.13.0
PATCH v9 6/10 x86/hyper-v: implement rep hypercalls
In reply to Vitaly KuznetsovRep hypercalls are normal hypercalls which perform multiple actions at once. Hyper-V guarantees to return exectution to the caller in not more than 50us and the caller needs to use hypercall continuation. Touch NMI watchdog between hypercall invocations.
This is going to be used for HvFlushVirtualAddressList hypercall for remote TLB flushing.
--- arch/x86/include/asm/mshyperv.h | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+)
arch/x86/include/asm/mshyperv.h +39 -0
@@ -3,6 +3,7 @@#include <linux/types.h> #include <linux/atomic.h> +#include <linux/nmi.h> #include <asm/hyperv.h> /*
@@ -210,7 +211,13 @@ static inline u64 hv_do_hypercall(u64 control, void *input, void *output)return hv_status; } +#define HV_HYPERCALL_RESULT_MASK GENMASK_ULL(15, 0)#define HV_HYPERCALL_FAST_BIT BIT(16) +#define HV_HYPERCALL_VARHEAD_OFFSET 17 +#define HV_HYPERCALL_REP_COMP_OFFSET 32 +#define HV_HYPERCALL_REP_COMP_MASK GENMASK_ULL(43, 32) +#define HV_HYPERCALL_REP_START_OFFSET 48 +#define HV_HYPERCALL_REP_START_MASK GENMASK_ULL(59, 48)/* Fast hypercall with 8 bytes of input and no output */ static inline u64 hv_do_fast_hypercall8 (u16 code,u64 input1)
@@ -244,6 +251,38 @@ static inline u64 hv_do_fast_hypercall8(u16 code, u64 input1)return hv_status; } +/* +* Rep hypercalls. Callers of this functions are supposed to ensure that +* rep_count and varhead_size comply with Hyper-V hypercall definition. +*/ +static inline u64 hv_do_rep_hypercall (u16 code,u16 rep_count,u16 varhead_size, +void *input,void *output) +{ +u64 control = code; +u64 status; +u16 rep_comp; + + control |= (u64 )varhead_size <<HV_HYPERCALL_VARHEAD_OFFSET ; + control |= (u64 )rep_count <<HV_HYPERCALL_REP_COMP_OFFSET ; + +do { + status =hv_do_hypercall (control, input, output); +if ((status &HV_HYPERCALL_RESULT_MASK ) !=HV_STATUS_SUCCESS ) +return status; + +/* Bits 32-43 of status have 'Reps completed' data. */ + rep_comp = (status &HV_HYPERCALL_REP_COMP_MASK ) >> +HV_HYPERCALL_REP_COMP_OFFSET ; + + control &= ~HV_HYPERCALL_REP_START_MASK ; + control |= (u64 )rep_comp <<HV_HYPERCALL_REP_START_OFFSET ; + +touch_nmi_watchdog (); + }while (rep_comp < rep_count); + +return status; +} +void hyperv_init (void );void hyperv_report_panic (struct pt_regs *regs);bool hv_is_hypercall_page_setup (void );
Signature · 1 line
2.13.0
PATCH v9 7/10 hyper-v: globalize vp_index
In reply to Vitaly KuznetsovTo support implementing remote TLB flushing on Hyper-V with a hypercall we need to make vp_index available outside of vmbus module. Rename and globalize.
--- arch/x86/hyperv/hv_init.c | 34 +++++++++++++++++++++++++- arch/x86/include/asm/mshyperv.h | 24 ++++++++++++++++++ drivers/hv/channel_mgmt.c | 7 +++--- drivers/hv/connection.c | 3 ++- drivers/hv/hv.c | 9 ------- drivers/hv/hyperv_vmbus.h | 11 --------- drivers/hv/vmbus_drv.c | 17 ------------- drivers/pci/host/pci-hyperv.c | 54 +++-------------------------------------- include/linux/hyperv.h | 1 - 9 files changed, 65 insertions(+), 95 deletions(-)
arch/x86/hyperv/hv_init.c +33 -1
@@ -26,6 +26,8 @@#include <linux/mm.h> #include <linux/clockchips.h> #include <linux/hyperv.h> +#include <linux/slab.h> +#include <linux/cpuhotplug.h> #ifdef CONFIG_HYPERV_TSCPAGE
@@ -80,6 +82,20 @@ EXPORT_SYMBOL_GPL(hv_hypercall_pg);struct clocksource *hyperv_cs;EXPORT_SYMBOL_GPL (hyperv_cs); +u32 *hv_vp_index; +EXPORT_SYMBOL_GPL (hv_vp_index); + +static int hv_cpu_init (unsigned int cpu) +{ +u64 msr_vp_index; + +hv_get_vp_index (msr_vp_index); + + hv_vp_index[smp_processor_id ()] = msr_vp_index; + +return 0 ; +} +/* * This function is to be invoked early in the boot sequence after the * hypervisor has been detected.
@@ -95,6 +111,16 @@ void hyperv_init(void)if (x86_hyper != &x86_hyper_ms_hyperv)return ; +/* Allocate percpu VP index */ + hv_vp_index =kmalloc_array (num_possible_cpus (),sizeof (*hv_vp_index), +GFP_KERNEL ); +if (!hv_vp_index) +return ; + +if (cpuhp_setup_state (CPUHP_AP_ONLINE_DYN ,"x86/hyperv_init:online" , + hv_cpu_init,NULL ) <0 ) + goto free_vp_index; +/* * Setup the hypercall page and enable hypercalls. * 1. Register the guest ID
@@ -106,7 +132,7 @@ void hyperv_init(void) hv_hypercall_pg =__vmalloc (PAGE_SIZE ,GFP_KERNEL ,PAGE_KERNEL_RX );if (hv_hypercall_pg ==NULL ) {wrmsrl (HV_X64_MSR_GUEST_OS_ID ,0 ); -return ; + goto free_vp_index; }rdmsrl (HV_X64_MSR_HYPERCALL , hypercall_msr.as_uint64);
@@ -149,6 +175,12 @@ void hyperv_init(void) hyperv_cs = &hyperv_cs_msr;if (ms_hyperv.features &HV_X64_MSR_TIME_REF_COUNT_AVAILABLE )clocksource_register_hz (&hyperv_cs_msr,NSEC_PER_SEC /100 ); + +return ; + +free_vp_index: +kfree (hv_vp_index); + hv_vp_index =NULL ; }/*
arch/x86/include/asm/mshyperv.h +24 -0
@@ -283,6 +283,30 @@ static inline u64 hv_do_rep_hypercall(u16 code, u16 rep_count, u16 varhead_size,return status; } +/* +* Hypervisor's notion of virtual processor ID is different from +* Linux' notion of CPU ID. This information can only be retrieved +* in the context of the calling CPU. Setup a map for easy access +* to this information. +*/ +extern u32 *hv_vp_index; + +/** +* hv_cpu_number_to_vp_number() - Map CPU to VP. +* @cpu_number: CPU number in Linux terms +* +* This function returns the mapping between the Linux processor +* number and the hypervisor's virtual processor number, useful +* in making hypercalls and such that talk about specific +* processors. +* +* Return: Virtual processor number in Hyper-V terms +*/ +static inline int hv_cpu_number_to_vp_number (int cpu_number) +{ +return hv_vp_index[cpu_number]; +} +void hyperv_init (void );void hyperv_report_panic (struct pt_regs *regs);bool hv_is_hypercall_page_setup (void );
drivers/hv/channel_mgmt.c +3 -4
@@ -599,7 +599,7 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type)*/ channel->numa_node =0 ; channel->target_cpu =0 ; - channel->target_vp = hv_context.vp_index[0 ]; + channel->target_vp =hv_cpu_number_to_vp_number (0 );return ; }
@@ -683,7 +683,7 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type) } channel->target_cpu = cur_cpu; - channel->target_vp = hv_context.vp_index[cur_cpu]; + channel->target_vp =hv_cpu_number_to_vp_number (cur_cpu); }static void vmbus_wait_for_unload (void )
@@ -1219,8 +1219,7 @@ struct vmbus_channel *vmbus_get_outgoing_channel(struct vmbus_channel *primary)return outgoing_channel; } - cur_cpu = hv_context.vp_index[get_cpu ()]; -put_cpu (); + cur_cpu =hv_cpu_number_to_vp_number (smp_processor_id ());list_for_each_safe (cur, tmp, &primary->sc_list) { cur_channel = list_entry(cur, struct vmbus_channel, sc_list);if (cur_channel->state !=CHANNEL_OPENED_STATE )
drivers/hv/connection.c +2 -1
@@ -96,7 +96,8 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo,* the CPU attempting to connect may not be CPU 0. */ if (version >=VERSION_WIN8_1 ) { - msg->target_vcpu = hv_context.vp_index[smp_processor_id ()]; + msg->target_vcpu = +hv_cpu_number_to_vp_number (smp_processor_id ()); vmbus_connection.connect_cpu =smp_processor_id (); }else { msg->target_vcpu =0 ;
drivers/hv/hv.c +0 -9
@@ -234,7 +234,6 @@ int hv_synic_init(unsigned int cpu)union hv_synic_siefp siefp;union hv_synic_sint shared_sint;union hv_synic_scontrol sctrl; -u64 vp_index;/* Setup the Synic's message page */ hv_get_simp (simp.as_uint64);
@@ -276,14 +275,6 @@ int hv_synic_init(unsigned int cpu) hv_context.synic_initialized = true;/* -* Setup the mapping between Hyper-V's notion -* of cpuid and Linux' notion of cpuid. -* This array will be indexed using Linux cpuid. -*/ -hv_get_vp_index (vp_index); - hv_context.vp_index[cpu] = (u32 )vp_index; - -/* * Register the per-cpu clockevent source. */ if (ms_hyperv.features &HV_X64_MSR_SYNTIMER_AVAILABLE )
drivers/hv/hyperv_vmbus.h +0 -11
@@ -229,17 +229,6 @@ struct hv_context {struct hv_per_cpu_context __percpu *cpu_context;/* -* Hypervisor's notion of virtual processor ID is different from -* Linux' notion of CPU ID. This information can only be retrieved -* in the context of the calling CPU. Setup a map for easy access -* to this information: -* -* vp_index[a] is the Hyper-V's processor ID corresponding to -* Linux cpuid 'a'. -*/ -u32 vp_index[NR_CPUS ]; - -/* * To manage allocations in a NUMA node. * Array indexed by numa node ID. */
drivers/hv/vmbus_drv.c +0 -17
@@ -1451,23 +1451,6 @@ void vmbus_free_mmio(resource_size_t start, resource_size_t size) }EXPORT_SYMBOL_GPL (vmbus_free_mmio); -/** -* vmbus_cpu_number_to_vp_number() - Map CPU to VP. -* @cpu_number: CPU number in Linux terms -* -* This function returns the mapping between the Linux processor -* number and the hypervisor's virtual processor number, useful -* in making hypercalls and such that talk about specific -* processors. -* -* Return: Virtual processor number in Hyper-V terms -*/ -int vmbus_cpu_number_to_vp_number (int cpu_number) -{ -return hv_context.vp_index[cpu_number]; -} -EXPORT_SYMBOL_GPL (vmbus_cpu_number_to_vp_number); -static int vmbus_acpi_add (struct acpi_device *device) {acpi_status result;
drivers/pci/host/pci-hyperv.c +3 -51
84 lines not on this page · raw message
include/linux/hyperv.h +0 -1
@@ -1173,7 +1173,6 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj, resource_size_t size, resource_size_t align, bool fb_overlap_ok);void vmbus_free_mmio (resource_size_t start,resource_size_t size); -int vmbus_cpu_number_to_vp_number (int cpu_number);/* * GUID definitions of various offer types - services offered to the guest.
Signature · 1 line
2.13.0
PATCH v9 8/10 x86/hyper-v: use hypercall for remote TLB flush
In reply to Vitaly KuznetsovHyper-V host can suggest us to use hypercall for doing remote TLB flush, this is supposed to work faster than IPIs.
Implementation details: to do HvFlushVirtualAddress{Space,List} hypercalls we need to put the input somewhere in memory and we don't really want to have memory allocation on each call so we pre-allocate per cpu memory areas on boot.
pv_ops patching is happening very early so we need to separate hyperv_setup_mmu_ops() and hyper_alloc_mmu().
It is possible and easy to implement local TLB flushing too and there is even a hint for that. However, I don't see a room for optimization on the host side as both hypercall and native tlb flush will result in vmexit. The hint is also not set on modern Hyper-V versions.
--- arch/x86/hyperv/Makefile | 2 +- arch/x86/hyperv/hv_init.c | 2 + arch/x86/hyperv/mmu.c | 135 +++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/mshyperv.h | 3 + arch/x86/include/uapi/asm/hyperv.h | 7 ++ arch/x86/kernel/cpu/mshyperv.c | 1 + 6 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 arch/x86/hyperv/mmu.c
arch/x86/hyperv/Makefile +1 -1
@@ -1 +1 @@ -obj-y := hv_init.o +obj-y := hv_init.o mmu.o
arch/x86/hyperv/hv_init.c +2 -0
@@ -140,6 +140,8 @@ void hyperv_init(void) hypercall_msr.guest_physical_address =vmalloc_to_pfn (hv_hypercall_pg);wrmsrl (HV_X64_MSR_HYPERCALL , hypercall_msr.as_uint64); +hyper_alloc_mmu (); +/* * Register Hyper-V specific clocksource. */
arch/x86/hyperv/mmu.c new file +135 -0
135 lines not on this page · raw message
arch/x86/include/asm/mshyperv.h +3 -0
@@ -308,6 +308,8 @@ static inline int hv_cpu_number_to_vp_number(int cpu_number) }void hyperv_init (void ); +void hyperv_setup_mmu_ops (void ); +void hyper_alloc_mmu (void );void hyperv_report_panic (struct pt_regs *regs);bool hv_is_hypercall_page_setup (void );void hyperv_cleanup (void );
@@ -315,6 +317,7 @@ void hyperv_cleanup(void);static inline void hyperv_init (void ) {}static inline bool hv_is_hypercall_page_setup (void ) {return false; }static inline hyperv_cleanup (void) {} +static inline void hyperv_setup_mmu_ops (void ) {}#endif /* CONFIG_HYPERV */ #ifdef CONFIG_HYPERV_TSCPAGE
arch/x86/include/uapi/asm/hyperv.h +7 -0
@@ -242,6 +242,8 @@ (~((1ull <<HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT ) -1 )) /* Declare the various hypercall operations. */ +#define HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE 0x0002 +#define HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST 0x0003#define HVCALL_NOTIFY_LONG_SPIN_WAIT 0x0008#define HVCALL_POST_MESSAGE 0x005c#define HVCALL_SIGNAL_EVENT 0x005d
@@ -259,6 +261,11 @@#define HV_PROCESSOR_POWER_STATE_C2 2#define HV_PROCESSOR_POWER_STATE_C3 3 +#define HV_FLUSH_ALL_PROCESSORS BIT(0) +#define HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES BIT(1) +#define HV_FLUSH_NON_GLOBAL_MAPPINGS_ONLY BIT(2) +#define HV_FLUSH_USE_EXTENDED_RANGE_FORMAT BIT(3) +/* hypercall status code */ #define HV_STATUS_SUCCESS 0#define HV_STATUS_INVALID_HYPERCALL_CODE 2
arch/x86/kernel/cpu/mshyperv.c +1 -0
@@ -255,6 +255,7 @@ static void __init ms_hyperv_init_platform(void)* Setup the hook to get control post apic initialization. */ x86_platform.apic_post_init = hyperv_init; +hyperv_setup_mmu_ops ();#endif }
Signature · 1 line
2.13.0
Re: [PATCH v9 08/10] x86/hyper-v: use hypercall for remote TLB flush
On Fri, Jul 14, 2017 at 3:44 PM, Vitaly Kuznetsov <[email protected]> wrote:
Couple of nits in case you are going send new version (I'm fine with this as well).
arch/x86/hyperv/mmu.c line 52
Quoted 5 lines
arch/x86/hyperv/mmu.c new file +4
-0+static inline int fill_gva_list (u64 gva_list[],int offset, +unsigned long start,unsigned long end) +{ +}
+ empty line.
Quoted 6 lines
arch/x86/hyperv/mmu.c new file +5
-0+static void hyperv_flush_tlb_others (const struct cpumask *cpus, +const struct flush_tlb_info *info) +{ + flush->processor_mask =0 ; +if (cpumask_equal (cpus, cpu_present_mask)) {
arch/x86/hyperv/mmu.c line 89
Quoted 10 lines
arch/x86/hyperv/mmu.c new file +9
-0+ flush->flags |=HV_FLUSH_ALL_PROCESSORS ; + }else { +for_each_cpu (cpu, cpus) { + vcpu =hv_cpu_number_to_vp_number (cpu); +if (vcpu <64 ) +__set_bit (vcpu, (unsigned long *) + &flush->processor_mask); +else + goto do_native;
Forgot to mention that else can be removed
if (vcpu >= 64)
goto do_native;
__set_bit(vcpu, (unsigned long *)&flush->processor_mask);arch/x86/hyperv/mmu.c line 125
Quoted 10 lines
arch/x86/hyperv/mmu.c new file +8
-0+ } + } +} + +void hyperv_setup_mmu_ops (void ) +{ +if (ms_hyperv.hints &HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED ) { +pr_info ("Hyper-V: Using hypercall for remote TLB flush\n" );
You may define pr_fmt() at the beginning of this file.
Like
#define pr_fmt(fmt) "Hyper-V: " ## fmt
Quoted 4 lines
arch/x86/hyperv/mmu.c new file +4
-0+ pv_mmu_ops.flush_tlb_others = hyperv_flush_tlb_others; +setup_clear_cpu_cap (X86_FEATURE_PCID ); + } +}
Signature · 2 lines
With Best Regards, Andy Shevchenko
PATCH v9 9/10 x86/hyper-v: support extended CPU ranges for TLB flush hypercalls
In reply to Vitaly KuznetsovHyper-V hosts may support more than 64 vCPUs, we need to use HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX/LIST_EX hypercalls in this case.
--- arch/x86/hyperv/mmu.c | 134 ++++++++++++++++++++++++++++++++++++- arch/x86/include/uapi/asm/hyperv.h | 10 +++ 2 files changed, 141 insertions(+), 3 deletions(-)
arch/x86/hyperv/mmu.c +131 -3
@@ -16,11 +16,25 @@ struct hv_flush_pcpu {u64 gva_list[]; }; +/* HvFlushVirtualAddressSpaceEx, HvFlushVirtualAddressListEx hypercalls */ +struct hv_flush_pcpu_ex { +u64 address_space; +u64 flags; +struct { +u64 format; +u64 valid_bank_mask; +u64 bank_contents[]; + } hv_vp_set; +u64 gva_list[]; +}; +/* Each gva in gva_list encodes up to 4096 pages to flush */ #define HV_TLB_FLUSH_UNIT (4096 * PAGE_SIZE)static struct hv_flush_pcpu __percpu *pcpu_flush; +static struct hv_flush_pcpu_ex __percpu *pcpu_flush_ex; +/* * Fills in gva_list starting from offset. Returns the number of items added. */
@@ -50,6 +64,35 @@ static inline int fill_gva_list(u64 gva_list[], int offset,return gva_n - offset; } + +/* Return the number of banks in the resulting vp_set */ +static inline int cpumask_to_vp_set (struct hv_flush_pcpu_ex *flush, +const struct cpumask *cpus) +{ +int cpu, vcpu, vcpu_bank, vcpu_offset, nr_bank =1 ; + +/* +* Some banks may end up being empty but this is acceptable. +*/ +for_each_cpu (cpu, cpus) { + vcpu =hv_cpu_number_to_vp_number (cpu); + vcpu_bank = vcpu /64 ; + vcpu_offset = vcpu %64 ; + +/* valid_bank_mask can represent up to 64 banks */ +if (vcpu_bank >=64 ) +return 0 ; + +__set_bit (vcpu_offset, (unsigned long *) + &flush->hv_vp_set.bank_contents[vcpu_bank]); +if (vcpu_bank >= nr_bank) + nr_bank = vcpu_bank +1 ; + } + flush->hv_vp_set.valid_bank_mask =GENMASK_ULL (nr_bank -1 ,0 ); + +return nr_bank; +} +static void hyperv_flush_tlb_others (const struct cpumask *cpus,const struct flush_tlb_info *info) {
@@ -119,17 +162,102 @@ static void hyperv_flush_tlb_others(const struct cpumask *cpus,native_flush_tlb_others (cpus, info); } +static void hyperv_flush_tlb_others_ex (const struct cpumask *cpus, +const struct flush_tlb_info *info) +{ +int nr_bank =0 , max_gvas, gva_n; +struct hv_flush_pcpu_ex *flush; +u64 status =U64_MAX ; +unsigned long flags; + +if (!pcpu_flush_ex || !hv_hypercall_pg) + goto do_native; + +if (cpumask_empty (cpus)) +return ; + +local_irq_save (flags); + + flush =this_cpu_ptr (pcpu_flush_ex); + +if (info->mm) { + flush->address_space =virt_to_phys (info->mm->pgd); + flush->flags =0 ; + }else { + flush->address_space =0 ; + flush->flags =HV_FLUSH_ALL_VIRTUAL_ADDRESS_SPACES ; + } + + flush->hv_vp_set.valid_bank_mask =0 ; + +if (!cpumask_equal (cpus, cpu_present_mask)) { + flush->hv_vp_set.format =HV_GENERIC_SET_SPARCE_4K ; + nr_bank =cpumask_to_vp_set (flush, cpus); + } + +if (!nr_bank) { + flush->hv_vp_set.format =HV_GENERIC_SET_ALL ; + flush->flags |=HV_FLUSH_ALL_PROCESSORS ; + } + +/* +* We can flush not more than max_gvas with one hypercall. Flush the +* whole address space if we were asked to do more. +*/ + max_gvas = + (PAGE_SIZE -sizeof (*flush) - nr_bank * +sizeof (flush->hv_vp_set.bank_contents[0 ])) / +sizeof (flush->gva_list[0 ]); + +if (info->end ==TLB_FLUSH_ALL ) { + flush->flags |=HV_FLUSH_NON_GLOBAL_MAPPINGS_ONLY ; + status =hv_do_rep_hypercall ( +HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX , +0 , nr_bank +2 , flush,NULL ); + }else if (info->end && + ((info->end - info->start)/HV_TLB_FLUSH_UNIT ) > max_gvas) { + status =hv_do_rep_hypercall ( +HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX , +0 , nr_bank +2 , flush,NULL ); + }else { + gva_n =fill_gva_list (flush->gva_list, nr_bank, + info->start, info->end); + status =hv_do_rep_hypercall ( +HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX , + gva_n, nr_bank +2 , flush,NULL ); + } + +local_irq_restore (flags); + +if (!(status &HV_HYPERCALL_RESULT_MASK )) +return ; +do_native: +native_flush_tlb_others (cpus, info); +} +void hyperv_setup_mmu_ops (void ) { -if (ms_hyperv.hints &HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED ) { +if (!(ms_hyperv.hints &HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED )) +return ; + +setup_clear_cpu_cap (X86_FEATURE_PCID ); + +if (!(ms_hyperv.hints &HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED )) {pr_info ("Hyper-V: Using hypercall for remote TLB flush\n" ); pv_mmu_ops.flush_tlb_others = hyperv_flush_tlb_others; -setup_clear_cpu_cap (X86_FEATURE_PCID ); + }else { +pr_info ("Hyper-V: Using ext hypercall for remote TLB flush\n" ); + pv_mmu_ops.flush_tlb_others = hyperv_flush_tlb_others_ex; } }void hyper_alloc_mmu (void ) { -if (ms_hyperv.hints &HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED ) +if (!(ms_hyperv.hints &HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED )) +return ; + +if (!(ms_hyperv.hints &HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED )) pcpu_flush =__alloc_percpu (PAGE_SIZE ,PAGE_SIZE ); +else + pcpu_flush_ex =__alloc_percpu (PAGE_SIZE ,PAGE_SIZE ); }
arch/x86/include/uapi/asm/hyperv.h +10 -0
@@ -149,6 +149,9 @@*/ #define HV_X64_DEPRECATING_AEOI_RECOMMENDED (1 << 9) +/* Recommend using the newer ExProcessorMasks interface */ +#define HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED (1 << 11) +/* * HV_VP_SET available */
@@ -245,6 +248,8 @@#define HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE 0x0002#define HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST 0x0003#define HVCALL_NOTIFY_LONG_SPIN_WAIT 0x0008 +#define HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX 0x0013 +#define HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX 0x0014#define HVCALL_POST_MESSAGE 0x005c#define HVCALL_SIGNAL_EVENT 0x005d
@@ -266,6 +271,11 @@#define HV_FLUSH_NON_GLOBAL_MAPPINGS_ONLY BIT(2)#define HV_FLUSH_USE_EXTENDED_RANGE_FORMAT BIT(3) +enum HV_GENERIC_SET_FORMAT { +HV_GENERIC_SET_SPARCE_4K , +HV_GENERIC_SET_ALL , +}; +/* hypercall status code */ #define HV_STATUS_SUCCESS 0#define HV_STATUS_INVALID_HYPERCALL_CODE 2
Signature · 1 line
2.13.0
PATCH v9 10/10 tracing/hyper-v: trace hyperv_mmu_flush_tlb_others()
In reply to Vitaly KuznetsovAdd Hyper-V tracing subsystem and trace hyperv_mmu_flush_tlb_others(). Tracing is done the same way we do xen_mmu_flush_tlb_others().
--- MAINTAINERS | 1 + arch/x86/hyperv/mmu.c | 7 +++++++ arch/x86/include/asm/trace/hyperv.h | 40 +++++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 arch/x86/include/asm/trace/hyperv.h
MAINTAINERS +1 -0
@@ -6276,6 +6276,7 @@ M: Stephen Hemminger <[email protected]> L: [email protected] S: Maintained F: arch/x86/include/asm/mshyperv.h +F: arch/x86/include/asm/trace/hyperv.h F: arch/x86/include/uapi/asm/hyperv.h F: arch/x86/kernel/cpu/mshyperv.c F: arch/x86/hyperv
arch/x86/hyperv/mmu.c +7 -0
@@ -8,6 +8,9 @@#include <asm/msr.h> #include <asm/tlbflush.h> +#define CREATE_TRACE_POINTS +#include <asm/trace/hyperv.h> +/* HvFlushVirtualAddressSpace, HvFlushVirtualAddressList hypercalls */ struct hv_flush_pcpu {u64 address_space;
@@ -101,6 +104,8 @@ static void hyperv_flush_tlb_others(const struct cpumask *cpus,u64 status =U64_MAX ;unsigned long flags; +trace_hyperv_mmu_flush_tlb_others (cpus, info); +if (!pcpu_flush || !hv_hypercall_pg) goto do_native;
@@ -170,6 +175,8 @@ static void hyperv_flush_tlb_others_ex(const struct cpumask *cpus,u64 status =U64_MAX ;unsigned long flags; +trace_hyperv_mmu_flush_tlb_others (cpus, info); +if (!pcpu_flush_ex || !hv_hypercall_pg) goto do_native;
arch/x86/include/asm/trace/hyperv.h new file +40 -0
@@ -0,0 +1,40 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM hyperv + +#if !defined(_TRACE_HYPERV_H) || defined(TRACE_HEADER_MULTI_READ ) +#define _TRACE_HYPERV_H + +#include <linux/tracepoint.h> + +#if IS_ENABLED (CONFIG_HYPERV ) + +TRACE_EVENT (hyperv_mmu_flush_tlb_others, + TP_PROTO(const struct cpumask *cpus, + const struct flush_tlb_info *info), +TP_ARGS (cpus, info), +TP_STRUCT__entry ( + __field(unsigned int, ncpus) + __field(struct mm_struct *, mm) + __field(unsigned long, addr) + __field(unsigned long, end) + ), + TP_fast_assign(__entry->ncpus = cpumask_weight(cpus); + __entry->mm = info->mm; + __entry->addr = info->start; + __entry->end = info->end; + ), +TP_printk ("ncpus %d mm %p addr %lx, end %lx" , + __entry->ncpus, __entry->mm, + __entry->addr, __entry->end) + ); + +#endif /* CONFIG_HYPERV */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH asm/trace/ +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE hyperv +#endif /* _TRACE_HYPERV_H */ + +/* This part must be outside protection */ +#include <trace/define_trace.h>
Signature · 1 line
2.13.0
Re: [PATCH v9 10/10] tracing/hyper-v: trace hyperv_mmu_flush_tlb_others()
Quoted 6 lines · On Fri, 14 Jul 2017 14:44:42 +0200 Vitaly Kuznetsov <[email protected]> wrote:
Add Hyper-V tracing subsystem and trace
hyperv_mmu_flush_tlb_others(). Tracing is done the same way we doxen_mmu_flush_tlb_others().Signed-off-by Vitaly Kuznetsov <[email protected]>Reviewed-by Andy Shevchenko <[email protected]>Reviewed-by Stephen Hemminger <[email protected]>
(comment below)
Quoted 81 lines
--- MAINTAINERS | 1 + arch/x86/hyperv/mmu.c | 7 +++++++ arch/x86/include/asm/trace/hyperv.h | 40 +++++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 arch/x86/include/asm/trace/hyperv.hMAINTAINERS +1
-0@@ -6276,6 +6276,7 @@ M: Stephen Hemminger <[email protected]> L: [email protected] S: Maintained F: arch/x86/include/asm/mshyperv.h +F: arch/x86/include/asm/trace/hyperv.h F: arch/x86/include/uapi/asm/hyperv.h F: arch/x86/kernel/cpu/mshyperv.c F: arch/x86/hypervarch/x86/hyperv/mmu.c +7
-0@@ -8,6 +8,9 @@#include <asm/msr.h> #include <asm/tlbflush.h> +#define CREATE_TRACE_POINTS +#include <asm/trace/hyperv.h> +/* HvFlushVirtualAddressSpace, HvFlushVirtualAddressList hypercalls */ struct hv_flush_pcpu {u64 address_space;@@ -101,6 +104,8 @@ static void hyperv_flush_tlb_others(const struct cpumask *cpus,u64 status =U64_MAX ;unsigned long flags; +trace_hyperv_mmu_flush_tlb_others (cpus, info); +if (!pcpu_flush || !hv_hypercall_pg) goto do_native;@@ -170,6 +175,8 @@ static void hyperv_flush_tlb_others_ex(const struct cpumask *cpus,u64 status =U64_MAX ;unsigned long flags; +trace_hyperv_mmu_flush_tlb_others (cpus, info); +if (!pcpu_flush_ex || !hv_hypercall_pg) goto do_native;arch/x86/include/asm/trace/hyperv.h new file +24
-0@@ -0,0 +1,40 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM hyperv + +#if !defined(_TRACE_HYPERV_H) || defined(TRACE_HEADER_MULTI_READ ) +#define _TRACE_HYPERV_H + +#include <linux/tracepoint.h> + +#if IS_ENABLED (CONFIG_HYPERV ) + +TRACE_EVENT(hyperv_mmu_flush_tlb_others, + TP_PROTO(const struct cpumask *cpus, + const struct flush_tlb_info *info), + TP_ARGS(cpus, info), + TP_STRUCT__entry( + __field(unsigned int, ncpus) + __field(struct mm_struct *, mm) + __field(unsigned long, addr) + __field(unsigned long, end) + ), + TP_fast_assign(__entry->ncpus = cpumask_weight(cpus); + __entry->mm = info->mm; + __entry->addr = info->start; + __entry->end = info->end;
arch/x86/include/asm/trace/hyperv.h line 34
Quoted 10 lines
arch/x86/include/asm/trace/hyperv.h new file +10
-0+ ), +TP_printk ("ncpus %d mm %p addr %lx, end %lx" , + __entry->ncpus, __entry->mm, + __entry->addr, __entry->end) + ); + +#endif /* CONFIG_HYPERV */ + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH asm/trace/
Sometimes adding the include path in the make file may be easier. But this is fine too.
-- Steve
Quoted 6 lines
arch/x86/include/asm/trace/hyperv.h new file +6
-0+#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE hyperv +#endif /* _TRACE_HYPERV_H */ + +/* This part must be outside protection */ +#include <trace/define_trace.h>