Эх сурвалжийг харах

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>
Stephen Hemminger 7 жил өмнө
parent
commit
e7d214642a

+ 2 - 0
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
     0) Channel ring buffers: guest to host and host to guest
     1) Guest to host interrupt signalling pages
     1) Guest to host interrupt signalling pages
     2) Guest to host monitor page
     2) Guest to host monitor page
+    3) Network receive buffer region
+    4) Network send buffer region
 
 
 Further information
 Further information
 ===================
 ===================

+ 69 - 2
drivers/uio/uio_hv_generic.c

@@ -39,6 +39,10 @@
 #define DRIVER_AUTHOR	"Stephen Hemminger <sthemmin at microsoft.com>"
 #define DRIVER_AUTHOR	"Stephen Hemminger <sthemmin at microsoft.com>"
 #define DRIVER_DESC	"Generic UIO driver for VMBus devices"
 #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
  * List of resources to be mapped to user space
  * can be extended up to MAX_UIO_MAPS(5) items
  * can be extended up to MAX_UIO_MAPS(5) items
@@ -47,13 +51,21 @@ enum hv_uio_map {
 	TXRX_RING_MAP = 0,
 	TXRX_RING_MAP = 0,
 	INT_PAGE_MAP,
 	INT_PAGE_MAP,
 	MON_PAGE_MAP,
 	MON_PAGE_MAP,
+	RECV_BUF_MAP,
+	SEND_BUF_MAP
 };
 };
 
 
-#define HV_RING_SIZE	512
-
 struct hv_uio_private_data {
 struct hv_uio_private_data {
 	struct uio_info info;
 	struct uio_info info;
 	struct hv_device *device;
 	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);
 	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
 static int
 hv_uio_probe(struct hv_device *dev,
 hv_uio_probe(struct hv_device *dev,
 	     const struct hv_vmbus_device_id *dev_id)
 	     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].size = PAGE_SIZE;
 	pdata->info.mem[MON_PAGE_MAP].memtype = UIO_MEM_LOGICAL;
 	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->info.priv = pdata;
 	pdata->device = dev;
 	pdata->device = dev;
 
 
@@ -151,6 +216,7 @@ hv_uio_probe(struct hv_device *dev,
 	return 0;
 	return 0;
 
 
 fail_close:
 fail_close:
+	hv_uio_cleanup(dev, pdata);
 	vmbus_close(dev->channel);
 	vmbus_close(dev->channel);
 fail:
 fail:
 	kfree(pdata);
 	kfree(pdata);
@@ -167,6 +233,7 @@ hv_uio_remove(struct hv_device *dev)
 		return 0;
 		return 0;
 
 
 	uio_unregister_device(&pdata->info);
 	uio_unregister_device(&pdata->info);
+	hv_uio_cleanup(dev, pdata);
 	hv_set_drvdata(dev, NULL);
 	hv_set_drvdata(dev, NULL);
 	vmbus_close(dev->channel);
 	vmbus_close(dev->channel);
 	kfree(pdata);
 	kfree(pdata);