summary refs log tree commit diff
path: root/drivers/uio
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-04-30 05:05:54 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-04-30 05:05:54 -0700
commit720d690e3680d8ae5fcf86f8614c1a10b4ee7605 (patch)
tree02158973d51022d7374f5b6e2f1953b530127f43 /drivers/uio
parent72b6500c1cc68b949faa1bac76359dc601b482d6 (diff)
parent6da6c0db5316275015e8cc2959f12a17584aeb64 (diff)
downloadlinux-720d690e3680d8ae5fcf86f8614c1a10b4ee7605.tar.gz
Merge 4.17-rc3 into char-misc-next
We want the fixes in here as well.

Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/uio')
-rw-r--r--drivers/uio/uio_hv_generic.c72
1 files changed, 23 insertions, 49 deletions
diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c
index f695a7e8c314..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 <linux/device.h>
@@ -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);
@@ -121,78 +122,46 @@ 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;
-
-	/* only allow 0 for now */
-	if (vma->vm_pgoff > 0)
-		return -EINVAL;
+	struct hv_device *dev = channel->primary_channel->device_obj;
+	u16 q_idx = channel->offermsg.offer.sub_channel_index;
 
-	requested_pages = vma_pages(vma);
-	actual_pages = 2 * HV_RING_SIZE;
-	if (requested_pages > actual_pages)
-		return -EINVAL;
+	dev_dbg(&dev->device, "mmap channel %u pages %#lx at %#lx\n",
+		q_idx, vma_pages(vma), vma->vm_pgoff);
 
-	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 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,
 };
 
-/* 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 +203,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;
 
@@ -326,6 +295,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;