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>
This commit is contained in:
Stephen Hemminger 2018-01-09 12:57:30 -08:00 committed by Greg Kroah-Hartman
parent c5702d1b31
commit e7d214642a
2 changed files with 71 additions and 2 deletions

View File

@ -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
===================

View File

@ -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);