From 6e3d66b80f670fdc64b9a120362a9f94b0494621 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 16 Apr 2018 11:19:24 -0700 Subject: uio_hv_generic: set size of ring buffer attribute The original code had ring size as a module parameter, but then it was made a fixed value. The code to set the size of the ring buffer binary file was lost in the transistion. The size is needed by user mode driver to know the size of the ring buffer. Fixes: 37b96a4931db ("uio_hv_generic: support sub-channels") Signed-off-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_hv_generic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/uio') diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index f695a7e8c314..7ff659dff11d 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -171,12 +171,12 @@ static int hv_uio_ring_mmap(struct file *filp, struct kobject *kobj, return 0; } -static struct bin_attribute ring_buffer_bin_attr __ro_after_init = { +static const struct bin_attribute ring_buffer_bin_attr = { .attr = { .name = "ring", .mode = 0600, - /* size is set at init time */ }, + .size = 2 * HV_RING_SIZE * PAGE_SIZE, .mmap = hv_uio_ring_mmap, }; -- cgit v1.2.3 From 9ab877a6ccf820483d79602bede0c1aa1da4d26a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 16 Apr 2018 11:19:25 -0700 Subject: uio_hv_generic: make ring buffer attribute for primary channel The primary channel also needs a ring buffer attribute. This allows application to check if kernel supports uio sub channels, and also makes all channels use consistent API. Fixes: 37b96a4931db ("uio_hv_generic: support sub-channels") Signed-off-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_hv_generic.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/uio') diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index 7ff659dff11d..972a42dd2a46 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -326,6 +326,11 @@ hv_uio_probe(struct hv_device *dev, vmbus_set_chn_rescind_callback(dev->channel, hv_uio_rescind); vmbus_set_sc_create_callback(dev->channel, hv_uio_new_channel); + ret = sysfs_create_bin_file(&dev->channel->kobj, &ring_buffer_bin_attr); + if (ret) + dev_notice(&dev->device, + "sysfs create ring bin file failed; %d\n", ret); + hv_set_drvdata(dev, pdata); return 0; -- cgit v1.2.3 From 135db384a2efde3718fd551e3968e97fcb400c84 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 16 Apr 2018 11:19:26 -0700 Subject: uio_hv_generic: use correct channel in isr Need to mask the correct sub-channel in the callback from VMBUS isr. Otherwise, can get in to infinite interrupt storm. Fixes: 37b96a4931db ("uio_hv_generic: support sub-channels") Signed-off-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_hv_generic.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/uio') diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index 972a42dd2a46..a9d7be4b964f 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -94,10 +94,11 @@ hv_uio_irqcontrol(struct uio_info *info, s32 irq_state) */ static void hv_uio_channel_cb(void *context) { - struct hv_uio_private_data *pdata = context; - struct hv_device *dev = pdata->device; + struct vmbus_channel *chan = context; + struct hv_device *hv_dev = chan->device_obj; + struct hv_uio_private_data *pdata = hv_get_drvdata(hv_dev); - dev->channel->inbound.ring_buffer->interrupt_mask = 1; + chan->inbound.ring_buffer->interrupt_mask = 1; virt_mb(); uio_event_notify(&pdata->info); @@ -180,19 +181,18 @@ static const struct bin_attribute ring_buffer_bin_attr = { .mmap = hv_uio_ring_mmap, }; -/* Callback from VMBUS subystem when new channel created. */ +/* Callback from VMBUS subsystem when new channel created. */ static void hv_uio_new_channel(struct vmbus_channel *new_sc) { struct hv_device *hv_dev = new_sc->primary_channel->device_obj; struct device *device = &hv_dev->device; - struct hv_uio_private_data *pdata = hv_get_drvdata(hv_dev); const size_t ring_bytes = HV_RING_SIZE * PAGE_SIZE; int ret; /* Create host communication ring */ ret = vmbus_open(new_sc, ring_bytes, ring_bytes, NULL, 0, - hv_uio_channel_cb, pdata); + hv_uio_channel_cb, new_sc); if (ret) { dev_err(device, "vmbus_open subchannel failed: %d\n", ret); return; @@ -234,7 +234,7 @@ hv_uio_probe(struct hv_device *dev, ret = vmbus_open(dev->channel, HV_RING_SIZE * PAGE_SIZE, HV_RING_SIZE * PAGE_SIZE, NULL, 0, - hv_uio_channel_cb, pdata); + hv_uio_channel_cb, dev->channel); if (ret) goto fail; -- cgit v1.2.3 From ce3d1536acabbdcdc3c945c3c078dd4ed1b8edfa Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 16 Apr 2018 11:19:27 -0700 Subject: uio_hv_generic: fix subchannel ring mmap The fault method of handling subchannel ring, did not work correctly (it only worked for the first page). Since ring buffer is physically contiguous, using the vm helper function is simpler and handles more cases. Fixes: 37b96a4931db ("uio_hv_generic: support sub-channels") Signed-off-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_hv_generic.c | 49 ++++++++------------------------------------ 1 file changed, 9 insertions(+), 40 deletions(-) (limited to 'drivers/uio') diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index a9d7be4b964f..c690d100adcd 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -19,7 +19,7 @@ * # echo -n "ed963694-e847-4b2a-85af-bc9cfc11d6f3" \ * > /sys/bus/vmbus/drivers/uio_hv_generic/bind */ - +#define DEBUG 1 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include @@ -122,54 +122,23 @@ static void hv_uio_rescind(struct vmbus_channel *channel) uio_event_notify(&pdata->info); } -/* - * Handle fault when looking for sub channel ring buffer - * Subchannel ring buffer is same as resource 0 which is main ring buffer - * This is derived from uio_vma_fault +/* Sysfs API to allow mmap of the ring buffers + * The ring buffer is allocated as contiguous memory by vmbus_open */ -static int hv_uio_vma_fault(struct vm_fault *vmf) -{ - struct vm_area_struct *vma = vmf->vma; - void *ring_buffer = vma->vm_private_data; - struct page *page; - void *addr; - - addr = ring_buffer + (vmf->pgoff << PAGE_SHIFT); - page = virt_to_page(addr); - get_page(page); - vmf->page = page; - return 0; -} - -static const struct vm_operations_struct hv_uio_vm_ops = { - .fault = hv_uio_vma_fault, -}; - -/* Sysfs API to allow mmap of the ring buffers */ static int hv_uio_ring_mmap(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, struct vm_area_struct *vma) { struct vmbus_channel *channel = container_of(kobj, struct vmbus_channel, kobj); - unsigned long requested_pages, actual_pages; - - if (vma->vm_end < vma->vm_start) - return -EINVAL; + struct hv_device *dev = channel->primary_channel->device_obj; + u16 q_idx = channel->offermsg.offer.sub_channel_index; - /* only allow 0 for now */ - if (vma->vm_pgoff > 0) - return -EINVAL; + dev_dbg(&dev->device, "mmap channel %u pages %#lx at %#lx\n", + q_idx, vma_pages(vma), vma->vm_pgoff); - requested_pages = vma_pages(vma); - actual_pages = 2 * HV_RING_SIZE; - if (requested_pages > actual_pages) - return -EINVAL; - - vma->vm_private_data = channel->ringbuffer_pages; - vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; - vma->vm_ops = &hv_uio_vm_ops; - return 0; + return vm_iomap_memory(vma, virt_to_phys(channel->ringbuffer_pages), + channel->ringbuffer_pagecount << PAGE_SHIFT); } static const struct bin_attribute ring_buffer_bin_attr = { -- cgit v1.2.3