[v5,03/14] bus/vmbus: move OS independent UIO functions

Message ID 20220423042849.7718-4-srikanth.k@oneconvergence.com (mailing list archive)
State Awaiting Upstream
Delegated to: Thomas Monjalon
Headers
Series add FreeBSD support to VMBUS & NetVSC PMDs |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Srikanth Kaka April 23, 2022, 4:28 a.m. UTC
  Moved all Linux independent UIO functions to unix dir.
Split the vmbus_uio_map_subchan() by keeping OS dependent
code in vmbus_uio_map_subchan_os() function

Signed-off-by: Srikanth Kaka <srikanth.k@oneconvergence.com>
Signed-off-by: Vag Singh <vag.singh@oneconvergence.com>
Signed-off-by: Anand Thulasiram <avelu@juniper.net>
---
 drivers/bus/vmbus/linux/vmbus_uio.c     | 292 ++----------------------------
 drivers/bus/vmbus/meson.build           |   3 +-
 drivers/bus/vmbus/unix/vmbus_unix.h     |  12 ++
 drivers/bus/vmbus/unix/vmbus_unix_uio.c | 306 ++++++++++++++++++++++++++++++++
 4 files changed, 330 insertions(+), 283 deletions(-)
 create mode 100644 drivers/bus/vmbus/unix/vmbus_unix_uio.c
  

Patch

diff --git a/drivers/bus/vmbus/linux/vmbus_uio.c b/drivers/bus/vmbus/linux/vmbus_uio.c
index 5db70f8..b5d15c9 100644
--- a/drivers/bus/vmbus/linux/vmbus_uio.c
+++ b/drivers/bus/vmbus/linux/vmbus_uio.c
@@ -21,233 +21,18 @@ 
 #include <rte_string_fns.h>
 
 #include "private.h"
+#include "vmbus_unix.h"
 
 /** Pathname of VMBUS devices directory. */
 #define SYSFS_VMBUS_DEVICES "/sys/bus/vmbus/devices"
 
