Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

uio_hv_generic: Set event for all channels on the device

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.

This patch also removes the memory barrier when monitor bit is enabled
as it is not necessary. The memory barrier is only needed between
setting up interrupt mask and calling vmbus_set_event() when monitor
bit is disabled.

Signed-off-by: Long Li <longli@microsoft.com>
Reviewed-by: Michael Kelley <mhklinux@outlook.com>
Reviewed-by: Saurabh Sengar <ssengar@linux.microsoft.com>
Link: https://lore.kernel.org/r/1741644721-20389-1-git-send-email-longli@linuxonhyperv.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Long Li and committed by
Greg Kroah-Hartman
d062463e dd09eb0e

+26 -6
+26 -6
drivers/uio/uio_hv_generic.c
··· 65 65 char send_name[32]; 66 66 }; 67 67 68 + static void set_event(struct vmbus_channel *channel, s32 irq_state) 69 + { 70 + channel->inbound.ring_buffer->interrupt_mask = !irq_state; 71 + if (!channel->offermsg.monitor_allocated && irq_state) { 72 + /* MB is needed for host to see the interrupt mask first */ 73 + virt_mb(); 74 + vmbus_set_event(channel); 75 + } 76 + } 77 + 68 78 /* 69 79 * This is the irqcontrol callback to be registered to uio_info. 70 80 * It can be used to disable/enable interrupt from user space processes. ··· 89 79 { 90 80 struct hv_uio_private_data *pdata = info->priv; 91 81 struct hv_device *dev = pdata->device; 82 + struct vmbus_channel *primary, *sc; 92 83 93 - dev->channel->inbound.ring_buffer->interrupt_mask = !irq_state; 94 - virt_mb(); 84 + primary = dev->channel; 85 + set_event(primary, irq_state); 95 86 96 - if (!dev->channel->offermsg.monitor_allocated && irq_state) 97 - vmbus_setevent(dev->channel); 87 + mutex_lock(&vmbus_connection.channel_mutex); 88 + list_for_each_entry(sc, &primary->sc_list, sc_list) 89 + set_event(sc, irq_state); 90 + mutex_unlock(&vmbus_connection.channel_mutex); 98 91 99 92 return 0; 100 93 } ··· 108 95 static void hv_uio_channel_cb(void *context) 109 96 { 110 97 struct vmbus_channel *chan = context; 111 - struct hv_device *hv_dev = chan->device_obj; 112 - struct hv_uio_private_data *pdata = hv_get_drvdata(hv_dev); 98 + struct hv_device *hv_dev; 99 + struct hv_uio_private_data *pdata; 113 100 114 101 chan->inbound.ring_buffer->interrupt_mask = 1; 115 102 virt_mb(); 116 103 104 + /* 105 + * The callback may come from a subchannel, in which case look 106 + * for the hv device in the primary channel 107 + */ 108 + hv_dev = chan->primary_channel ? 109 + chan->primary_channel->device_obj : chan->device_obj; 110 + pdata = hv_get_drvdata(hv_dev); 117 111 uio_event_notify(&pdata->info); 118 112 } 119 113