Message ID | 20161220155602.6298-3-rkagan@virtuozzo.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Tue, Dec 20, 2016 at 09:24:53AM -0800, Stephen Hemminger wrote: > On Tue, 20 Dec 2016 18:55:49 +0300 > Roman Kagan <rkagan@virtuozzo.com> wrote: > > > Move definitions related to the Hyper-V SynIC event flags to a header > > where they can be consumed by userspace. > > > > While doing so, also clean up their use by switching to standard bitops > > and struct-based dereferencing. The latter is also done for message > > pages. > > > > Signed-off-by: Roman Kagan <rkagan@virtuozzo.com> > > --- > > arch/x86/include/uapi/asm/hyperv.h | 13 +++++++++ > > drivers/hv/hyperv_vmbus.h | 24 ++-------------- > > drivers/hv/channel_mgmt.c | 10 +++---- > > drivers/hv/connection.c | 47 ++++++++++--------------------- > > drivers/hv/vmbus_drv.c | 57 ++++++++++++++------------------------ > > 5 files changed, 54 insertions(+), 97 deletions(-) > > > > diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h > > index 6098ab5..af542a3 100644 > > --- a/arch/x86/include/uapi/asm/hyperv.h > > +++ b/arch/x86/include/uapi/asm/hyperv.h > > @@ -363,4 +363,17 @@ struct hv_timer_message_payload { > > #define HV_STIMER_AUTOENABLE (1ULL << 3) > > #define HV_STIMER_SINT(config) (__u8)(((config) >> 16) & 0x0F) > > > > +/* Define synthetic interrupt controller flag constants. */ > > +#define HV_EVENT_FLAGS_COUNT (256 * 8) > > + > > +/* Define the synthetic interrupt controller event flags format. */ > > +struct hv_synic_event_flags { > > + __u64 flags[HV_EVENT_FLAGS_COUNT / 64]; > > +}; > > + > > +/* Define the synthetic interrupt flags page layout. */ > > +struct hv_synic_event_flags_page { > > + struct hv_synic_event_flags sintevent_flags[HV_SYNIC_SINT_COUNT]; > > +}; > > + > > #endif > > How are these going to be exposed to user space? > > They should really be unsigned long since there is no guarantee of atomic operation > on 64 bit values on 32 bit architectures. Indeed, absolutely. These are bitmaps and should be unsigned long[], of course. I'll fix it in the next iteration. Thanks, Roman. -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Roman, [auto build test ERROR on linus/master] [also build test ERROR on v4.9 next-20161221] [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/Roman-Kagan/hyperv-more-stuff-to-uapi-cleanup/20161221-130415 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/Roman-Kagan/hyperv-more-stuff-to-uapi-cleanup/20161221-130415 HEAD 35a54cd6795c4aa6f101c58ab076c6bdd63b3779 builds fine. It only hurts bisectibility. All errors (new ones prefixed by >>): drivers/hv/connection.c: In function 'vmbus_set_event': >> drivers/hv/connection.c:473:3: error: implicit declaration of function 'sync_set_bit' [-Werror=implicit-function-declaration] sync_set_bit(child_relid & 31, ^~~~~~~~~~~~ cc1: some warnings being treated as errors -- drivers/hv/channel.c: In function 'vmbus_setevent': >> drivers/hv/channel.c:53:3: error: implicit declaration of function 'sync_set_bit' [-Werror=implicit-function-declaration] sync_set_bit(channel->offermsg.child_relid & 31, ^~~~~~~~~~~~ cc1: some warnings being treated as errors vim +/sync_set_bit +473 drivers/hv/connection.c 1b807e101 drivers/hv/connection.c K. Y. Srinivasan 2015-12-21 467 void vmbus_set_event(struct vmbus_channel *channel) 3e7ee4902 drivers/staging/hv/Connection.c Hank Janssen 2009-07-13 468 { 21c3bef5d drivers/hv/connection.c K. Y. Srinivasan 2012-12-01 469 u32 child_relid = channel->offermsg.child_relid; 3be777740 drivers/hv/connection.c K. Y. Srinivasan 2012-12-01 470 3be777740 drivers/hv/connection.c K. Y. Srinivasan 2012-12-01 471 if (!channel->is_dedicated_interrupt) { 454f18a96 drivers/staging/hv/Connection.c Bill Pemberton 2009-07-27 472 /* Each u32 represents 32 channels */ 223565857 drivers/staging/hv/connection.c Olaf Hering 2011-03-21 @473 sync_set_bit(child_relid & 31, da9fcb726 drivers/staging/hv/connection.c Haiyang Zhang 2011-01-26 474 (unsigned long *)vmbus_connection.send_int_page + 15b2f6479 drivers/staging/hv/connection.c Haiyang Zhang 2011-01-26 475 (child_relid >> 5)); 3be777740 drivers/hv/connection.c K. Y. Srinivasan 2012-12-01 476 } :::::: The code at line 473 was first introduced by commit :::::: 22356585712d1ff08fbfed152edd8b386873b238 staging: hv: use sync_bitops when interacting with the hypervisor :::::: TO: Olaf Hering <olaf@aepfle.de> :::::: CC: Greg Kroah-Hartman <gregkh@suse.de> --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation
> -----Original Message----- > From: Roman Kagan [mailto:rkagan@virtuozzo.com] > Sent: Tuesday, December 20, 2016 7:56 AM > To: Paolo Bonzini <pbonzini@redhat.com>; Radim Krčmář > <rkrcmar@redhat.com>; KY Srinivasan <kys@microsoft.com>; Vitaly > Kuznetsov <vkuznets@redhat.com> > Cc: Thomas Gleixner <tglx@linutronix.de>; Ingo Molnar > <mingo@redhat.com>; H. Peter Anvin <hpa@zytor.com>; x86@kernel.org; > Haiyang Zhang <haiyangz@microsoft.com>; kvm@vger.kernel.org; linux- > kernel@vger.kernel.org; devel@linuxdriverproject.org; Denis V . Lunev > <den@openvz.org>; Roman Kagan <rkagan@virtuozzo.com> > Subject: [PATCH 02/15] hyperv: uapi-fy synic event flags definitions > > Move definitions related to the Hyper-V SynIC event flags to a header > where they can be consumed by userspace. > > While doing so, also clean up their use by switching to standard bitops > and struct-based dereferencing. The latter is also done for message > pages. Please breakup this patch. > > Signed-off-by: Roman Kagan <rkagan@virtuozzo.com> > --- > arch/x86/include/uapi/asm/hyperv.h | 13 +++++++++ > drivers/hv/hyperv_vmbus.h | 24 ++-------------- > drivers/hv/channel_mgmt.c | 10 +++---- > drivers/hv/connection.c | 47 ++++++++++--------------------- > drivers/hv/vmbus_drv.c | 57 ++++++++++++++------------------------ > 5 files changed, 54 insertions(+), 97 deletions(-) > > diff --git a/arch/x86/include/uapi/asm/hyperv.h > b/arch/x86/include/uapi/asm/hyperv.h > index 6098ab5..af542a3 100644 > --- a/arch/x86/include/uapi/asm/hyperv.h > +++ b/arch/x86/include/uapi/asm/hyperv.h > @@ -363,4 +363,17 @@ struct hv_timer_message_payload { > #define HV_STIMER_AUTOENABLE (1ULL << 3) > #define HV_STIMER_SINT(config) (__u8)(((config) >> 16) & > 0x0F) > > +/* Define synthetic interrupt controller flag constants. */ > +#define HV_EVENT_FLAGS_COUNT (256 * 8) > + > +/* Define the synthetic interrupt controller event flags format. */ > +struct hv_synic_event_flags { > + __u64 flags[HV_EVENT_FLAGS_COUNT / 64]; > +}; > + > +/* Define the synthetic interrupt flags page layout. */ > +struct hv_synic_event_flags_page { > + struct hv_synic_event_flags > sintevent_flags[HV_SYNIC_SINT_COUNT]; > +}; > + > #endif > diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h > index 4516498..4fab154 100644 > --- a/drivers/hv/hyperv_vmbus.h > +++ b/drivers/hv/hyperv_vmbus.h > @@ -26,7 +26,6 @@ > #define _HYPERV_VMBUS_H > > #include <linux/list.h> > -#include <asm/sync_bitops.h> > #include <linux/atomic.h> > #include <linux/hyperv.h> > > @@ -75,11 +74,6 @@ enum hv_cpuid_function { > > #define HV_ANY_VP (0xFFFFFFFF) > > -/* Define synthetic interrupt controller flag constants. */ > -#define HV_EVENT_FLAGS_COUNT (256 * 8) > -#define HV_EVENT_FLAGS_BYTE_COUNT (256) > -#define HV_EVENT_FLAGS_DWORD_COUNT (256 / sizeof(u32)) > - > /* Define invalid partition identifier. */ > #define HV_PARTITION_ID_INVALID ((u64)0x0) > > @@ -146,20 +140,6 @@ union hv_timer_config { > }; > }; > > -/* Define the number of message buffers associated with each port. */ > -#define HV_PORT_MESSAGE_BUFFER_COUNT (16) > - > -/* Define the synthetic interrupt controller event flags format. */ > -union hv_synic_event_flags { > - u8 flags8[HV_EVENT_FLAGS_BYTE_COUNT]; > - u32 flags32[HV_EVENT_FLAGS_DWORD_COUNT]; > -}; > - > -/* Define the synthetic interrupt flags page layout. */ > -struct hv_synic_event_flags_page { > - union hv_synic_event_flags > sintevent_flags[HV_SYNIC_SINT_COUNT]; > -}; > - > /* Define SynIC control register. */ > union hv_synic_scontrol { > u64 as_uint64; > @@ -434,8 +414,8 @@ struct hv_context { > > bool synic_initialized; > > - void *synic_message_page[NR_CPUS]; > - void *synic_event_page[NR_CPUS]; > + struct hv_message_page *synic_message_page[NR_CPUS]; > + struct hv_synic_event_flags_page *synic_event_page[NR_CPUS]; > /* > * Hypervisor's notion of virtual processor ID is different from > * Linux' notion of CPU ID. This information can only be retrieved > diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c > index 26b4192..49eaae2 100644 > --- a/drivers/hv/channel_mgmt.c > +++ b/drivers/hv/channel_mgmt.c > @@ -654,7 +654,6 @@ static void init_vp_index(struct vmbus_channel > *channel, u16 dev_type) > static void vmbus_wait_for_unload(void) > { > int cpu; > - void *page_addr; > struct hv_message *msg; > struct vmbus_channel_message_header *hdr; > u32 message_type; > @@ -673,9 +672,8 @@ static void vmbus_wait_for_unload(void) > break; > > for_each_online_cpu(cpu) { > - page_addr = hv_context.synic_message_page[cpu]; > - msg = (struct hv_message *)page_addr + > - VMBUS_MESSAGE_SINT; > + msg = &hv_context.synic_message_page[cpu]-> > + > sint_message[VMBUS_MESSAGE_SINT]; > > message_type = READ_ONCE(msg- > >header.message_type); > if (message_type == HVMSG_NONE) > @@ -699,8 +697,8 @@ static void vmbus_wait_for_unload(void) > * messages after we reconnect. > */ > for_each_online_cpu(cpu) { > - page_addr = hv_context.synic_message_page[cpu]; > - msg = (struct hv_message *)page_addr + > VMBUS_MESSAGE_SINT; > + msg = &hv_context.synic_message_page[cpu]-> > + sint_message[VMBUS_MESSAGE_SINT]; > msg->header.message_type = HVMSG_NONE; > } > } > diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c > index 6ce8b87..aaa2103 100644 > --- a/drivers/hv/connection.c > +++ b/drivers/hv/connection.c > @@ -381,17 +381,12 @@ static void process_chn_event(u32 relid) > */ > void vmbus_on_event(unsigned long data) > { > - u32 dword; > - u32 maxdword; > - int bit; > - u32 relid; > - u32 *recv_int_page = NULL; > - void *page_addr; > + u32 relid, max_relid; > + unsigned long *recv_int_page; > int cpu = smp_processor_id(); > - union hv_synic_event_flags *event; > > if (vmbus_proto_version < VERSION_WIN8) { > - maxdword = MAX_NUM_CHANNELS_SUPPORTED >> 5; > + max_relid = MAX_NUM_CHANNELS_SUPPORTED; > recv_int_page = vmbus_connection.recv_int_page; > } else { > /* > @@ -399,36 +394,22 @@ void vmbus_on_event(unsigned long data) > * can be directly checked to get the id of the channel > * that has the interrupt pending. > */ > - maxdword = HV_EVENT_FLAGS_DWORD_COUNT; > - page_addr = hv_context.synic_event_page[cpu]; > - event = (union hv_synic_event_flags *)page_addr + > - VMBUS_MESSAGE_SINT; > - recv_int_page = event->flags32; > + struct hv_synic_event_flags *event = > + &hv_context.synic_event_page[cpu]-> > + sintevent_flags[VMBUS_MESSAGE_SINT]; > + max_relid = HV_EVENT_FLAGS_COUNT; > + recv_int_page = (unsigned long *)event->flags; > } > > - > - > /* Check events */ > if (!recv_int_page) > return; > - for (dword = 0; dword < maxdword; dword++) { > - if (!recv_int_page[dword]) > - continue; > - for (bit = 0; bit < 32; bit++) { > - if (sync_test_and_clear_bit(bit, > - (unsigned long *)&recv_int_page[dword])) { > - relid = (dword << 5) + bit; > - > - if (relid == 0) > - /* > - * Special case - vmbus > - * channel protocol msg > - */ > - continue; > - > - process_chn_event(relid); > - } > - } > + > + /* relid == 0 is vmbus channel protocol msg */ > + relid = 1; > + for_each_set_bit_from(relid, recv_int_page, max_relid) { > + clear_bit(relid, recv_int_page); We are using this test_and_clear_bit paradigm for locking. The current code used the sync variant to ensure the host saw the changes we were making here (clearing the bit). You may want to add a barrier here or use the sync variant. > + process_chn_event(relid); > } > } > > diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c > index 230c62e..13dd210 100644 > --- a/drivers/hv/vmbus_drv.c > +++ b/drivers/hv/vmbus_drv.c > @@ -872,9 +872,8 @@ static void hv_process_timer_expiration(struct > hv_message *msg, int cpu) > void vmbus_on_msg_dpc(unsigned long data) > { > int cpu = smp_processor_id(); > - void *page_addr = hv_context.synic_message_page[cpu]; > - struct hv_message *msg = (struct hv_message *)page_addr + > - VMBUS_MESSAGE_SINT; > + struct hv_message *msg = &hv_context.synic_message_page[cpu]- > > > + > sint_message[VMBUS_MESSAGE_SINT]; > struct vmbus_channel_message_header *hdr; > struct vmbus_channel_message_table_entry *entry; > struct onmessage_work_context *ctx; > @@ -911,54 +910,40 @@ void vmbus_on_msg_dpc(unsigned long data) > static void vmbus_isr(void) > { > int cpu = smp_processor_id(); > - void *page_addr; > struct hv_message *msg; > - union hv_synic_event_flags *event; > - bool handled = false; > + struct hv_synic_event_flags *event; > > - page_addr = hv_context.synic_event_page[cpu]; > - if (page_addr == NULL) > + if (!hv_context.synic_event_page[cpu]) > return; > > - event = (union hv_synic_event_flags *)page_addr + > - VMBUS_MESSAGE_SINT; > + event = &hv_context.synic_event_page[cpu]-> > + sintevent_flags[VMBUS_MESSAGE_SINT]; > /* > * Check for events before checking for messages. This is the order > * in which events and messages are checked in Windows guests on > * Hyper-V, and the Windows team suggested we do the same. > */ > > - if ((vmbus_proto_version == VERSION_WS2008) || > - (vmbus_proto_version == VERSION_WIN7)) { > - > + /* On win8 and above the channel interrupts are signaled directly in > + * the event page and will be checked in the .event_dpc > + */ > + if (vmbus_proto_version >= VERSION_WIN8 || > /* Since we are a child, we only need to check bit 0 */ > - if (sync_test_and_clear_bit(0, > - (unsigned long *) &event->flags32[0])) { > - handled = true; > - } > - } else { > - /* > - * Our host is win8 or above. The signaling mechanism > - * has changed and we can directly look at the event page. > - * If bit n is set then we have an interrup on the channel > - * whose id is n. > - */ > - handled = true; > - } > - > - if (handled) > + test_and_clear_bit(0, (unsigned long *)event->flags)) Don't we need the sync variant of test_and_clear_bit here. > tasklet_schedule(hv_context.event_dpc[cpu]); > > - > - page_addr = hv_context.synic_message_page[cpu]; > - msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT; > + msg = &hv_context.synic_message_page[cpu]-> > + sint_message[VMBUS_MESSAGE_SINT]; > > /* Check if there are actual msgs to be processed */ > - if (msg->header.message_type != HVMSG_NONE) { > - if (msg->header.message_type == HVMSG_TIMER_EXPIRED) > - hv_process_timer_expiration(msg, cpu); > - else > - tasklet_schedule(hv_context.msg_dpc[cpu]); > + switch (READ_ONCE(msg->header.message_type)) { > + case HVMSG_NONE: > + break; > + case HVMSG_TIMER_EXPIRED: > + hv_process_timer_expiration(msg, cpu); > + break; > + default: > + tasklet_schedule(hv_context.msg_dpc[cpu]); > } > > add_interrupt_randomness(HYPERVISOR_CALLBACK_VECTOR, 0); > -- > 2.9.3 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h index 6098ab5..af542a3 100644 --- a/arch/x86/include/uapi/asm/hyperv.h +++ b/arch/x86/include/uapi/asm/hyperv.h @@ -363,4 +363,17 @@ struct hv_timer_message_payload { #define HV_STIMER_AUTOENABLE (1ULL << 3) #define HV_STIMER_SINT(config) (__u8)(((config) >> 16) & 0x0F) +/* Define synthetic interrupt controller flag constants. */ +#define HV_EVENT_FLAGS_COUNT (256 * 8) + +/* Define the synthetic interrupt controller event flags format. */ +struct hv_synic_event_flags { + __u64 flags[HV_EVENT_FLAGS_COUNT / 64]; +}; + +/* Define the synthetic interrupt flags page layout. */ +struct hv_synic_event_flags_page { + struct hv_synic_event_flags sintevent_flags[HV_SYNIC_SINT_COUNT]; +}; + #endif diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 4516498..4fab154 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -26,7 +26,6 @@ #define _HYPERV_VMBUS_H #include <linux/list.h> -#include <asm/sync_bitops.h> #include <linux/atomic.h> #include <linux/hyperv.h> @@ -75,11 +74,6 @@ enum hv_cpuid_function { #define HV_ANY_VP (0xFFFFFFFF) -/* Define synthetic interrupt controller flag constants. */ -#define HV_EVENT_FLAGS_COUNT (256 * 8) -#define HV_EVENT_FLAGS_BYTE_COUNT (256) -#define HV_EVENT_FLAGS_DWORD_COUNT (256 / sizeof(u32)) - /* Define invalid partition identifier. */ #define HV_PARTITION_ID_INVALID ((u64)0x0) @@ -146,20 +140,6 @@ union hv_timer_config { }; }; -/* Define the number of message buffers associated with each port. */ -#define HV_PORT_MESSAGE_BUFFER_COUNT (16) - -/* Define the synthetic interrupt controller event flags format. */ -union hv_synic_event_flags { - u8 flags8[HV_EVENT_FLAGS_BYTE_COUNT]; - u32 flags32[HV_EVENT_FLAGS_DWORD_COUNT]; -}; - -/* Define the synthetic interrupt flags page layout. */ -struct hv_synic_event_flags_page { - union hv_synic_event_flags sintevent_flags[HV_SYNIC_SINT_COUNT]; -}; - /* Define SynIC control register. */ union hv_synic_scontrol { u64 as_uint64; @@ -434,8 +414,8 @@ struct hv_context { bool synic_initialized; - void *synic_message_page[NR_CPUS]; - void *synic_event_page[NR_CPUS]; + struct hv_message_page *synic_message_page[NR_CPUS]; + struct hv_synic_event_flags_page *synic_event_page[NR_CPUS]; /* * Hypervisor's notion of virtual processor ID is different from * Linux' notion of CPU ID. This information can only be retrieved diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 26b4192..49eaae2 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -654,7 +654,6 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type) static void vmbus_wait_for_unload(void) { int cpu; - void *page_addr; struct hv_message *msg; struct vmbus_channel_message_header *hdr; u32 message_type; @@ -673,9 +672,8 @@ static void vmbus_wait_for_unload(void) break; for_each_online_cpu(cpu) { - page_addr = hv_context.synic_message_page[cpu]; - msg = (struct hv_message *)page_addr + - VMBUS_MESSAGE_SINT; + msg = &hv_context.synic_message_page[cpu]-> + sint_message[VMBUS_MESSAGE_SINT]; message_type = READ_ONCE(msg->header.message_type); if (message_type == HVMSG_NONE) @@ -699,8 +697,8 @@ static void vmbus_wait_for_unload(void) * messages after we reconnect. */ for_each_online_cpu(cpu) { - page_addr = hv_context.synic_message_page[cpu]; - msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT; + msg = &hv_context.synic_message_page[cpu]-> + sint_message[VMBUS_MESSAGE_SINT]; msg->header.message_type = HVMSG_NONE; } } diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index 6ce8b87..aaa2103 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c @@ -381,17 +381,12 @@ static void process_chn_event(u32 relid) */ void vmbus_on_event(unsigned long data) { - u32 dword; - u32 maxdword; - int bit; - u32 relid; - u32 *recv_int_page = NULL; - void *page_addr; + u32 relid, max_relid; + unsigned long *recv_int_page; int cpu = smp_processor_id(); - union hv_synic_event_flags *event; if (vmbus_proto_version < VERSION_WIN8) { - maxdword = MAX_NUM_CHANNELS_SUPPORTED >> 5; + max_relid = MAX_NUM_CHANNELS_SUPPORTED; recv_int_page = vmbus_connection.recv_int_page; } else { /* @@ -399,36 +394,22 @@ void vmbus_on_event(unsigned long data) * can be directly checked to get the id of the channel * that has the interrupt pending. */ - maxdword = HV_EVENT_FLAGS_DWORD_COUNT; - page_addr = hv_context.synic_event_page[cpu]; - event = (union hv_synic_event_flags *)page_addr + - VMBUS_MESSAGE_SINT; - recv_int_page = event->flags32; + struct hv_synic_event_flags *event = + &hv_context.synic_event_page[cpu]-> + sintevent_flags[VMBUS_MESSAGE_SINT]; + max_relid = HV_EVENT_FLAGS_COUNT; + recv_int_page = (unsigned long *)event->flags; } - - /* Check events */ if (!recv_int_page) return; - for (dword = 0; dword < maxdword; dword++) { - if (!recv_int_page[dword]) - continue; - for (bit = 0; bit < 32; bit++) { - if (sync_test_and_clear_bit(bit, - (unsigned long *)&recv_int_page[dword])) { - relid = (dword << 5) + bit; - - if (relid == 0) - /* - * Special case - vmbus - * channel protocol msg - */ - continue; - - process_chn_event(relid); - } - } + + /* relid == 0 is vmbus channel protocol msg */ + relid = 1; + for_each_set_bit_from(relid, recv_int_page, max_relid) { + clear_bit(relid, recv_int_page); + process_chn_event(relid); } } diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 230c62e..13dd210 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -872,9 +872,8 @@ static void hv_process_timer_expiration(struct hv_message *msg, int cpu) void vmbus_on_msg_dpc(unsigned long data) { int cpu = smp_processor_id(); - void *page_addr = hv_context.synic_message_page[cpu]; - struct hv_message *msg = (struct hv_message *)page_addr + - VMBUS_MESSAGE_SINT; + struct hv_message *msg = &hv_context.synic_message_page[cpu]-> + sint_message[VMBUS_MESSAGE_SINT]; struct vmbus_channel_message_header *hdr; struct vmbus_channel_message_table_entry *entry; struct onmessage_work_context *ctx; @@ -911,54 +910,40 @@ void vmbus_on_msg_dpc(unsigned long data) static void vmbus_isr(void) { int cpu = smp_processor_id(); - void *page_addr; struct hv_message *msg; - union hv_synic_event_flags *event; - bool handled = false; + struct hv_synic_event_flags *event; - page_addr = hv_context.synic_event_page[cpu]; - if (page_addr == NULL) + if (!hv_context.synic_event_page[cpu]) return; - event = (union hv_synic_event_flags *)page_addr + - VMBUS_MESSAGE_SINT; + event = &hv_context.synic_event_page[cpu]-> + sintevent_flags[VMBUS_MESSAGE_SINT]; /* * Check for events before checking for messages. This is the order * in which events and messages are checked in Windows guests on * Hyper-V, and the Windows team suggested we do the same. */ - if ((vmbus_proto_version == VERSION_WS2008) || - (vmbus_proto_version == VERSION_WIN7)) { - + /* On win8 and above the channel interrupts are signaled directly in + * the event page and will be checked in the .event_dpc + */ + if (vmbus_proto_version >= VERSION_WIN8 || /* Since we are a child, we only need to check bit 0 */ - if (sync_test_and_clear_bit(0, - (unsigned long *) &event->flags32[0])) { - handled = true; - } - } else { - /* - * Our host is win8 or above. The signaling mechanism - * has changed and we can directly look at the event page. - * If bit n is set then we have an interrup on the channel - * whose id is n. - */ - handled = true; - } - - if (handled) + test_and_clear_bit(0, (unsigned long *)event->flags)) tasklet_schedule(hv_context.event_dpc[cpu]); - - page_addr = hv_context.synic_message_page[cpu]; - msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT; + msg = &hv_context.synic_message_page[cpu]-> + sint_message[VMBUS_MESSAGE_SINT]; /* Check if there are actual msgs to be processed */ - if (msg->header.message_type != HVMSG_NONE) { - if (msg->header.message_type == HVMSG_TIMER_EXPIRED) - hv_process_timer_expiration(msg, cpu); - else - tasklet_schedule(hv_context.msg_dpc[cpu]); + switch (READ_ONCE(msg->header.message_type)) { + case HVMSG_NONE: + break; + case HVMSG_TIMER_EXPIRED: + hv_process_timer_expiration(msg, cpu); + break; + default: + tasklet_schedule(hv_context.msg_dpc[cpu]); } add_interrupt_randomness(HYPERVISOR_CALLBACK_VECTOR, 0);
Move definitions related to the Hyper-V SynIC event flags to a header where they can be consumed by userspace. While doing so, also clean up their use by switching to standard bitops and struct-based dereferencing. The latter is also done for message pages. Signed-off-by: Roman Kagan <rkagan@virtuozzo.com> --- arch/x86/include/uapi/asm/hyperv.h | 13 +++++++++ drivers/hv/hyperv_vmbus.h | 24 ++-------------- drivers/hv/channel_mgmt.c | 10 +++---- drivers/hv/connection.c | 47 ++++++++++--------------------- drivers/hv/vmbus_drv.c | 57 ++++++++++++++------------------------ 5 files changed, 54 insertions(+), 97 deletions(-)