From: Long Li <longli@xxxxxxxxxxxxx> Hyper-V may offer a non latency sensitive device with subchannels without monitor bit enabled. The decision is entirely on the Hyper-V host not configurable within guest. When a device has subchannels, also signal events for the subchannel if its monitor bit is disabled. Signed-off-by: Long Li <longli@xxxxxxxxxxxxx> --- drivers/uio/uio_hv_generic.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index 3976360d0096..8b6df598a728 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -65,6 +65,16 @@ struct hv_uio_private_data { char send_name[32]; }; +static void set_event(struct vmbus_channel *channel, s32 irq_state) +{ + channel->inbound.ring_buffer->interrupt_mask = !irq_state; + if (!channel->offermsg.monitor_allocated && irq_state) { + /* MB is needed for host to see the interrupt mask first */ + virt_mb(); + vmbus_setevent(channel); + } +} + /* * This is the irqcontrol callback to be registered to uio_info. * It can be used to disable/enable interrupt from user space processes. @@ -79,12 +89,13 @@ hv_uio_irqcontrol(struct uio_info *info, s32 irq_state) { struct hv_uio_private_data *pdata = info->priv; struct hv_device *dev = pdata->device; + struct vmbus_channel *primary, *sc; - dev->channel->inbound.ring_buffer->interrupt_mask = !irq_state; - virt_mb(); + primary = dev->channel; + set_event(primary, irq_state); - if (!dev->channel->offermsg.monitor_allocated && irq_state) - vmbus_setevent(dev->channel); + list_for_each_entry(sc, &primary->sc_list, sc_list) + set_event(sc, irq_state); return 0; } @@ -95,12 +106,19 @@ hv_uio_irqcontrol(struct uio_info *info, s32 irq_state) static void hv_uio_channel_cb(void *context) { struct vmbus_channel *chan = context; - struct hv_device *hv_dev = chan->device_obj; - struct hv_uio_private_data *pdata = hv_get_drvdata(hv_dev); + struct hv_device *hv_dev; + struct hv_uio_private_data *pdata; chan->inbound.ring_buffer->interrupt_mask = 1; virt_mb(); + /* + * The callback may come from a subchannel, in which case look + * for the hv device in the primary channel + */ + hv_dev = chan->primary_channel ? + chan->primary_channel->device_obj : chan->device_obj; + pdata = hv_get_drvdata(hv_dev); uio_event_notify(&pdata->info); } -- 2.34.1