From: Long Li <lon...@microsoft.com>

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 <lon...@microsoft.com>
---
Change log
v2: Use vmbus_set_event() to avoid additional check on monitored bit
    Lock vmbus_connection.channel_mutex when going through subchannels

 drivers/uio/uio_hv_generic.c | 32 ++++++++++++++++++++++++++------
 1 file changed, 26 insertions(+), 6 deletions(-)

diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c
index 3976360d0096..45be2f8baade 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_set_event(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,15 @@ 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);
+       mutex_lock(&vmbus_connection.channel_mutex);
+       list_for_each_entry(sc, &primary->sc_list, sc_list)
+               set_event(sc, irq_state);
+       mutex_unlock(&vmbus_connection.channel_mutex);
 
        return 0;
 }
@@ -95,12 +108,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


Reply via email to