From 4289696863cc320e5fe573df5ad7800701751599 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 4 Jan 2018 14:13:27 -0800 Subject: uio_hv_generic: fix configuration comments The suggested method for configuration does not work with current kernels. Paths and ids changed. Signed-off-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_hv_generic.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/uio') diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index 48d5327d38d4..4fea9a578990 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -10,11 +10,13 @@ * Since the driver does not declare any device ids, you must allocate * id and bind the device to the driver yourself. For example: * + * Associate Network GUID with UIO device * # echo "f8615163-df3e-46c5-913f-f2d2f965ed0e" \ - * > /sys/bus/vmbus/drivers/uio_hv_generic - * # echo -n vmbus-ed963694-e847-4b2a-85af-bc9cfc11d6f3 \ + * > /sys/bus/vmbus/drivers/uio_hv_generic/new_id + * Then rebind + * # echo -n "ed963694-e847-4b2a-85af-bc9cfc11d6f3" \ * > /sys/bus/vmbus/drivers/hv_netvsc/unbind - * # echo -n vmbus-ed963694-e847-4b2a-85af-bc9cfc11d6f3 \ + * # echo -n "ed963694-e847-4b2a-85af-bc9cfc11d6f3" \ * > /sys/bus/vmbus/drivers/uio_hv_generic/bind */ -- cgit v1.2.3 From 9c40546c012c8d98e88be38c650e66203cb2f1a8 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 4 Jan 2018 14:13:28 -0800 Subject: uio_hv_generic: use standard mmap for resources The generic UIO mmap should work for us. Signed-off-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_hv_generic.c | 33 +++++++-------------------------- 1 file changed, 7 insertions(+), 26 deletions(-) (limited to 'drivers/uio') diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index 4fea9a578990..8d5f529a1dc1 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -56,24 +56,6 @@ struct hv_uio_private_data { struct hv_device *device; }; -static int -hv_uio_mmap(struct uio_info *info, struct vm_area_struct *vma) -{ - int mi; - - if (vma->vm_pgoff >= MAX_UIO_MAPS) - return -EINVAL; - - if (info->mem[vma->vm_pgoff].size == 0) - return -EINVAL; - - mi = (int)vma->vm_pgoff; - - return remap_pfn_range(vma, vma->vm_start, - info->mem[mi].addr >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, vma->vm_page_prot); -} - /* * This is the irqcontrol callback to be registered to uio_info. * It can be used to disable/enable interrupt from user space processes. @@ -133,26 +115,25 @@ hv_uio_probe(struct hv_device *dev, pdata->info.name = "uio_hv_generic"; pdata->info.version = DRIVER_VERSION; pdata->info.irqcontrol = hv_uio_irqcontrol; - pdata->info.mmap = hv_uio_mmap; pdata->info.irq = UIO_IRQ_CUSTOM; /* mem resources */ pdata->info.mem[TXRX_RING_MAP].name = "txrx_rings"; pdata->info.mem[TXRX_RING_MAP].addr - = virt_to_phys(dev->channel->ringbuffer_pages); + = (phys_addr_t)dev->channel->ringbuffer_pages; pdata->info.mem[TXRX_RING_MAP].size - = dev->channel->ringbuffer_pagecount * PAGE_SIZE; + = dev->channel->ringbuffer_pagecount << PAGE_SHIFT; pdata->info.mem[TXRX_RING_MAP].memtype = UIO_MEM_LOGICAL; pdata->info.mem[INT_PAGE_MAP].name = "int_page"; - pdata->info.mem[INT_PAGE_MAP].addr = - virt_to_phys(vmbus_connection.int_page); + pdata->info.mem[INT_PAGE_MAP].addr + = (phys_addr_t)vmbus_connection.int_page; pdata->info.mem[INT_PAGE_MAP].size = PAGE_SIZE; pdata->info.mem[INT_PAGE_MAP].memtype = UIO_MEM_LOGICAL; - pdata->info.mem[MON_PAGE_MAP].name = "monitor_pages"; - pdata->info.mem[MON_PAGE_MAP].addr = - virt_to_phys(vmbus_connection.monitor_pages[1]); + pdata->info.mem[MON_PAGE_MAP].name = "monitor_page"; + pdata->info.mem[MON_PAGE_MAP].addr + = (phys_addr_t)vmbus_connection.monitor_pages[1]; pdata->info.mem[MON_PAGE_MAP].size = PAGE_SIZE; pdata->info.mem[MON_PAGE_MAP].memtype = UIO_MEM_LOGICAL; -- cgit v1.2.3 From 2141a8457f16bac72ef4b4c38885612d1f2232cb Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 4 Jan 2018 14:13:31 -0800 Subject: uio_hv_generic: use ISR callback method The UIO IRQ handler doesn't need to be called from a tasklet. Signed-off-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_hv_generic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/uio') diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index 8d5f529a1dc1..a0c4c07a907f 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -109,7 +109,7 @@ hv_uio_probe(struct hv_device *dev, goto fail; dev->channel->inbound.ring_buffer->interrupt_mask = 1; - set_channel_read_mode(dev->channel, HV_CALL_DIRECT); + set_channel_read_mode(dev->channel, HV_CALL_ISR); /* Fill general uio info */ pdata->info.name = "uio_hv_generic"; -- cgit v1.2.3 From e7d214642a19b8e0e7ecda39184c2ab98ba4801f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 9 Jan 2018 12:57:30 -0800 Subject: uio_hv_generic: create send and receive buffers Map in receive and send buffers for networking in UIO device. These buffers are special and need to be setup by kernel API's; userspace can not do it. Signed-off-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/uio-howto.rst | 2 + drivers/uio/uio_hv_generic.c | 71 +++++++++++++++++++++++++++++++++- 2 files changed, 71 insertions(+), 2 deletions(-) (limited to 'drivers/uio') diff --git a/Documentation/driver-api/uio-howto.rst b/Documentation/driver-api/uio-howto.rst index 968f4c21c733..97e6435b3934 100644 --- a/Documentation/driver-api/uio-howto.rst +++ b/Documentation/driver-api/uio-howto.rst @@ -702,6 +702,8 @@ The vmbus device regions are mapped into uio device resources: 0) Channel ring buffers: guest to host and host to guest 1) Guest to host interrupt signalling pages 2) Guest to host monitor page + 3) Network receive buffer region + 4) Network send buffer region Further information =================== diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index a0c4c07a907f..dcd80aad9636 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -39,6 +39,10 @@ #define DRIVER_AUTHOR "Stephen Hemminger " #define DRIVER_DESC "Generic UIO driver for VMBus devices" +#define HV_RING_SIZE 512 /* pages */ +#define SEND_BUFFER_SIZE (15 * 1024 * 1024) +#define RECV_BUFFER_SIZE (15 * 1024 * 1024) + /* * List of resources to be mapped to user space * can be extended up to MAX_UIO_MAPS(5) items @@ -47,13 +51,21 @@ enum hv_uio_map { TXRX_RING_MAP = 0, INT_PAGE_MAP, MON_PAGE_MAP, + RECV_BUF_MAP, + SEND_BUF_MAP }; -#define HV_RING_SIZE 512 - struct hv_uio_private_data { struct uio_info info; struct hv_device *device; + + void *recv_buf; + u32 recv_gpadl; + char recv_name[32]; /* "recv_4294967295" */ + + void *send_buf; + u32 send_gpadl; + char send_name[32]; }; /* @@ -91,6 +103,19 @@ static void hv_uio_channel_cb(void *context) uio_event_notify(&pdata->info); } + +static void +hv_uio_cleanup(struct hv_device *dev, struct hv_uio_private_data *pdata) +{ + if (pdata->send_gpadl) + vmbus_teardown_gpadl(dev->channel, pdata->send_gpadl); + vfree(pdata->send_buf); + + if (pdata->recv_gpadl) + vmbus_teardown_gpadl(dev->channel, pdata->recv_gpadl); + vfree(pdata->recv_buf); +} + static int hv_uio_probe(struct hv_device *dev, const struct hv_vmbus_device_id *dev_id) @@ -137,6 +162,46 @@ hv_uio_probe(struct hv_device *dev, pdata->info.mem[MON_PAGE_MAP].size = PAGE_SIZE; pdata->info.mem[MON_PAGE_MAP].memtype = UIO_MEM_LOGICAL; + pdata->recv_buf = vzalloc(RECV_BUFFER_SIZE); + if (pdata->recv_buf == NULL) { + ret = -ENOMEM; + goto fail_close; + } + + ret = vmbus_establish_gpadl(dev->channel, pdata->recv_buf, + RECV_BUFFER_SIZE, &pdata->recv_gpadl); + if (ret) + goto fail_close; + + /* put Global Physical Address Label in name */ + snprintf(pdata->recv_name, sizeof(pdata->recv_name), + "recv:%u", pdata->recv_gpadl); + pdata->info.mem[RECV_BUF_MAP].name = pdata->recv_name; + pdata->info.mem[RECV_BUF_MAP].addr + = (phys_addr_t)pdata->recv_buf; + pdata->info.mem[RECV_BUF_MAP].size = RECV_BUFFER_SIZE; + pdata->info.mem[RECV_BUF_MAP].memtype = UIO_MEM_VIRTUAL; + + + pdata->send_buf = vzalloc(SEND_BUFFER_SIZE); + if (pdata->send_buf == NULL) { + ret = -ENOMEM; + goto fail_close; + } + + ret = vmbus_establish_gpadl(dev->channel, pdata->send_buf, + SEND_BUFFER_SIZE, &pdata->send_gpadl); + if (ret) + goto fail_close; + + snprintf(pdata->send_name, sizeof(pdata->send_name), + "send:%u", pdata->send_gpadl); + pdata->info.mem[SEND_BUF_MAP].name = pdata->send_name; + pdata->info.mem[SEND_BUF_MAP].addr + = (phys_addr_t)pdata->send_buf; + pdata->info.mem[SEND_BUF_MAP].size = SEND_BUFFER_SIZE; + pdata->info.mem[SEND_BUF_MAP].memtype = UIO_MEM_VIRTUAL; + pdata->info.priv = pdata; pdata->device = dev; @@ -151,6 +216,7 @@ hv_uio_probe(struct hv_device *dev, return 0; fail_close: + hv_uio_cleanup(dev, pdata); vmbus_close(dev->channel); fail: kfree(pdata); @@ -167,6 +233,7 @@ hv_uio_remove(struct hv_device *dev) return 0; uio_unregister_device(&pdata->info); + hv_uio_cleanup(dev, pdata); hv_set_drvdata(dev, NULL); vmbus_close(dev->channel); kfree(pdata); -- cgit v1.2.3 From 06028d15177a1b406b7b075ea47c6a352732f23a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 9 Jan 2018 12:57:31 -0800 Subject: uio_hv_generic: check that host supports monitor page In order for userspace application to signal host, it needs the host to support the monitor page property. Check for the flag and fail if this is not supported. Signed-off-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_hv_generic.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/uio') diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index dcd80aad9636..ee6d862ef4bd 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -133,6 +133,13 @@ hv_uio_probe(struct hv_device *dev, if (ret) goto fail; + /* Communicating with host has to be via shared memory not hypercall */ + if (!dev->channel->offermsg.monitor_allocated) { + dev_err(&dev->device, "vmbus channel requires hypercall\n"); + ret = -ENOTSUPP; + goto fail_close; + } + dev->channel->inbound.ring_buffer->interrupt_mask = 1; set_channel_read_mode(dev->channel, HV_CALL_ISR); -- cgit v1.2.3 From ca3cda6fcf1e922213a0cc58e708ffb999151db3 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 9 Jan 2018 12:57:32 -0800 Subject: uio_hv_generic: add rescind support When host rescinds the device, the UIO driver will clear the interrupt state and notify application. The read (or write) on the interrupt FD will then fail with -EIO. This is simpler than adding lots extra uevent stuff inside UIO. Signed-off-by: Stephen Hemminger Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/uio-howto.rst | 4 ++++ drivers/uio/uio_hv_generic.c | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+) (limited to 'drivers/uio') diff --git a/Documentation/driver-api/uio-howto.rst b/Documentation/driver-api/uio-howto.rst index 97e6435b3934..693e3bd84e79 100644 --- a/Documentation/driver-api/uio-howto.rst +++ b/Documentation/driver-api/uio-howto.rst @@ -698,6 +698,10 @@ prevents the device from generating further interrupts until the bit is cleared. The userspace driver should clear this bit before blocking and waiting for more interrupts. +When host rescinds a device, the interrupt file descriptor is marked down +and any reads of the interrupt file descriptor will return -EIO. Similar +to a closed socket or disconnected serial device. + The vmbus device regions are mapped into uio device resources: 0) Channel ring buffers: guest to host and host to guest 1) Guest to host interrupt signalling pages diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index ee6d862ef4bd..8c6b04a26c47 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -103,6 +103,23 @@ static void hv_uio_channel_cb(void *context) uio_event_notify(&pdata->info); } +/* + * Callback from vmbus_event when channel is rescinded. + */ +static void hv_uio_rescind(struct vmbus_channel *channel) +{ + struct hv_device *hv_dev = channel->primary_channel->device_obj; + struct hv_uio_private_data *pdata = hv_get_drvdata(hv_dev); + + /* + * Turn off the interrupt file handle + * Next read for event will return -EIO + */ + pdata->info.irq = 0; + + /* Wake up reader */ + uio_event_notify(&pdata->info); +} static void hv_uio_cleanup(struct hv_device *dev, struct hv_uio_private_data *pdata) @@ -218,6 +235,8 @@ hv_uio_probe(struct hv_device *dev, goto fail_close; } + vmbus_set_chn_rescind_callback(dev->channel, hv_uio_rescind); + hv_set_drvdata(dev, pdata); return 0; -- cgit v1.2.3 From 72d1465789506cdc441cb85271d993aee4ae79fe Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 10 Jan 2018 17:42:38 +0100 Subject: uio_hv_generic: fix type mismatch warnings I moved the virt_to_phys() conversion into hv_uio_probe() as part of a warning fix. Stephen's cleanup to remove the private mmap() function seems reasonable, but part of it reverted the change that I did to hide the warnings, so they are back now: drivers/uio/uio_hv_generic.c: In function 'hv_uio_probe': drivers/uio/uio_hv_generic.c:123:5: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast] drivers/uio/uio_hv_generic.c:130:5: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast] drivers/uio/uio_hv_generic.c:136:5: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast] The type mismatch is now the result of the uio_mmap() definition, and the best way I see from here is to shut them up with a uintptr_t cast. Fixes: 9c40546c012c ("uio_hv_generic: use standard mmap for resources") Signed-off-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio_hv_generic.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/uio') diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c index 8c6b04a26c47..787598ad933d 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -169,20 +169,20 @@ hv_uio_probe(struct hv_device *dev, /* mem resources */ pdata->info.mem[TXRX_RING_MAP].name = "txrx_rings"; pdata->info.mem[TXRX_RING_MAP].addr - = (phys_addr_t)dev->channel->ringbuffer_pages; + = (uintptr_t)dev->channel->ringbuffer_pages; pdata->info.mem[TXRX_RING_MAP].size = dev->channel->ringbuffer_pagecount << PAGE_SHIFT; pdata->info.mem[TXRX_RING_MAP].memtype = UIO_MEM_LOGICAL; pdata->info.mem[INT_PAGE_MAP].name = "int_page"; pdata->info.mem[INT_PAGE_MAP].addr - = (phys_addr_t)vmbus_connection.int_page; + = (uintptr_t)vmbus_connection.int_page; pdata->info.mem[INT_PAGE_MAP].size = PAGE_SIZE; pdata->info.mem[INT_PAGE_MAP].memtype = UIO_MEM_LOGICAL; pdata->info.mem[MON_PAGE_MAP].name = "monitor_page"; pdata->info.mem[MON_PAGE_MAP].addr - = (phys_addr_t)vmbus_connection.monitor_pages[1]; + = (uintptr_t)vmbus_connection.monitor_pages[1]; pdata->info.mem[MON_PAGE_MAP].size = PAGE_SIZE; pdata->info.mem[MON_PAGE_MAP].memtype = UIO_MEM_LOGICAL; -- cgit v1.2.3 From d6088e9a89f7c6fe9720978196c4d9799fd16c29 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 12 Jan 2018 16:51:14 +0100 Subject: uio_hv_generic: fix new type mismatch warnings In commit 72d146578950 ("uio_hv_generic: fix type mismatch warnings"), I addressed some warnings that show up with CONFIG_X86_PAE, now a new change has added more of the same: drivers/uio/uio_hv_generic.c: In function 'hv_uio_probe': drivers/uio/uio_hv_generic.c:205:5: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast] drivers/uio/uio_hv_generic.c:225:5: error: cast from pointer to integer of different size [-Werror=pointer-to-int-cast] The fix is the same as before, casting to uintptr_t as an intermediate. Fixes: e7d214642a19 ("uio_hv_generic: create send and receive buffers") Signed-off-by: Arnd Bergmann Cc: 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 787598ad933d..8ca549032c27 100644 --- a/drivers/uio/uio_hv_generic.c +++ b/drivers/uio/uio_hv_generic.c @@ -202,7 +202,7 @@ hv_uio_probe(struct hv_device *dev, "recv:%u", pdata->recv_gpadl); pdata->info.mem[RECV_BUF_MAP].name = pdata->recv_name; pdata->info.mem[RECV_BUF_MAP].addr - = (phys_addr_t)pdata->recv_buf; + = (uintptr_t)pdata->recv_buf; pdata->info.mem[RECV_BUF_MAP].size = RECV_BUFFER_SIZE; pdata->info.mem[RECV_BUF_MAP].memtype = UIO_MEM_VIRTUAL; @@ -222,7 +222,7 @@ hv_uio_probe(struct hv_device *dev, "send:%u", pdata->send_gpadl); pdata->info.mem[SEND_BUF_MAP].name = pdata->send_name; pdata->info.mem[SEND_BUF_MAP].addr - = (phys_addr_t)pdata->send_buf; + = (uintptr_t)pdata->send_buf; pdata->info.mem[SEND_BUF_MAP].size = SEND_BUFFER_SIZE; pdata->info.mem[SEND_BUF_MAP].memtype = UIO_MEM_VIRTUAL; -- cgit v1.2.3