hyperv/vmbus: Avoid two unnecessary protocol checks on isr handling path

MFC after:	1 week
Sponsored by:	Microsoft OSTC
Differential Revision:	https://reviews.freebsd.org/D6405
This commit is contained in:
Sepherosa Ziehau 2016-05-18 03:41:37 +00:00
parent be2dfd58fe
commit 646995bdda
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=300107
4 changed files with 68 additions and 49 deletions

View File

@ -289,56 +289,20 @@ hv_vmbus_disconnect(void) {
return (ret);
}
/**
* Handler for events
*/
void
hv_vmbus_on_events(int cpu)
static __inline void
vmbus_event_flags_proc(unsigned long *event_flags, int flag_cnt)
{
unsigned long *intr_flags;
hv_vmbus_synic_event_flags *event;
void *page_addr;
int flag_cnt, f;
int f;
KASSERT(cpu <= mp_maxid, ("VMBUS: hv_vmbus_on_events: "
"cpu out of range!"));
page_addr = hv_vmbus_g_context.syn_ic_event_page[cpu];
event = (hv_vmbus_synic_event_flags *)
page_addr + HV_VMBUS_MESSAGE_SINT;
if ((hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008) ||
(hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7)) {
flag_cnt = HV_MAX_NUM_CHANNELS_SUPPORTED >>
HV_CHANNEL_ULONG_SHIFT;
/*
* receive size is 1/2 page and divide that by 4 bytes
*/
if (atomic_testandclear_int(&event->flags32[0], 0))
intr_flags = hv_vmbus_g_connection.recv_interrupt_page;
else
return;
} else {
/*
* On Host with Win8 or above, the event page can be
* checked directly to get the id of the channel
* that has the pending interrupt.
*/
flag_cnt = VMBUS_PCPU_GET(event_flag_cnt, cpu);
intr_flags = event->flagsul;
}
/*
* Check events
*/
for (f = 0; f < flag_cnt; f++) {
for (f = 0; f < flag_cnt; ++f) {
uint32_t rel_id_base;
unsigned long flags;
int bit;
if (intr_flags[f] == 0)
if (event_flags[f] == 0)
continue;
flags = atomic_swap_long(&intr_flags[f], 0);
flags = atomic_swap_long(&event_flags[f], 0);
rel_id_base = f << HV_CHANNEL_ULONG_SHIFT;
while ((bit = ffsl(flags)) != 0) {
@ -362,6 +326,37 @@ hv_vmbus_on_events(int cpu)
}
}
void
vmbus_event_proc(struct vmbus_softc *sc, int cpu)
{
hv_vmbus_synic_event_flags *event;
event = ((hv_vmbus_synic_event_flags *)
hv_vmbus_g_context.syn_ic_event_page[cpu]) + HV_VMBUS_MESSAGE_SINT;
/*
* On Host with Win8 or above, the event page can be checked directly
* to get the id of the channel that has the pending interrupt.
*/
vmbus_event_flags_proc(event->flagsul,
VMBUS_SC_PCPU_GET(sc, event_flag_cnt, cpu));
}
void
vmbus_event_proc_compat(struct vmbus_softc *sc __unused, int cpu)
{
hv_vmbus_synic_event_flags *event;
event = ((hv_vmbus_synic_event_flags *)
hv_vmbus_g_context.syn_ic_event_page[cpu]) + HV_VMBUS_MESSAGE_SINT;
if (atomic_testandclear_int(&event->flags32[0], 0)) {
vmbus_event_flags_proc(
hv_vmbus_g_connection.recv_interrupt_page,
HV_MAX_NUM_CHANNELS_SUPPORTED >> HV_CHANNEL_ULONG_SHIFT);
}
}
/**
* Send a msg on the vmbus's message connection
*/

View File

@ -146,6 +146,7 @@ vmbus_msg_swintr(void *arg, int pending __unused)
static inline int
hv_vmbus_isr(struct trapframe *frame)
{
struct vmbus_softc *sc = vmbus_get_softc();
int cpu;
hv_vmbus_message* msg;
void* page_addr;
@ -157,8 +158,7 @@ hv_vmbus_isr(struct trapframe *frame)
* before checking for messages. This is the way they do it
* in Windows when running as a guest in Hyper-V
*/
hv_vmbus_on_events(cpu);
sc->vmbus_event_proc(sc, cpu);
/* Check if there are actual msgs to be process */
page_addr = hv_vmbus_g_context.syn_ic_msg_page[cpu];
@ -388,6 +388,7 @@ extern inthand_t IDTVEC(hv_vmbus_callback);
static int
vmbus_bus_init(void)
{
struct vmbus_softc *sc;
int i, j, n, ret;
char buf[MAXCOMLEN + 1];
cpuset_t cpu_mask;
@ -396,6 +397,7 @@ vmbus_bus_init(void)
return (0);
vmbus_inited = 1;
sc = vmbus_get_softc();
ret = hv_vmbus_init();
@ -481,6 +483,12 @@ vmbus_bus_init(void)
if (ret != 0)
goto cleanup1;
if (hv_vmbus_protocal_version == HV_VMBUS_VERSION_WS2008 ||
hv_vmbus_protocal_version == HV_VMBUS_VERSION_WIN7)
sc->vmbus_event_proc = vmbus_event_proc_compat;
else
sc->vmbus_event_proc = vmbus_event_proc;
hv_vmbus_request_channel_offers();
vmbus_scan();
@ -515,6 +523,11 @@ vmbus_bus_init(void)
return (ret);
}
static void
vmbus_event_proc_dummy(struct vmbus_softc *sc __unused, int cpu __unused)
{
}
static int
vmbus_attach(device_t dev)
{
@ -524,6 +537,13 @@ vmbus_attach(device_t dev)
vmbus_devp = dev;
vmbus_sc = device_get_softc(dev);
/*
* Event processing logic will be configured:
* - After the vmbus protocol version negotiation.
* - Before we request channel offers.
*/
vmbus_sc->vmbus_event_proc = vmbus_event_proc_dummy;
#ifndef EARLY_AP_STARTUP
/*
* If the system has already booted and thread

View File

@ -753,7 +753,6 @@ int hv_vmbus_connect(void);
int hv_vmbus_disconnect(void);
int hv_vmbus_post_message(void *buffer, size_t buf_size);
int hv_vmbus_set_event(hv_vmbus_channel *channel);
void hv_vmbus_on_events(int cpu);
/**
* Event Timer interfaces

View File

@ -36,6 +36,7 @@ struct vmbus_pcpu_data {
} __aligned(CACHE_LINE_SIZE);
struct vmbus_softc {
void (*vmbus_event_proc)(struct vmbus_softc *, int);
struct vmbus_pcpu_data vmbus_pcpu[MAXCPU];
};
@ -47,11 +48,15 @@ vmbus_get_softc(void)
return vmbus_sc;
}
#define VMBUS_PCPU_GET(field, cpu) \
(vmbus_get_softc())->vmbus_pcpu[cpu].field
#define VMBUS_PCPU_PTR(field, cpu) \
&(vmbus_get_softc())->vmbus_pcpu[cpu].field
#define VMBUS_SC_PCPU_GET(sc, field, cpu) (sc)->vmbus_pcpu[(cpu)].field
#define VMBUS_SC_PCPU_PTR(sc, field, cpu) &(sc)->vmbus_pcpu[(cpu)].field
#define VMBUS_PCPU_GET(field, cpu) \
VMBUS_SC_PCPU_GET(vmbus_get_softc(), field, (cpu))
#define VMBUS_PCPU_PTR(field, cpu) \
VMBUS_SC_PCPU_PTR(vmbus_get_softc(), field, (cpu))
void vmbus_on_channel_open(const struct hv_vmbus_channel *);
void vmbus_event_proc(struct vmbus_softc *, int);
void vmbus_event_proc_compat(struct vmbus_softc *, int);
#endif /* !_VMBUS_VAR_H_ */