-static void *vmbus_map_addr;
-
-/* Control interrupts */
-void vmbus_uio_irq_control(struct rte_vmbus_device *dev, int32_t onoff)
-{
-	if ((rte_intr_fd_get(dev->intr_handle) < 0) ||
-	    write(rte_intr_fd_get(dev->intr_handle), &onoff,
-		  sizeof(onoff)) < 0) {
-		VMBUS_LOG(ERR, "cannot write to %d:%s",
-			  rte_intr_fd_get(dev->intr_handle),
-			  strerror(errno));
-	}
-}
-
-int vmbus_uio_irq_read(struct rte_vmbus_device *dev)
-{
-	int32_t count;
-	int cc;
-
-	if (rte_intr_fd_get(dev->intr_handle) < 0)
-		return -1;
-
-	cc = read(rte_intr_fd_get(dev->intr_handle), &count,
-		  sizeof(count));
-	if (cc < (int)sizeof(count)) {
-		if (cc < 0) {
-			VMBUS_LOG(ERR, "IRQ read failed %s",
-				  strerror(errno));
-			return -errno;
-		}
-		VMBUS_LOG(ERR, "can't read IRQ count");
-		return -EINVAL;
-	}
-
-	return count;
-}
-
-void
-vmbus_uio_free_resource(struct rte_vmbus_device *dev,
-		struct mapped_vmbus_resource *uio_res)
-{
-	rte_free(uio_res);
-
-	if (rte_intr_dev_fd_get(dev->intr_handle) >= 0) {
-		close(rte_intr_dev_fd_get(dev->intr_handle));
-		rte_intr_dev_fd_set(dev->intr_handle, -1);
-	}
-
-	if (rte_intr_fd_get(dev->intr_handle) >= 0) {
-		close(rte_intr_fd_get(dev->intr_handle));
-		rte_intr_fd_set(dev->intr_handle, -1);
-		rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UNKNOWN);
-	}
-}
-
-int
-vmbus_uio_alloc_resource(struct rte_vmbus_device *dev,
-			 struct mapped_vmbus_resource **uio_res)
-{
-	char devname[PATH_MAX]; /* contains the /dev/uioX */
-	int fd;
-
-	/* save fd if in primary process */
-	snprintf(devname, sizeof(devname), "/dev/uio%u", dev->uio_num);
-	fd = open(devname, O_RDWR);
-	if (fd < 0) {
-		VMBUS_LOG(ERR, "Cannot open %s: %s",
-			devname, strerror(errno));
-		goto error;
-	}
-
-	if (rte_intr_fd_set(dev->intr_handle, fd))
-		goto error;
-
-	if (rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UIO_INTX))
-		goto error;
-
-	/* allocate the mapping details for secondary processes*/
-	*uio_res = rte_zmalloc("UIO_RES", sizeof(**uio_res), 0);
-	if (*uio_res == NULL) {
-		VMBUS_LOG(ERR, "cannot store uio mmap details");
-		goto error;
-	}
-
-	strlcpy((*uio_res)->path, devname, PATH_MAX);
-	rte_uuid_copy((*uio_res)->id, dev->device_id);
-
-	return 0;
-
-error:
-	vmbus_uio_free_resource(dev, *uio_res);
-	return -1;
-}
-
-static int
-find_max_end_va(const struct rte_memseg_list *msl, void *arg)
-{
-	size_t sz = msl->memseg_arr.len * msl->page_sz;
-	void *end_va = RTE_PTR_ADD(msl->base_va, sz);
-	void **max_va = arg;
-
-	if (*max_va < end_va)
-		*max_va = end_va;
-	return 0;
-}
-
-/*
- * TODO: this should be part of memseg api.
- *       code is duplicated from PCI.
- */
-static void *
-vmbus_find_max_end_va(void)
-{
-	void *va = NULL;
-
-	rte_memseg_list_walk(find_max_end_va, &va);
-	return va;
-}
-
-int
-vmbus_uio_map_resource_by_index(struct rte_vmbus_device *dev, int idx,
-				struct mapped_vmbus_resource *uio_res,
-				int flags)
-{
-	size_t size = dev->resource[idx].len;
-	struct vmbus_map *maps = uio_res->maps;
-	void *mapaddr;
-	off_t offset;
-	int fd;
-
-	/* devname for mmap  */
-	fd = open(uio_res->path, O_RDWR);
-	if (fd < 0) {
-		VMBUS_LOG(ERR, "Cannot open %s: %s",
-			  uio_res->path, strerror(errno));
-		return -1;
-	}
-
-	/* try mapping somewhere close to the end of hugepages */
-	if (vmbus_map_addr == NULL)
-		vmbus_map_addr = vmbus_find_max_end_va();
-
-	/* offset is special in uio it indicates which resource */
-	offset = idx * rte_mem_page_size();
-
-	mapaddr = vmbus_map_resource(vmbus_map_addr, fd, offset, size, flags);
-	close(fd);
-
-	if (mapaddr == MAP_FAILED)
-		return -1;
-
-	dev->resource[idx].addr = mapaddr;
-	vmbus_map_addr = RTE_PTR_ADD(mapaddr, size);
-
-	/* Record result of successful mapping for use by secondary */
-	maps[idx].addr = mapaddr;
-	maps[idx].size = size;
-
-	return 0;
-}
-
-static int vmbus_uio_map_primary(struct vmbus_channel *chan,
-				 void **ring_buf, uint32_t *ring_size)
-{
-	struct mapped_vmbus_resource *uio_res;
-
-	uio_res = vmbus_uio_find_resource(chan->device);
-	if (!uio_res) {
-		VMBUS_LOG(ERR, "can not find resources!");
-		return -ENOMEM;
-	}
-
-	if (uio_res->nb_maps < VMBUS_MAX_RESOURCE) {
-		VMBUS_LOG(ERR, "VMBUS: only %u resources found!",
-			  uio_res->nb_maps);
-		return -EINVAL;
-	}
-
-	*ring_size = uio_res->maps[HV_TXRX_RING_MAP].size / 2;
-	*ring_buf  = uio_res->maps[HV_TXRX_RING_MAP].addr;
-	return 0;
-}
-
-static int vmbus_uio_map_subchan(const struct rte_vmbus_device *dev,
-				 const struct vmbus_channel *chan,
-				 void **ring_buf, uint32_t *ring_size)
+int vmbus_uio_map_subchan_os(const struct rte_vmbus_device *dev,
+			     const struct vmbus_channel *chan,
+			     void **mapaddr, size_t *file_size)
 {
 	char ring_path[PATH_MAX];
-	size_t file_size;
 	struct stat sb;
-	void *mapaddr;
 	int fd;
-	struct mapped_vmbus_resource *uio_res;
-	int channel_idx;
-
-	uio_res = vmbus_uio_find_resource(dev);
-	if (!uio_res) {
-		VMBUS_LOG(ERR, "can not find resources for mapping subchan");
-		return -ENOMEM;
-	}
-
-	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
-		if (uio_res->nb_subchannels >= UIO_MAX_SUBCHANNEL) {
-			VMBUS_LOG(ERR,
-				"exceeding max subchannels UIO_MAX_SUBCHANNEL(%d)",
-				UIO_MAX_SUBCHANNEL);
-			VMBUS_LOG(ERR, "Change UIO_MAX_SUBCHANNEL and recompile");
-			return -ENOMEM;
-		}
-	} else {
-		for (channel_idx = 0; channel_idx < uio_res->nb_subchannels;
-		     channel_idx++)
-			if (uio_res->subchannel_maps[channel_idx].relid ==
-					chan->relid)
-				break;
-		if (channel_idx == uio_res->nb_subchannels) {
-			VMBUS_LOG(ERR,
-				"couldn't find sub channel %d from shared mapping in primary",
-				chan->relid);
-			return -ENOMEM;
-		}
-		vmbus_map_addr = uio_res->subchannel_maps[channel_idx].addr;
-	}
 
 	snprintf(ring_path, sizeof(ring_path),
 		 "%s/%s/channels/%u/ring",
@@ -267,68 +52,23 @@  static int vmbus_uio_map_subchan(const struct rte_vmbus_device *dev,
 		close(fd);
 		return -errno;
 	}
-	file_size = sb.st_size;
+	*file_size = sb.st_size;
 
-	if (file_size == 0 || (file_size & (rte_mem_page_size() - 1))) {
+	if (*file_size == 0 || (*file_size & (rte_mem_page_size() - 1))) {
 		VMBUS_LOG(ERR, "incorrect size %s: %zu",
-			  ring_path, file_size);
+			  ring_path, *file_size);
 
 		close(fd);
 		return -EINVAL;
 	}
 
-	mapaddr = vmbus_map_resource(vmbus_map_addr, fd,
-				     0, file_size, 0);
+	*mapaddr = vmbus_map_resource(vmbus_map_addr, fd,
+				     0, *file_size, 0);
 	close(fd);
 
-	if (mapaddr == MAP_FAILED)
+	if (*mapaddr == MAP_FAILED)
 		return -EIO;
 
-	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
-
-		/* Add this mapping to uio_res for use by secondary */
-		uio_res->subchannel_maps[uio_res->nb_subchannels].relid =
-			chan->relid;
-		uio_res->subchannel_maps[uio_res->nb_subchannels].addr =
-			mapaddr;
-		uio_res->subchannel_maps[uio_res->nb_subchannels].size =
-			file_size;
-		uio_res->nb_subchannels++;
-
-		vmbus_map_addr = RTE_PTR_ADD(mapaddr, file_size);
-	} else {
-		if (mapaddr != vmbus_map_addr) {
-			VMBUS_LOG(ERR, "failed to map channel %d to addr %p",
-					chan->relid, mapaddr);
-			vmbus_unmap_resource(mapaddr, file_size);
-			return -EIO;
-		}
-	}
-
-	*ring_size = file_size / 2;
-	*ring_buf = mapaddr;
-
-	return 0;
-}
-
-int vmbus_uio_map_rings(struct vmbus_channel *chan)
-{
-	const struct rte_vmbus_device *dev = chan->device;
-	uint32_t ring_size;
-	void *ring_buf;
-	int ret;
-
-	/* Primary channel */
-	if (chan->subchannel_id == 0)
-		ret = vmbus_uio_map_primary(chan, &ring_buf, &ring_size);
-	else
-		ret = vmbus_uio_map_subchan(dev, chan, &ring_buf, &ring_size);
-
-	if (ret)
-		return ret;
-
-	vmbus_br_setup(&chan->txbr, ring_buf, ring_size);
-	vmbus_br_setup(&chan->rxbr, (char *)ring_buf + ring_size, ring_size);
 	return 0;
 }
 
