diff options
author | Stephen Hemminger <stephen@networkplumber.org> | 2018-01-09 12:57:30 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2018-01-10 17:40:53 +0100 |
commit | e7d214642a19b8e0e7ecda39184c2ab98ba4801f (patch) | |
tree | 7f102f87fb2580d8159ff7d05a5f55882450cb38 | |
parent | c5702d1b31085ccda7f46e514a51c6c8db54cdc4 (diff) |
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 <sthemmin@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | Documentation/driver-api/uio-howto.rst | 2 | ||||
-rw-r--r-- | drivers/uio/uio_hv_generic.c | 71 |
2 files changed, 71 insertions, 2 deletions
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 <sthemmin at microsoft.com>" #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); |