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:
parent
be2dfd58fe
commit
646995bdda
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=300107
@ -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
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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_ */
|
||||
|
Loading…
Reference in New Issue
Block a user