@@ -377,18 +117,6 @@  bool vmbus_uio_subchannels_supported(const struct rte_vmbus_device *dev,
 	return vmbus_uio_ring_present(dev, chan->relid);
 }
 
-static bool vmbus_isnew_subchannel(struct vmbus_channel *primary,
-				   unsigned long id)
-{
-	const struct vmbus_channel *c;
-
-	STAILQ_FOREACH(c, &primary->subchannel_list, next) {
-		if (c->relid == id)
-			return false;
-	}
-	return true;
-}
-
 int vmbus_uio_get_subchan(struct vmbus_channel *primary,
 			  struct vmbus_channel **subchan)
 {
diff --git a/drivers/bus/vmbus/meson.build b/drivers/bus/vmbus/meson.build
index 01ef01f..60913d0 100644
--- a/drivers/bus/vmbus/meson.build
+++ b/drivers/bus/vmbus/meson.build
@@ -18,7 +18,8 @@  sources = files(
 
 includes += include_directories('unix')
 sources += files(
-	'unix/vmbus_unix_bus.c'
+	'unix/vmbus_unix_bus.c',
+	'unix/vmbus_unix_uio.c'
 )
 
 if is_linux
diff --git a/drivers/bus/vmbus/unix/vmbus_unix.h b/drivers/bus/vmbus/unix/vmbus_unix.h
index 2db9399..579c4bb 100644
--- a/drivers/bus/vmbus/unix/vmbus_unix.h
+++ b/drivers/bus/vmbus/unix/vmbus_unix.h
@@ -6,6 +6,18 @@ 
 #ifndef _VMBUS_BUS_UNIX_H_
 #define _VMBUS_BUS_UNIX_H_
 
+#include <rte_bus_vmbus.h>
+
+#include "private.h"
+
 extern const rte_uuid_t vmbus_nic_uuid;
+extern void *vmbus_map_addr;
+
+int vmbus_uio_map_subchan_os(const struct rte_vmbus_device *dev,
+			     const struct vmbus_channel *chan,
+			     void **mapaddr, size_t *file_size);
+
+bool vmbus_isnew_subchannel(struct vmbus_channel *primary,
+			    unsigned long id);
 
 #endif /* _VMBUS_BUS_UNIX_H_ */
diff --git a/drivers/bus/vmbus/unix/vmbus_unix_uio.c b/drivers/bus/vmbus/unix/vmbus_unix_uio.c
new file mode 100644
index 0000000..c5ce8ca
--- /dev/null
+++ b/drivers/bus/vmbus/unix/vmbus_unix_uio.c
@@ -0,0 +1,306 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2018, Microsoft Corporation.
+ * All Rights Reserved.
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include <rte_eal.h>
+#include <rte_log.h>
+#include <rte_bus.h>
+#include <rte_memory.h>
+#include <rte_common.h>
+#include <rte_malloc.h>
+#include <rte_bus_vmbus.h>
+#include <rte_string_fns.h>
+
+#include "private.h"
+#include "vmbus_unix.h"
+
+void *vmbus_map_addr;
+
+/* Control interrupts */
+void vmbus_uio_irq_control(struct rte_vmbus_device *dev, int32_t onoff)
+{
+	if ((rte_intr_fd_get(dev->intr_handle) < 0) ||
+	    write(rte_intr_fd_get(dev->intr_handle), &onoff,
+		  sizeof(onoff)) < 0) {
+		VMBUS_LOG(ERR, "cannot write to %d:%s",
+			  rte_intr_fd_get(dev->intr_handle),
+			  strerror(errno));
+	}
+}
+
+int vmbus_uio_irq_read(struct rte_vmbus_device *dev)
+{
+	int32_t count;
+	int cc;
+
+	if (rte_intr_fd_get(dev->intr_handle) < 0)
+		return -1;
+
+	cc = read(rte_intr_fd_get(dev->intr_handle), &count,
+		  sizeof(count));
+	if (cc < (int)sizeof(count)) {
+		if (cc < 0) {
+			VMBUS_LOG(ERR, "IRQ read failed %s",
+				  strerror(errno));
+			return -errno;
+		}
+		VMBUS_LOG(ERR, "can't read IRQ count");
+		return -EINVAL;
+	}
+
+	return count;
+}
+
+void
+vmbus_uio_free_resource(struct rte_vmbus_device *dev,
+		struct mapped_vmbus_resource *uio_res)
+{
+	rte_free(uio_res);
+
+	if (rte_intr_dev_fd_get(dev->intr_handle) >= 0) {
+		close(rte_intr_dev_fd_get(dev->intr_handle));
+		rte_intr_dev_fd_set(dev->intr_handle, -1);
+	}
+
+	if (rte_intr_fd_get(dev->intr_handle) >= 0) {
+		close(rte_intr_fd_get(dev->intr_handle));
+		rte_intr_fd_set(dev->intr_handle, -1);
+		rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UNKNOWN);
+	}
+}
+
+int
+vmbus_uio_alloc_resource(struct rte_vmbus_device *dev,
+			 struct mapped_vmbus_resource **uio_res)
+{
+	char devname[PATH_MAX]; /* contains the /dev/uioX */
+	int fd;
+
+	/* save fd if in primary process */
+	snprintf(devname, sizeof(devname), "/dev/uio%u", dev->uio_num);
+	fd = open(devname, O_RDWR);
+	if (fd < 0) {
+		VMBUS_LOG(ERR, "Cannot open %s: %s",
+			devname, strerror(errno));
+		goto error;
+	}
+
+	if (rte_intr_fd_set(dev->intr_handle, fd))
+		goto error;
+
+	if (rte_intr_type_set(dev->intr_handle, RTE_INTR_HANDLE_UIO_INTX))
+		goto error;
+
+	/* allocate the mapping details for secondary processes*/
+	*uio_res = rte_zmalloc("UIO_RES", sizeof(**uio_res), 0);
+	if (*uio_res == NULL) {
+		VMBUS_LOG(ERR, "cannot store uio mmap details");
+		goto error;
+	}
+
+	strlcpy((*uio_res)->path, devname, PATH_MAX);
+	rte_uuid_copy((*uio_res)->id, dev->device_id);
+
+	return 0;
+
+error:
+	vmbus_uio_free_resource(dev, *uio_res);
+	return -1;
+}
+
+static int
+find_max_end_va(const struct rte_memseg_list *msl, void *arg)
+{
+	size_t sz = msl->memseg_arr.len * msl->page_sz;
+	void *end_va = RTE_PTR_ADD(msl->base_va, sz);
+	void **max_va = arg;
+
+	if (*max_va < end_va)
+		*max_va = end_va;
+	return 0;
+}
+
+/*
+ * TODO: this should be part of memseg api.
+ *       code is duplicated from PCI.
+ */
+static void *
+vmbus_find_max_end_va(void)
+{
+	void *va = NULL;
+
+	rte_memseg_list_walk(find_max_end_va, &va);
+	return va;
+}
+
+int
+vmbus_uio_map_resource_by_index(struct rte_vmbus_device *dev, int idx,
+				struct mapped_vmbus_resource *uio_res,
+				int flags)
+{
+	size_t size = dev->resource[idx].len;
+	struct vmbus_map *maps = uio_res->maps;
+	void *mapaddr;
+	off_t offset;
+	int fd;
+
+	/* devname for mmap  */
+	fd = open(uio_res->path, O_RDWR);
+	if (fd < 0) {
+		VMBUS_LOG(ERR, "Cannot open %s: %s",
+			  uio_res->path, strerror(errno));
+		return -1;
+	}
+
+	/* try mapping somewhere close to the end of hugepages */
+	if (vmbus_map_addr == NULL)
+		vmbus_map_addr = vmbus_find_max_end_va();
+
+	/* offset is special in uio it indicates which resource */
+	offset = idx * rte_mem_page_size();
+
+	mapaddr = vmbus_map_resource(vmbus_map_addr, fd, offset, size, flags);
+	close(fd);
+
+	if (mapaddr == MAP_FAILED)
+		return -1;
+
+	dev->resource[idx].addr = mapaddr;
+	vmbus_map_addr = RTE_PTR_ADD(mapaddr, size);
+
+	/* Record result of successful mapping for use by secondary */
+	maps[idx].addr = mapaddr;
+	maps[idx].size = size;
+
+	return 0;
+}
+
+static int vmbus_uio_map_primary(struct vmbus_channel *chan,
+				 void **ring_buf, uint32_t *ring_size)
+{
+	struct mapped_vmbus_resource *uio_res;
+
+	uio_res = vmbus_uio_find_resource(chan->device);
+	if (!uio_res) {
+		VMBUS_LOG(ERR, "can not find resources!");
+		return -ENOMEM;
+	}
+
+	if (uio_res->nb_maps < VMBUS_MAX_RESOURCE) {
+		VMBUS_LOG(ERR, "VMBUS: only %u resources found!",
+			  uio_res->nb_maps);
+		return -EINVAL;
+	}
+
+	*ring_size = uio_res->maps[HV_TXRX_RING_MAP].size / 2;
+	*ring_buf  = uio_res->maps[HV_TXRX_RING_MAP].addr;
+	return 0;
+}
+
+static int vmbus_uio_map_subchan(const struct rte_vmbus_device *dev,
+				 const struct vmbus_channel *chan,
+				 void **ring_buf, uint32_t *ring_size)
+{
+	size_t file_size = 0;
+	void *mapaddr = NULL;
+	struct mapped_vmbus_resource *uio_res;
+	int channel_idx;
+	int ret;
+
+	uio_res = vmbus_uio_find_resource(dev);
+	if (!uio_res) {
+		VMBUS_LOG(ERR, "can not find resources for mapping subchan");
+		return -ENOMEM;
+	}
+
+	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+		if (uio_res->nb_subchannels >= UIO_MAX_SUBCHANNEL) {
+			VMBUS_LOG(ERR,
+				"exceeding max subchannels UIO_MAX_SUBCHANNEL(%d)",
+				UIO_MAX_SUBCHANNEL);
+			VMBUS_LOG(ERR, "Change UIO_MAX_SUBCHANNEL and recompile");
+			return -ENOMEM;
+		}
+	} else {
+		for (channel_idx = 0; channel_idx < uio_res->nb_subchannels;
+		     channel_idx++)
+			if (uio_res->subchannel_maps[channel_idx].relid ==
+					chan->relid)
+				break;
+		if (channel_idx == uio_res->nb_subchannels) {
+			VMBUS_LOG(ERR,
+				"couldn't find sub channel %d from shared mapping in primary",
+				chan->relid);
+			return -ENOMEM;
+		}
+		vmbus_map_addr = uio_res->subchannel_maps[channel_idx].addr;
+	}
+
+	ret = vmbus_uio_map_subchan_os(dev, chan, &mapaddr, &file_size);
+	if (ret)
+		return ret;
+
+	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+
+		/* Add this mapping to uio_res for use by secondary */
+		uio_res->subchannel_maps[uio_res->nb_subchannels].relid =
+			chan->relid;
+		uio_res->subchannel_maps[uio_res->nb_subchannels].addr =
+			mapaddr;
+		uio_res->subchannel_maps[uio_res->nb_subchannels].size =
+			file_size;
+		uio_res->nb_subchannels++;
+
+		vmbus_map_addr = RTE_PTR_ADD(mapaddr, file_size);
+	} else {
+		if (mapaddr != vmbus_map_addr) {
+			VMBUS_LOG(ERR, "failed to map channel %d to addr %p",
+					chan->relid, mapaddr);
+			vmbus_unmap_resource(mapaddr, file_size);
+			return -EIO;
+		}
+	}
+
+	*ring_size = file_size / 2;
+	*ring_buf = mapaddr;
+
+	return 0;
+}
+
+int vmbus_uio_map_rings(struct vmbus_channel *chan)
+{
+	const struct rte_vmbus_device *dev = chan->device;
+	uint32_t ring_size = 0;
+	void *ring_buf = NULL;
+	int ret;
+
+	/* Primary channel */
+	if (chan->subchannel_id == 0)
+		ret = vmbus_uio_map_primary(chan, &ring_buf, &ring_size);
+	else
+		ret = vmbus_uio_map_subchan(dev, chan, &ring_buf, &ring_size);
+
+	if (ret)
+		return ret;
+
+	vmbus_br_setup(&chan->txbr, ring_buf, ring_size);
+	vmbus_br_setup(&chan->rxbr, (char *)ring_buf + ring_size, ring_size);
+	return 0;
+}
+
+bool vmbus_isnew_subchannel(struct vmbus_channel *primary,
+			    unsigned long id)
+{
+	const struct vmbus_channel *c;
+
+	STAILQ_FOREACH(c, &primary->subchannel_list, next) {
+		if (c->relid == id)
+			return false;
+	}
+	return true;
+}