diff options
Diffstat (limited to 'drivers/uio/uio_hv_generic.c')
-rw-r--r-- | drivers/uio/uio_hv_generic.c | 71 |
1 files changed, 69 insertions, 2 deletions
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); |