All of lore.kernel.org
 help / color / mirror / Atom feed
From: Oleksandr Andrushchenko <andr2000@gmail.com>
To: Dongwon Kim <dongwon.kim@intel.com>,
	linux-kernel@vger.kernel.org, linaro-mm-sig@lists.linaro.org,
	xen-devel@lists.xenproject.org
Cc: dri-devel@lists.freedesktop.org, mateuszx.potrola@intel.com
Subject: Re: [RFC,v2,5/9] hyper_dmabuf: default backend for XEN hypervisor
Date: Tue, 10 Apr 2018 12:27:32 +0300	[thread overview]
Message-ID: <590a9e6f-1e04-c832-5fd4-107af94d1ef7@gmail.com> (raw)
In-Reply-To: <20180214015008.9513-6-dongwon.kim@intel.com>

On 02/14/2018 03:50 AM, Dongwon Kim wrote:
> From: "Matuesz Polrola" <mateuszx.potrola@intel.com>
>
> The default backend for XEN hypervisor. This backend contains actual
> implementation of individual methods defined in "struct hyper_dmabuf_bknd_ops"
> defined as:
>
> struct hyper_dmabuf_bknd_ops {
>          /* backend initialization routine (optional) */
>          int (*init)(void);
>
>          /* backend cleanup routine (optional) */
>          int (*cleanup)(void);
>
>          /* retreiving id of current virtual machine */
>          int (*get_vm_id)(void);
>
>          /* get pages shared via hypervisor-specific method */
>          int (*share_pages)(struct page **, int, int, void **);
>
>          /* make shared pages unshared via hypervisor specific method */
>          int (*unshare_pages)(void **, int);
>
>          /* map remotely shared pages on importer's side via
>           * hypervisor-specific method
>           */
>          struct page ** (*map_shared_pages)(unsigned long, int, int, void **);
>
>          /* unmap and free shared pages on importer's side via
>           * hypervisor-specific method
>           */
>          int (*unmap_shared_pages)(void **, int);
>
>          /* initialize communication environment */
>          int (*init_comm_env)(void);
>
>          void (*destroy_comm)(void);
>
>          /* upstream ch setup (receiving and responding) */
>          int (*init_rx_ch)(int);
>
>          /* downstream ch setup (transmitting and parsing responses) */
>          int (*init_tx_ch)(int);
>
>          int (*send_req)(int, struct hyper_dmabuf_req *, int);
> };
>
> First two methods are for extra initialization or cleaning up possibly
> required for the current Hypervisor (optional). Third method
> (.get_vm_id) provides a way to get current VM's id, which will be used
> as an identication of source VM of shared hyper_DMABUF later.
>
> All other methods are related to either memory sharing or inter-VM
> communication, which are minimum requirement for hyper_DMABUF driver.
> (Brief description of role of each method is embedded as a comment in the
> definition of the structure above and header file.)
>
> Actual implementation of each of these methods specific to XEN is under
> backends/xen/. Their mappings are done as followed:
>
> struct hyper_dmabuf_bknd_ops xen_bknd_ops = {
>          .init = NULL, /* not needed for xen */
>          .cleanup = NULL, /* not needed for xen */
>          .get_vm_id = xen_be_get_domid,
>          .share_pages = xen_be_share_pages,
>          .unshare_pages = xen_be_unshare_pages,
>          .map_shared_pages = (void *)xen_be_map_shared_pages,
>          .unmap_shared_pages = xen_be_unmap_shared_pages,
>          .init_comm_env = xen_be_init_comm_env,
>          .destroy_comm = xen_be_destroy_comm,
>          .init_rx_ch = xen_be_init_rx_rbuf,
>          .init_tx_ch = xen_be_init_tx_rbuf,
>          .send_req = xen_be_send_req,
> };
>
> A section for Hypervisor Backend has been added to
>
> "Documentation/hyper-dmabuf-sharing.txt" accordingly
>
> Signed-off-by: Dongwon Kim <dongwon.kim@intel.com>
> Signed-off-by: Mateusz Polrola <mateuszx.potrola@intel.com>
> ---
>   drivers/dma-buf/hyper_dmabuf/Kconfig               |   7 +
>   drivers/dma-buf/hyper_dmabuf/Makefile              |   7 +
>   .../backends/xen/hyper_dmabuf_xen_comm.c           | 941 +++++++++++++++++++++
>   .../backends/xen/hyper_dmabuf_xen_comm.h           |  78 ++
>   .../backends/xen/hyper_dmabuf_xen_comm_list.c      | 158 ++++
>   .../backends/xen/hyper_dmabuf_xen_comm_list.h      |  67 ++
>   .../backends/xen/hyper_dmabuf_xen_drv.c            |  46 +
>   .../backends/xen/hyper_dmabuf_xen_drv.h            |  53 ++
>   .../backends/xen/hyper_dmabuf_xen_shm.c            | 525 ++++++++++++
>   .../backends/xen/hyper_dmabuf_xen_shm.h            |  46 +
>   drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_drv.c    |  10 +
>   11 files changed, 1938 insertions(+)
>   create mode 100644 drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_comm.c
>   create mode 100644 drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_comm.h
>   create mode 100644 drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_comm_list.c
>   create mode 100644 drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_comm_list.h
>   create mode 100644 drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_drv.c
>   create mode 100644 drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_drv.h
>   create mode 100644 drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_shm.c
>   create mode 100644 drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_shm.h
>
> diff --git a/drivers/dma-buf/hyper_dmabuf/Kconfig b/drivers/dma-buf/hyper_dmabuf/Kconfig
> index 5ebf516d65eb..68f3d6ce2c1f 100644
> --- a/drivers/dma-buf/hyper_dmabuf/Kconfig
> +++ b/drivers/dma-buf/hyper_dmabuf/Kconfig
> @@ -20,4 +20,11 @@ config HYPER_DMABUF_SYSFS
>   
>   	  The location of sysfs is under "...."
>   
> +config HYPER_DMABUF_XEN
> +        bool "Configure hyper_dmabuf for XEN hypervisor"
> +        default y
n?
> +        depends on HYPER_DMABUF && XEN && XENFS
> +        help
> +          Enabling Hyper_DMABUF Backend for XEN hypervisor
> +
>   endmenu
> diff --git a/drivers/dma-buf/hyper_dmabuf/Makefile b/drivers/dma-buf/hyper_dmabuf/Makefile
> index 3908522b396a..b9ab4eeca6f2 100644
> --- a/drivers/dma-buf/hyper_dmabuf/Makefile
> +++ b/drivers/dma-buf/hyper_dmabuf/Makefile
> @@ -10,6 +10,13 @@ ifneq ($(KERNELRELEASE),)
>   				 hyper_dmabuf_msg.o \
>   				 hyper_dmabuf_id.o \
>   
> +ifeq ($(CONFIG_HYPER_DMABUF_XEN), y)
> +	$(TARGET_MODULE)-objs += backends/xen/hyper_dmabuf_xen_comm.o \
> +				 backends/xen/hyper_dmabuf_xen_comm_list.o \
> +				 backends/xen/hyper_dmabuf_xen_shm.o \
> +				 backends/xen/hyper_dmabuf_xen_drv.o
> +endif
> +
>   obj-$(CONFIG_HYPER_DMABUF) := $(TARGET_MODULE).o
>   
>   # If we are running without kernel build system
> diff --git a/drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_comm.c b/drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_comm.c
> new file mode 100644
> index 000000000000..30bc4b6304ac
> --- /dev/null
> +++ b/drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_comm.c
> @@ -0,0 +1,941 @@
> +/*
> + * Copyright © 2018 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + *    Dongwon Kim <dongwon.kim@intel.com>
> + *    Mateusz Polrola <mateuszx.potrola@intel.com>
> + *
> + */
> +
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +#include <linux/workqueue.h>
> +#include <linux/delay.h>
> +#include <xen/grant_table.h>
> +#include <xen/events.h>
> +#include <xen/xenbus.h>
> +#include <asm/xen/page.h>
> +#include "hyper_dmabuf_xen_comm.h"
> +#include "hyper_dmabuf_xen_comm_list.h"
> +#include "../../hyper_dmabuf_drv.h"
> +
> +static int export_req_id;
can we avoid this?
> +
> +struct hyper_dmabuf_req req_pending = {0};
> +
> +static void xen_get_domid_delayed(struct work_struct *unused);
> +static void xen_init_comm_env_delayed(struct work_struct *unused);
> +
> +static DECLARE_DELAYED_WORK(get_vm_id_work, xen_get_domid_delayed);
> +static DECLARE_DELAYED_WORK(xen_init_comm_env_work, xen_init_comm_env_delayed);
> +
> +/* Creates entry in xen store that will keep details of all
> + * exporter rings created by this domain
> + */
> +static int xen_comm_setup_data_dir(void)
> +{
> +	char buf[255];
> +
> +	sprintf(buf, "/local/domain/%d/data/hyper_dmabuf",
> +		hy_drv_priv->domid);
Here and below: please have a string constant for that
> +
> +	return xenbus_mkdir(XBT_NIL, buf, "");
Please think of updating XenBus with a transaction, not XBT_NIL
> +}
> +
> +/* Removes entry from xenstore with exporter ring details.
> + * Other domains that has connected to any of exporter rings
> + * created by this domain, will be notified about removal of
> + * this entry and will treat that as signal to cleanup importer
> + * rings created for this domain
> + */
> +static int xen_comm_destroy_data_dir(void)
> +{
> +	char buf[255];
> +
> +	sprintf(buf, "/local/domain/%d/data/hyper_dmabuf",
> +		hy_drv_priv->domid);
> +
> +	return xenbus_rm(XBT_NIL, buf, "");
> +}
> +
> +/* Adds xenstore entries with details of exporter ring created
> + * for given remote domain. It requires special daemon running
what is this special daemon?
> + * in dom0 to make sure that given remote domain will have right
> + * permissions to access that data.
> + */
> +static int xen_comm_expose_ring_details(int domid, int rdomid,
> +					int gref, int port)
> +{
> +	char buf[255];
> +	int ret;
> +
> +	sprintf(buf, "/local/domain/%d/data/hyper_dmabuf/%d",
> +		domid, rdomid);
> +
> +	ret = xenbus_printf(XBT_NIL, buf, "grefid", "%d", gref);
> +
> +	if (ret) {
> +		dev_err(hy_drv_priv->dev,
Please do not touch global hy_drv_priv directly
> +			"Failed to write xenbus entry %s: %d\n",
> +			buf, ret);
> +
> +		return ret;
> +	}
> +
> +	ret = xenbus_printf(XBT_NIL, buf, "port", "%d", port);
> +
> +	if (ret) {
> +		dev_err(hy_drv_priv->dev,
> +			"Failed to write xenbus entry %s: %d\n",
> +			buf, ret);
> +
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * Queries details of ring exposed by remote domain.
> + */
> +static int xen_comm_get_ring_details(int domid, int rdomid,
> +				     int *grefid, int *port)
> +{
> +	char buf[255];
> +	int ret;
> +
> +	sprintf(buf, "/local/domain/%d/data/hyper_dmabuf/%d",
> +		rdomid, domid);
> +
> +	ret = xenbus_scanf(XBT_NIL, buf, "grefid", "%d", grefid);
You'll have a race condition here as you are not using transactions,
so you might read partial data from XenBus
> +
> +	if (ret <= 0) {
> +		dev_err(hy_drv_priv->dev,
> +			"Failed to read xenbus entry %s: %d\n",
> +			buf, ret);
> +
> +		return ret;
> +	}
> +
> +	ret = xenbus_scanf(XBT_NIL, buf, "port", "%d", port);
Ditto
> +
> +	if (ret <= 0) {
> +		dev_err(hy_drv_priv->dev,
> +			"Failed to read xenbus entry %s: %d\n",
> +			buf, ret);
> +
> +		return ret;
> +	}
> +
> +	return (ret <= 0 ? 1 : 0);
> +}
> +
> +static void xen_get_domid_delayed(struct work_struct *unused)
> +{
> +	struct xenbus_transaction xbt;
> +	int domid, ret;
> +
> +	/* scheduling another if driver is still running
> +	 * and xenstore has not been initialized
> +	 */
Please think of using XenBus drivers for this (struct xenbus_driver)
It might add some complexity in the backend (by dynamically registering/
unregistering XenBus driver), but will also let you run such code as
you have here synchronously, e.g. see struct xenbus_driver.otherend_changed.
This way you'll be able to implement XenBus state machine as other Xen
front/back drivers do.
> +	if (likely(xenstored_ready == 0)) {
> +		dev_dbg(hy_drv_priv->dev,
> +			"Xenstore is not ready yet. Will retry in 500ms\n");
> +		schedule_delayed_work(&get_vm_id_work, msecs_to_jiffies(500));
> +	} else {
> +		xenbus_transaction_start(&xbt);
> +
so, for consistency, please use transactions everywhere
> +		ret = xenbus_scanf(xbt, "domid", "", "%d", &domid);
> +
> +		if (ret <= 0)
> +			domid = -1;
> +
> +		xenbus_transaction_end(xbt, 0);
> +
> +		/* try again since -1 is an invalid id for domain
> +		 * (but only if driver is still running)
> +		 */
> +		if (unlikely(domid == -1)) {
> +			dev_dbg(hy_drv_priv->dev,
> +				"domid==-1 is invalid. Will retry it in 500ms\n");
> +			schedule_delayed_work(&get_vm_id_work,
> +					      msecs_to_jiffies(500));
This doesn't seem to be designed right as you need to poll for values
and have this worker
> +		} else {
> +			dev_info(hy_drv_priv->dev,
> +				 "Successfully retrieved domid from Xenstore:%d\n",
> +				 domid);
> +			hy_drv_priv->domid = domid;
> +		}
> +	}
> +}
> +
> +int xen_be_get_domid(void)
> +{
> +	struct xenbus_transaction xbt;
> +	int domid;
> +
> +	if (unlikely(xenstored_ready == 0)) {
> +		xen_get_domid_delayed(NULL);
> +		return -1;
> +	}
> +
> +	xenbus_transaction_start(&xbt);
> +
> +	if (!xenbus_scanf(xbt, "domid", "", "%d", &domid))
> +		domid = -1;
> +
> +	xenbus_transaction_end(xbt, 0);
> +
> +	return domid;
> +}
> +
> +static int xen_comm_next_req_id(void)
> +{
> +	export_req_id++;
> +	return export_req_id;
> +}
> +
> +/* For now cache latast rings as global variables TODO: keep them in list*/
> +static irqreturn_t front_ring_isr(int irq, void *info);
> +static irqreturn_t back_ring_isr(int irq, void *info);
> +
> +/* Callback function that will be called on any change of xenbus path
> + * being watched. Used for detecting creation/destruction of remote
> + * domain exporter ring.
If you implement xenbus_driver.otherend_changed and
corresponding state machine this might not be needed
> + *
> + * When remote domain's exporter ring will be detected, importer ring
> + * on this domain will be created.
> + *
> + * When remote domain's exporter ring destruction will be detected it
> + * will celanup this domain importer ring.
> + *
> + * Destruction can be caused by unloading module by remote domain or
> + * it's crash/force shutdown.
> + */
> +static void remote_dom_exporter_watch_cb(struct xenbus_watch *watch,
> +					 const char *path, const char *token)
> +{
> +	int rdom, ret;
> +	uint32_t grefid, port;
> +	struct xen_comm_rx_ring_info *ring_info;
> +
> +	/* Check which domain has changed its exporter rings */
> +	ret = sscanf(watch->node, "/local/domain/%d/", &rdom);
> +	if (ret <= 0)
> +		return;
> +
> +	/* Check if we have importer ring for given remote domain already
> +	 * created
> +	 */
> +	ring_info = xen_comm_find_rx_ring(rdom);
> +
> +	/* Try to query remote domain exporter ring details - if
> +	 * that will fail and we have importer ring that means remote
> +	 * domains has cleanup its exporter ring, so our importer ring
> +	 * is no longer useful.
> +	 *
> +	 * If querying details will succeed and we don't have importer ring,
> +	 * it means that remote domain has setup it for us and we should
> +	 * connect to it.
> +	 */
> +
> +	ret = xen_comm_get_ring_details(xen_be_get_domid(),
> +					rdom, &grefid, &port);
> +
> +	if (ring_info && ret != 0) {
> +		dev_info(hy_drv_priv->dev,
> +			 "Remote exporter closed, cleaninup importer\n");
> +		xen_be_cleanup_rx_rbuf(rdom);
> +	} else if (!ring_info && ret == 0) {
> +		dev_info(hy_drv_priv->dev,
> +			 "Registering importer\n");
> +		xen_be_init_rx_rbuf(rdom);
> +	}
> +}
> +
> +/* exporter needs to generated info for page sharing */
> +int xen_be_init_tx_rbuf(int domid)
> +{
> +	struct xen_comm_tx_ring_info *ring_info;
> +	struct xen_comm_sring *sring;
> +	struct evtchn_alloc_unbound alloc_unbound;
> +	struct evtchn_close close;
> +
> +	void *shared_ring;
> +	int ret;
> +
> +	/* check if there's any existing tx channel in the table */
> +	ring_info = xen_comm_find_tx_ring(domid);
> +
> +	if (ring_info) {
> +		dev_info(hy_drv_priv->dev,
> +			 "tx ring ch to domid = %d already exist\ngref = %d, port = %d\n",
> +		ring_info->rdomain, ring_info->gref_ring, ring_info->port);
> +		return 0;
> +	}
> +
> +	ring_info = kmalloc(sizeof(*ring_info), GFP_KERNEL);
> +
> +	if (!ring_info)
> +		return -ENOMEM;
> +
> +	/* from exporter to importer */
> +	shared_ring = (void *)__get_free_pages(GFP_KERNEL, 1);
> +	if (shared_ring == 0) {
> +		kfree(ring_info);
> +		return -ENOMEM;
> +	}
> +
> +	sring = (struct xen_comm_sring *) shared_ring;
> +
> +	SHARED_RING_INIT(sring);
> +
> +	FRONT_RING_INIT(&(ring_info->ring_front), sring, PAGE_SIZE);
> +
> +	ring_info->gref_ring = gnttab_grant_foreign_access(domid,
> +						virt_to_mfn(shared_ring),
> +						0);
> +	if (ring_info->gref_ring < 0) {
> +		/* fail to get gref */
> +		kfree(ring_info);
> +		return -EFAULT;
> +	}
> +
> +	alloc_unbound.dom = DOMID_SELF;
> +	alloc_unbound.remote_dom = domid;
> +	ret = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
> +					  &alloc_unbound);
Please do not open-code: xenbus_alloc_evtchn
> +	if (ret) {
> +		dev_err(hy_drv_priv->dev,
> +			"Cannot allocate event channel\n");
> +		kfree(ring_info);
> +		return -EIO;
> +	}
> +
> +	/* setting up interrupt */
> +	ret = bind_evtchn_to_irqhandler(alloc_unbound.port,
> +					front_ring_isr, 0,
> +					NULL, (void *) ring_info);
> +
> +	if (ret < 0) {
> +		dev_err(hy_drv_priv->dev,
> +			"Failed to setup event channel\n");
> +		close.port = alloc_unbound.port;
> +		HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
Please do not open-code: xenbus_free_evtchn
> +		gnttab_end_foreign_access(ring_info->gref_ring, 0,
> +					virt_to_mfn(shared_ring));
> +		kfree(ring_info);
> +		return -EIO;
> +	}
> +
> +	ring_info->rdomain = domid;
> +	ring_info->irq = ret;
> +	ring_info->port = alloc_unbound.port;
> +
> +	mutex_init(&ring_info->lock);
> +
> +	dev_dbg(hy_drv_priv->dev,
> +		"%s: allocated eventchannel gref %d  port: %d  irq: %d\n",
> +		__func__,
> +		ring_info->gref_ring,
> +		ring_info->port,
> +		ring_info->irq);
> +
> +	ret = xen_comm_add_tx_ring(ring_info);
> +
And what if we fail?
> +	ret = xen_comm_expose_ring_details(xen_be_get_domid(),
> +					   domid,
> +					   ring_info->gref_ring,
> +					   ring_info->port);
> +
> +	/* Register watch for remote domain exporter ring.
> +	 * When remote domain will setup its exporter ring,
> +	 * we will automatically connect our importer ring to it.
> +	 */
> +	ring_info->watch.callback = remote_dom_exporter_watch_cb;
> +	ring_info->watch.node = kmalloc(255, GFP_KERNEL);
> +
> +	if (!ring_info->watch.node) {
> +		kfree(ring_info);
> +		return -ENOMEM;
> +	}
> +
> +	sprintf((char *)ring_info->watch.node,
> +		"/local/domain/%d/data/hyper_dmabuf/%d/port",
> +		domid, xen_be_get_domid());
> +
> +	register_xenbus_watch(&ring_info->watch);
> +
> +	return ret;
> +}
> +
> +/* cleans up exporter ring created for given remote domain */
> +void xen_be_cleanup_tx_rbuf(int domid)
> +{
> +	struct xen_comm_tx_ring_info *ring_info;
> +	struct xen_comm_rx_ring_info *rx_ring_info;
> +
> +	/* check if we at all have exporter ring for given rdomain */
> +	ring_info = xen_comm_find_tx_ring(domid);
> +
> +	if (!ring_info)
> +		return;
> +
> +	xen_comm_remove_tx_ring(domid);
> +
> +	unregister_xenbus_watch(&ring_info->watch);
> +	kfree(ring_info->watch.node);
> +
> +	/* No need to close communication channel, will be done by
> +	 * this function
> +	 */
> +	unbind_from_irqhandler(ring_info->irq, (void *) ring_info);
> +
> +	/* No need to free sring page, will be freed by this function
> +	 * when other side will end its access
> +	 */
> +	gnttab_end_foreign_access(ring_info->gref_ring, 0,
> +				  (unsigned long) ring_info->ring_front.sring);
> +
> +	kfree(ring_info);
> +
> +	rx_ring_info = xen_comm_find_rx_ring(domid);
> +	if (!rx_ring_info)
> +		return;
> +
> +	BACK_RING_INIT(&(rx_ring_info->ring_back),
> +		       rx_ring_info->ring_back.sring,
> +		       PAGE_SIZE);
why init on cleanup?
> +}
> +
> +/* importer needs to know about shared page and port numbers for
> + * ring buffer and event channel
> + */
> +int xen_be_init_rx_rbuf(int domid)
> +{
> +	struct xen_comm_rx_ring_info *ring_info;
> +	struct xen_comm_sring *sring;
> +
> +	struct page *shared_ring;
> +
> +	struct gnttab_map_grant_ref *map_ops;
> +
> +	int ret;
> +	int rx_gref, rx_port;
> +
> +	/* check if there's existing rx ring channel */
> +	ring_info = xen_comm_find_rx_ring(domid);
> +
> +	if (ring_info) {
> +		dev_info(hy_drv_priv->dev,
> +			 "rx ring ch from domid = %d already exist\n",
> +			 ring_info->sdomain);
> +
> +		return 0;
> +	}
> +
> +	ret = xen_comm_get_ring_details(xen_be_get_domid(), domid,
> +					&rx_gref, &rx_port);
> +
> +	if (ret) {
> +		dev_err(hy_drv_priv->dev,
> +			"Domain %d has not created exporter ring for current domain\n",
> +			domid);
> +
> +		return ret;
> +	}
> +
> +	ring_info = kmalloc(sizeof(*ring_info), GFP_KERNEL);
> +
> +	if (!ring_info)
> +		return -ENOMEM;
> +
> +	ring_info->sdomain = domid;
> +	ring_info->evtchn = rx_port;
> +
> +	map_ops = kmalloc(sizeof(*map_ops), GFP_KERNEL);
> +
> +	if (!map_ops) {
> +		ret = -ENOMEM;
> +		goto fail_no_map_ops;
> +	}
> +
> +	if (gnttab_alloc_pages(1, &shared_ring)) {
> +		ret = -ENOMEM;
> +		goto fail_others;
> +	}
> +
Please see xenbus_grant_ring
> +	gnttab_set_map_op(&map_ops[0],
> +			  (unsigned long)pfn_to_kaddr(
> +					page_to_pfn(shared_ring)),
> +			  GNTMAP_host_map, rx_gref, domid);
> +
> +	gnttab_set_unmap_op(&ring_info->unmap_op,
> +			    (unsigned long)pfn_to_kaddr(
> +					page_to_pfn(shared_ring)),
> +			    GNTMAP_host_map, -1);
> +
> +	ret = gnttab_map_refs(map_ops, NULL, &shared_ring, 1);
> +	if (ret < 0) {
> +		dev_err(hy_drv_priv->dev, "Cannot map ring\n");
> +		ret = -EFAULT;
> +		goto fail_others;
> +	}
> +
> +	if (map_ops[0].status) {
> +		dev_err(hy_drv_priv->dev, "Ring mapping failed\n");
> +		ret = -EFAULT;
> +		goto fail_others;
> +	} else {
> +		ring_info->unmap_op.handle = map_ops[0].handle;
> +	}
> +
> +	kfree(map_ops);
> +
> +	sring = (struct xen_comm_sring *)pfn_to_kaddr(page_to_pfn(shared_ring));
> +
> +	BACK_RING_INIT(&ring_info->ring_back, sring, PAGE_SIZE);
> +
> +	ret = bind_interdomain_evtchn_to_irq(domid, rx_port);
> +
> +	if (ret < 0) {
> +		ret = -EIO;
> +		goto fail_others;
> +	}
> +
> +	ring_info->irq = ret;
> +
> +	dev_dbg(hy_drv_priv->dev,
> +		"%s: bound to eventchannel port: %d  irq: %d\n", __func__,
> +		rx_port,
> +		ring_info->irq);
> +
> +	ret = xen_comm_add_rx_ring(ring_info);
> +
> +	/* Setup communcation channel in opposite direction */
> +	if (!xen_comm_find_tx_ring(domid))
> +		ret = xen_be_init_tx_rbuf(domid);
> +
> +	ret = request_irq(ring_info->irq,
> +			  back_ring_isr, 0,
> +			  NULL, (void *)ring_info);
> +
> +	return ret;
> +
> +fail_others:
> +	kfree(map_ops);
> +
> +fail_no_map_ops:
> +	kfree(ring_info);
> +
> +	return ret;
> +}
> +
> +/* clenas up importer ring create for given source domain */
> +void xen_be_cleanup_rx_rbuf(int domid)
> +{
> +	struct xen_comm_rx_ring_info *ring_info;
> +	struct xen_comm_tx_ring_info *tx_ring_info;
> +	struct page *shared_ring;
> +
> +	/* check if we have importer ring created for given sdomain */
> +	ring_info = xen_comm_find_rx_ring(domid);
> +
> +	if (!ring_info)
> +		return;
> +
> +	xen_comm_remove_rx_ring(domid);
> +
> +	/* no need to close event channel, will be done by that function */
> +	unbind_from_irqhandler(ring_info->irq, (void *)ring_info);
> +
> +	/* unmapping shared ring page */
> +	shared_ring = virt_to_page(ring_info->ring_back.sring);
> +	gnttab_unmap_refs(&ring_info->unmap_op, NULL, &shared_ring, 1);
> +	gnttab_free_pages(1, &shared_ring);
> +
> +	kfree(ring_info);
> +
> +	tx_ring_info = xen_comm_find_tx_ring(domid);
> +	if (!tx_ring_info)
> +		return;
> +
> +	SHARED_RING_INIT(tx_ring_info->ring_front.sring);
> +	FRONT_RING_INIT(&(tx_ring_info->ring_front),
> +			tx_ring_info->ring_front.sring,
> +			PAGE_SIZE);
> +}
> +
> +#ifdef CONFIG_HYPER_DMABUF_XEN_AUTO_RX_CH_ADD
> +
> +static void xen_rx_ch_add_delayed(struct work_struct *unused);
> +
> +static DECLARE_DELAYED_WORK(xen_rx_ch_auto_add_work, xen_rx_ch_add_delayed);
> +
> +#define DOMID_SCAN_START	1	/*  domid = 1 */
> +#define DOMID_SCAN_END		10	/* domid = 10 */
> +
> +static void xen_rx_ch_add_delayed(struct work_struct *unused)
> +{
> +	int ret;
> +	char buf[128];
> +	int i, dummy;
> +
> +	dev_dbg(hy_drv_priv->dev,
> +		"Scanning new tx channel comming from another domain\n");
This should be synchronous IMO, no scanners
> +
> +	/* check other domains and schedule another work if driver
> +	 * is still running and backend is valid
> +	 */
> +	if (hy_drv_priv &&
> +	    hy_drv_priv->initialized) {
> +		for (i = DOMID_SCAN_START; i < DOMID_SCAN_END + 1; i++) {
> +			if (i == hy_drv_priv->domid)
> +				continue;
> +
> +			sprintf(buf, "/local/domain/%d/data/hyper_dmabuf/%d",
> +				i, hy_drv_priv->domid);
> +
> +			ret = xenbus_scanf(XBT_NIL, buf, "port", "%d", &dummy);
> +
> +			if (ret > 0) {
> +				if (xen_comm_find_rx_ring(i) != NULL)
> +					continue;
> +
> +				ret = xen_be_init_rx_rbuf(i);
> +
> +				if (!ret)
> +					dev_info(hy_drv_priv->dev,
> +						 "Done rx ch init for VM %d\n",
> +						 i);
> +			}
> +		}
> +
> +		/* check every 10 seconds */
> +		schedule_delayed_work(&xen_rx_ch_auto_add_work,
> +				      msecs_to_jiffies(10000));
> +	}
> +}
> +
> +#endif /* CONFIG_HYPER_DMABUF_XEN_AUTO_RX_CH_ADD */
> +
> +void xen_init_comm_env_delayed(struct work_struct *unused)
> +{
> +	int ret;
> +
> +	/* scheduling another work if driver is still running
> +	 * and xenstore hasn't been initialized or dom_id hasn't
> +	 * been correctly retrieved.
> +	 */
> +	if (likely(xenstored_ready == 0 ||
> +	    hy_drv_priv->domid == -1)) {
> +		dev_dbg(hy_drv_priv->dev,
> +			"Xenstore not ready Will re-try in 500ms\n");
> +		schedule_delayed_work(&xen_init_comm_env_work,
> +				      msecs_to_jiffies(500));
> +	} else {
> +		ret = xen_comm_setup_data_dir();
> +		if (ret < 0) {
> +			dev_err(hy_drv_priv->dev,
> +				"Failed to create data dir in Xenstore\n");
> +		} else {
> +			dev_info(hy_drv_priv->dev,
> +				"Successfully finished comm env init\n");
> +			hy_drv_priv->initialized = true;
> +
> +#ifdef CONFIG_HYPER_DMABUF_XEN_AUTO_RX_CH_ADD
> +			xen_rx_ch_add_delayed(NULL);
> +#endif /* CONFIG_HYPER_DMABUF_XEN_AUTO_RX_CH_ADD */
> +		}
> +	}
> +}
> +
> +int xen_be_init_comm_env(void)
> +{
> +	int ret;
> +
> +	xen_comm_ring_table_init();
> +
> +	if (unlikely(xenstored_ready == 0 ||
> +	    hy_drv_priv->domid == -1)) {
> +		xen_init_comm_env_delayed(NULL);
> +		return -1;
> +	}
> +
> +	ret = xen_comm_setup_data_dir();
> +	if (ret < 0) {
> +		dev_err(hy_drv_priv->dev,
> +			"Failed to create data dir in Xenstore\n");
> +	} else {
> +		dev_info(hy_drv_priv->dev,
> +			"Successfully finished comm env initialization\n");
> +
> +		hy_drv_priv->initialized = true;
> +	}
> +
> +	return ret;
> +}
> +
> +/* cleans up all tx/rx rings */
> +static void xen_be_cleanup_all_rbufs(void)
> +{
> +	xen_comm_foreach_tx_ring(xen_be_cleanup_tx_rbuf);
> +	xen_comm_foreach_rx_ring(xen_be_cleanup_rx_rbuf);
> +}
> +
> +void xen_be_destroy_comm(void)
> +{
> +	xen_be_cleanup_all_rbufs();
> +	xen_comm_destroy_data_dir();
> +}
> +
> +int xen_be_send_req(int domid, struct hyper_dmabuf_req *req,
> +			      int wait)
> +{
> +	struct xen_comm_front_ring *ring;
> +	struct hyper_dmabuf_req *new_req;
> +	struct xen_comm_tx_ring_info *ring_info;
> +	int notify;
> +
> +	struct timeval tv_start, tv_end;
> +	struct timeval tv_diff;
> +
> +	int timeout = 1000;
> +
> +	/* find a ring info for the channel */
> +	ring_info = xen_comm_find_tx_ring(domid);
> +	if (!ring_info) {
> +		dev_err(hy_drv_priv->dev,
> +			"Can't find ring info for the channel\n");
> +		return -ENOENT;
> +	}
> +
> +
> +	ring = &ring_info->ring_front;
> +
> +	do_gettimeofday(&tv_start);
> +
> +	while (RING_FULL(ring)) {
> +		dev_dbg(hy_drv_priv->dev, "RING_FULL\n");
> +
> +		if (timeout == 0) {
> +			dev_err(hy_drv_priv->dev,
> +				"Timeout while waiting for an entry in the ring\n");
> +			return -EIO;
> +		}
> +		usleep_range(100, 120);
> +		timeout--;
> +	}
Heh
> +
> +	timeout = 1000;
> +
> +	mutex_lock(&ring_info->lock);
> +
> +	new_req = RING_GET_REQUEST(ring, ring->req_prod_pvt);
> +	if (!new_req) {
> +		mutex_unlock(&ring_info->lock);
> +		dev_err(hy_drv_priv->dev,
> +			"NULL REQUEST\n");
> +		return -EIO;
> +	}
> +
> +	req->req_id = xen_comm_next_req_id();
> +
> +	/* update req_pending with current request */
> +	memcpy(&req_pending, req, sizeof(req_pending));
> +
> +	/* pass current request to the ring */
> +	memcpy(new_req, req, sizeof(*new_req));
> +
> +	ring->req_prod_pvt++;
> +
> +	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(ring, notify);
> +	if (notify)
> +		notify_remote_via_irq(ring_info->irq);
> +
> +	if (wait) {
> +		while (timeout--) {
> +			if (req_pending.stat !=
> +			    HYPER_DMABUF_REQ_NOT_RESPONDED)
> +				break;
> +			usleep_range(100, 120);
> +		}
> +
> +		if (timeout < 0) {
> +			mutex_unlock(&ring_info->lock);
> +			dev_err(hy_drv_priv->dev,
> +				"request timed-out\n");
> +			return -EBUSY;
> +		}
> +
> +		mutex_unlock(&ring_info->lock);
> +		do_gettimeofday(&tv_end);
> +
> +		/* checking time duration for round-trip of a request
> +		 * for debugging
> +		 */
put it under debug #ifdef then?
> +		if (tv_end.tv_usec >= tv_start.tv_usec) {
> +			tv_diff.tv_sec = tv_end.tv_sec-tv_start.tv_sec;
> +			tv_diff.tv_usec = tv_end.tv_usec-tv_start.tv_usec;
> +		} else {
> +			tv_diff.tv_sec = tv_end.tv_sec-tv_start.tv_sec-1;
> +			tv_diff.tv_usec = tv_end.tv_usec+1000000-
> +					  tv_start.tv_usec;
> +		}
> +
> +		if (tv_diff.tv_sec != 0 && tv_diff.tv_usec > 16000)
> +			dev_dbg(hy_drv_priv->dev,
> +				"send_req:time diff: %ld sec, %ld usec\n",
> +				tv_diff.tv_sec, tv_diff.tv_usec);
> +	}
> +
> +	mutex_unlock(&ring_info->lock);
> +
> +	return 0;
> +}
> +
> +/* ISR for handling request */
> +static irqreturn_t back_ring_isr(int irq, void *info)
> +{
> +	RING_IDX rc, rp;
> +	struct hyper_dmabuf_req req;
> +	struct hyper_dmabuf_resp resp;
> +
> +	int notify, more_to_do;
> +	int ret;
> +
> +	struct xen_comm_rx_ring_info *ring_info;
> +	struct xen_comm_back_ring *ring;
> +
> +	ring_info = (struct xen_comm_rx_ring_info *)info;
> +	ring = &ring_info->ring_back;
> +
> +	dev_dbg(hy_drv_priv->dev, "%s\n", __func__);
> +
> +	do {
> +		rc = ring->req_cons;
> +		rp = ring->sring->req_prod;
> +		more_to_do = 0;
> +		while (rc != rp) {
> +			if (RING_REQUEST_CONS_OVERFLOW(ring, rc))
> +				break;
> +
> +			memcpy(&req, RING_GET_REQUEST(ring, rc), sizeof(req));
> +			ring->req_cons = ++rc;
> +
> +			ret = hyper_dmabuf_msg_parse(ring_info->sdomain, &req);
> +
> +			if (ret > 0) {
> +				/* preparing a response for the request and
> +				 * send it to the requester
> +				 */
> +				memcpy(&resp, &req, sizeof(resp));
> +				memcpy(RING_GET_RESPONSE(ring,
> +							 ring->rsp_prod_pvt),
> +							 &resp, sizeof(resp));
> +				ring->rsp_prod_pvt++;
> +
> +				dev_dbg(hy_drv_priv->dev,
> +					"responding to exporter for req:%d\n",
> +					resp.resp_id);
> +
> +				RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(ring,
> +								     notify);
> +
> +				if (notify)
> +					notify_remote_via_irq(ring_info->irq);
> +			}
> +
> +			RING_FINAL_CHECK_FOR_REQUESTS(ring, more_to_do);
> +		}
> +	} while (more_to_do);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +/* ISR for handling responses */
> +static irqreturn_t front_ring_isr(int irq, void *info)
> +{
> +	/* front ring only care about response from back */
> +	struct hyper_dmabuf_resp *resp;
> +	RING_IDX i, rp;
> +	int more_to_do, ret;
> +
> +	struct xen_comm_tx_ring_info *ring_info;
> +	struct xen_comm_front_ring *ring;
> +
> +	ring_info = (struct xen_comm_tx_ring_info *)info;
> +	ring = &ring_info->ring_front;
> +
> +	dev_dbg(hy_drv_priv->dev, "%s\n", __func__);
> +
> +	do {
> +		more_to_do = 0;
> +		rp = ring->sring->rsp_prod;
> +		for (i = ring->rsp_cons; i != rp; i++) {
> +			resp = RING_GET_RESPONSE(ring, i);
> +
> +			/* update pending request's status with what is
> +			 * in the response
> +			 */
> +
> +			dev_dbg(hy_drv_priv->dev,
> +				"getting response from importer\n");
> +
> +			if (req_pending.req_id == resp->resp_id)
> +				req_pending.stat = resp->stat;
> +
> +			if (resp->stat == HYPER_DMABUF_REQ_NEEDS_FOLLOW_UP) {
> +				/* parsing response */
> +				ret = hyper_dmabuf_msg_parse(ring_info->rdomain,
> +					(struct hyper_dmabuf_req *)resp);
> +
> +				if (ret < 0) {
> +					dev_err(hy_drv_priv->dev,
> +						"err while parsing resp\n");
> +				}
> +			} else if (resp->stat == HYPER_DMABUF_REQ_PROCESSED) {
> +				/* for debugging dma_buf remote synch */
> +				dev_dbg(hy_drv_priv->dev,
> +					"original request = 0x%x\n", resp->cmd);
> +				dev_dbg(hy_drv_priv->dev,
> +					"got HYPER_DMABUF_REQ_PROCESSED\n");
> +			} else if (resp->stat == HYPER_DMABUF_REQ_ERROR) {
> +				/* for debugging dma_buf remote synch */
> +				dev_dbg(hy_drv_priv->dev,
> +					"original request = 0x%x\n", resp->cmd);
> +				dev_dbg(hy_drv_priv->dev,
> +					"got HYPER_DMABUF_REQ_ERROR\n");
> +			}
> +		}
> +
> +		ring->rsp_cons = i;
> +
> +		if (i != ring->req_prod_pvt)
> +			RING_FINAL_CHECK_FOR_RESPONSES(ring, more_to_do);
> +		else
> +			ring->sring->rsp_event = i+1;
> +
> +	} while (more_to_do);
> +
> +	return IRQ_HANDLED;
> +}
> diff --git a/drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_comm.h b/drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_comm.h
> new file mode 100644
> index 000000000000..c0d3139ace59
> --- /dev/null
> +++ b/drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_comm.h
> @@ -0,0 +1,78 @@
> +/*
> + * Copyright © 2018 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + */
> +
> +#ifndef __HYPER_DMABUF_XEN_COMM_H__
> +#define __HYPER_DMABUF_XEN_COMM_H__
> +
> +#include "xen/interface/io/ring.h"
> +#include "xen/xenbus.h"
> +#include "../../hyper_dmabuf_msg.h"
> +
> +extern int xenstored_ready;
> +
> +DEFINE_RING_TYPES(xen_comm, struct hyper_dmabuf_req, struct hyper_dmabuf_resp);
> +
> +struct xen_comm_tx_ring_info {
> +	struct xen_comm_front_ring ring_front;
> +	int rdomain;
> +	int gref_ring;
> +	int irq;
> +	int port;
> +	struct mutex lock;
> +	struct xenbus_watch watch;
> +};
> +
> +struct xen_comm_rx_ring_info {
> +	int sdomain;
> +	int irq;
> +	int evtchn;
> +	struct xen_comm_back_ring ring_back;
> +	struct gnttab_unmap_grant_ref unmap_op;
> +};
> +
> +int xen_be_get_domid(void);
> +
> +int xen_be_init_comm_env(void);
> +
> +/* exporter needs to generated info for page sharing */
> +int xen_be_init_tx_rbuf(int domid);
> +
> +/* importer needs to know about shared page and port numbers
> + * for ring buffer and event channel
> + */
> +int xen_be_init_rx_rbuf(int domid);
> +
> +/* cleans up exporter ring created for given domain */
> +void xen_be_cleanup_tx_rbuf(int domid);
> +
> +/* cleans up importer ring created for given domain */
> +void xen_be_cleanup_rx_rbuf(int domid);
> +
> +void xen_be_destroy_comm(void);
> +
> +/* send request to the remote domain */
> +int xen_be_send_req(int domid, struct hyper_dmabuf_req *req,
> +		    int wait);
> +
> +#endif /* __HYPER_DMABUF_XEN_COMM_H__ */
> diff --git a/drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_comm_list.c b/drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_comm_list.c
> new file mode 100644
> index 000000000000..5a8e9d9b737f
> --- /dev/null
> +++ b/drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_comm_list.c
> @@ -0,0 +1,158 @@
> +/*
> + * Copyright © 2018 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + *    Dongwon Kim <dongwon.kim@intel.com>
> + *    Mateusz Polrola <mateuszx.potrola@intel.com>
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +#include <linux/cdev.h>
> +#include <linux/hashtable.h>
> +#include <xen/grant_table.h>
> +#include "../../hyper_dmabuf_drv.h"
> +#include "hyper_dmabuf_xen_comm.h"
> +#include "hyper_dmabuf_xen_comm_list.h"
> +
> +DECLARE_HASHTABLE(xen_comm_tx_ring_hash, MAX_ENTRY_TX_RING);
> +DECLARE_HASHTABLE(xen_comm_rx_ring_hash, MAX_ENTRY_RX_RING);
> +
> +void xen_comm_ring_table_init(void)
> +{
> +	hash_init(xen_comm_rx_ring_hash);
> +	hash_init(xen_comm_tx_ring_hash);
> +}
> +
> +int xen_comm_add_tx_ring(struct xen_comm_tx_ring_info *ring_info)
> +{
> +	struct xen_comm_tx_ring_info_entry *info_entry;
> +
> +	info_entry = kmalloc(sizeof(*info_entry), GFP_KERNEL);
> +
> +	if (!info_entry)
> +		return -ENOMEM;
> +
> +	info_entry->info = ring_info;
> +
> +	hash_add(xen_comm_tx_ring_hash, &info_entry->node,
> +		info_entry->info->rdomain);
> +
> +	return 0;
> +}
> +
> +int xen_comm_add_rx_ring(struct xen_comm_rx_ring_info *ring_info)
> +{
> +	struct xen_comm_rx_ring_info_entry *info_entry;
> +
> +	info_entry = kmalloc(sizeof(*info_entry), GFP_KERNEL);
> +
> +	if (!info_entry)
> +		return -ENOMEM;
> +
> +	info_entry->info = ring_info;
> +
> +	hash_add(xen_comm_rx_ring_hash, &info_entry->node,
> +		info_entry->info->sdomain);
> +
> +	return 0;
> +}
> +
> +struct xen_comm_tx_ring_info *xen_comm_find_tx_ring(int domid)
> +{
> +	struct xen_comm_tx_ring_info_entry *info_entry;
> +	int bkt;
> +
> +	hash_for_each(xen_comm_tx_ring_hash, bkt, info_entry, node)
> +		if (info_entry->info->rdomain == domid)
> +			return info_entry->info;
> +
> +	return NULL;
> +}
> +
> +struct xen_comm_rx_ring_info *xen_comm_find_rx_ring(int domid)
> +{
> +	struct xen_comm_rx_ring_info_entry *info_entry;
> +	int bkt;
> +
> +	hash_for_each(xen_comm_rx_ring_hash, bkt, info_entry, node)
> +		if (info_entry->info->sdomain == domid)
> +			return info_entry->info;
> +
> +	return NULL;
> +}
> +
> +int xen_comm_remove_tx_ring(int domid)
> +{
> +	struct xen_comm_tx_ring_info_entry *info_entry;
> +	int bkt;
> +
> +	hash_for_each(xen_comm_tx_ring_hash, bkt, info_entry, node)
> +		if (info_entry->info->rdomain == domid) {
> +			hash_del(&info_entry->node);
> +			kfree(info_entry);
> +			return 0;
> +		}
> +
> +	return -ENOENT;
> +}
> +
> +int xen_comm_remove_rx_ring(int domid)
> +{
> +	struct xen_comm_rx_ring_info_entry *info_entry;
> +	int bkt;
> +
> +	hash_for_each(xen_comm_rx_ring_hash, bkt, info_entry, node)
> +		if (info_entry->info->sdomain == domid) {
> +			hash_del(&info_entry->node);
> +			kfree(info_entry);
> +			return 0;
> +		}
> +
> +	return -ENOENT;
> +}
> +
> +void xen_comm_foreach_tx_ring(void (*func)(int domid))
> +{
> +	struct xen_comm_tx_ring_info_entry *info_entry;
> +	struct hlist_node *tmp;
> +	int bkt;
> +
> +	hash_for_each_safe(xen_comm_tx_ring_hash, bkt, tmp,
> +			   info_entry, node) {
> +		func(info_entry->info->rdomain);
> +	}
> +}
> +
> +void xen_comm_foreach_rx_ring(void (*func)(int domid))
> +{
> +	struct xen_comm_rx_ring_info_entry *info_entry;
> +	struct hlist_node *tmp;
> +	int bkt;
> +
> +	hash_for_each_safe(xen_comm_rx_ring_hash, bkt, tmp,
> +			   info_entry, node) {
> +		func(info_entry->info->sdomain);
> +	}
> +}
> diff --git a/drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_comm_list.h b/drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_comm_list.h
> new file mode 100644
> index 000000000000..8d4b52bd41b0
> --- /dev/null
> +++ b/drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_comm_list.h
> @@ -0,0 +1,67 @@
> +/*
> + * Copyright © 2018 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + */
> +
> +#ifndef __HYPER_DMABUF_XEN_COMM_LIST_H__
> +#define __HYPER_DMABUF_XEN_COMM_LIST_H__
> +
> +/* number of bits to be used for exported dmabufs hash table */
> +#define MAX_ENTRY_TX_RING 7
> +/* number of bits to be used for imported dmabufs hash table */
> +#define MAX_ENTRY_RX_RING 7
> +
> +struct xen_comm_tx_ring_info_entry {
> +	struct xen_comm_tx_ring_info *info;
> +	struct hlist_node node;
> +};
> +
> +struct xen_comm_rx_ring_info_entry {
> +	struct xen_comm_rx_ring_info *info;
> +	struct hlist_node node;
> +};
> +
> +void xen_comm_ring_table_init(void);
> +
> +int xen_comm_add_tx_ring(struct xen_comm_tx_ring_info *ring_info);
> +
> +int xen_comm_add_rx_ring(struct xen_comm_rx_ring_info *ring_info);
> +
> +int xen_comm_remove_tx_ring(int domid);
> +
> +int xen_comm_remove_rx_ring(int domid);
> +
> +struct xen_comm_tx_ring_info *xen_comm_find_tx_ring(int domid);
> +
> +struct xen_comm_rx_ring_info *xen_comm_find_rx_ring(int domid);
> +
> +/* iterates over all exporter rings and calls provided
> + * function for each of them
> + */
> +void xen_comm_foreach_tx_ring(void (*func)(int domid));
> +
> +/* iterates over all importer rings and calls provided
> + * function for each of them
> + */
> +void xen_comm_foreach_rx_ring(void (*func)(int domid));
> +
> +#endif // __HYPER_DMABUF_XEN_COMM_LIST_H__
> diff --git a/drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_drv.c b/drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_drv.c
> new file mode 100644
> index 000000000000..8122dc15b4cb
> --- /dev/null
> +++ b/drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_drv.c
> @@ -0,0 +1,46 @@
> +/*
> + * Copyright © 2018 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + *    Dongwon Kim <dongwon.kim@intel.com>
> + *    Mateusz Polrola <mateuszx.potrola@intel.com>
> + *
> + */
> +
> +#include "../../hyper_dmabuf_drv.h"
> +#include "hyper_dmabuf_xen_comm.h"
> +#include "hyper_dmabuf_xen_shm.h"
> +
> +struct hyper_dmabuf_bknd_ops xen_bknd_ops = {
> +	.init = NULL, /* not needed for xen */
> +	.cleanup = NULL, /* not needed for xen */
> +	.get_vm_id = xen_be_get_domid,
> +	.share_pages = xen_be_share_pages,
> +	.unshare_pages = xen_be_unshare_pages,
> +	.map_shared_pages = (void *)xen_be_map_shared_pages,
> +	.unmap_shared_pages = xen_be_unmap_shared_pages,
> +	.init_comm_env = xen_be_init_comm_env,
> +	.destroy_comm = xen_be_destroy_comm,
> +	.init_rx_ch = xen_be_init_rx_rbuf,
> +	.init_tx_ch = xen_be_init_tx_rbuf,
> +	.send_req = xen_be_send_req,
> +};
> diff --git a/drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_drv.h b/drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_drv.h
> new file mode 100644
> index 000000000000..c97dc1c5d042
> --- /dev/null
> +++ b/drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_drv.h
> @@ -0,0 +1,53 @@
> +/*
> + * Copyright © 2018 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + */
> +
> +#ifndef __HYPER_DMABUF_XEN_DRV_H__
> +#define __HYPER_DMABUF_XEN_DRV_H__
> +#include <xen/interface/grant_table.h>
> +
> +extern struct hyper_dmabuf_bknd_ops xen_bknd_ops;
> +
> +/* Main purpose of this structure is to keep
> + * all references created or acquired for sharing
> + * pages with another domain for freeing those later
> + * when unsharing.
> + */
> +struct xen_shared_pages_info {
> +	/* top level refid */
> +	grant_ref_t lvl3_gref;
> +
> +	/* page of top level addressing, it contains refids of 2nd lvl pages */
> +	grant_ref_t *lvl3_table;
> +
> +	/* table of 2nd level pages, that contains refids to data pages */
> +	grant_ref_t *lvl2_table;
> +
> +	/* unmap ops for mapped pages */
> +	struct gnttab_unmap_grant_ref *unmap_ops;
> +
> +	/* data pages to be unmapped */
> +	struct page **data_pages;
> +};
> +
> +#endif // __HYPER_DMABUF_XEN_COMM_H__
> diff --git a/drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_shm.c b/drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_shm.c
> new file mode 100644
> index 000000000000..b2dcef34e10f
> --- /dev/null
> +++ b/drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_shm.c
> @@ -0,0 +1,525 @@
> +/*
> + * Copyright © 2018 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + *    Dongwon Kim <dongwon.kim@intel.com>
> + *    Mateusz Polrola <mateuszx.potrola@intel.com>
> + *
> + */
> +
> +#include <linux/slab.h>
> +#include <xen/grant_table.h>
> +#include <asm/xen/page.h>
> +#include "hyper_dmabuf_xen_drv.h"
> +#include "../../hyper_dmabuf_drv.h"
> +
> +#define REFS_PER_PAGE (PAGE_SIZE/sizeof(grant_ref_t))
> +
> +/*
> + * Creates 2 level page directory structure for referencing shared pages.
> + * Top level page is a single page that contains up to 1024 refids that
> + * point to 2nd level pages.
> + *
> + * Each 2nd level page contains up to 1024 refids that point to shared
> + * data pages.
> + *
> + * There will always be one top level page and number of 2nd level pages
> + * depends on number of shared data pages.
> + *
> + *      3rd level page                2nd level pages            Data pages
> + * +-------------------------+   ┌>+--------------------+ ┌>+------------+
> + * |2nd level page 0 refid   |---┘ |Data page 0 refid   |-┘ |Data page 0 |
> + * |2nd level page 1 refid   |---┐ |Data page 1 refid   |-┐ +------------+
> + * |           ...           |   | |     ....           | |
> + * |2nd level page 1023 refid|-┐ | |Data page 1023 refid| └>+------------+
> + * +-------------------------+ | | +--------------------+   |Data page 1 |
> + *                             | |                          +------------+
> + *                             | └>+--------------------+
> + *                             |   |Data page 1024 refid|
> + *                             |   |Data page 1025 refid|
> + *                             |   |       ...          |
> + *                             |   |Data page 2047 refid|
> + *                             |   +--------------------+
> + *                             |
> + *                             |        .....
> + *                             └-->+-----------------------+
> + *                                 |Data page 1047552 refid|
> + *                                 |Data page 1047553 refid|
> + *                                 |       ...             |
> + *                                 |Data page 1048575 refid|
> + *                                 +-----------------------+
> + *
> + * Using such 2 level structure it is possible to reference up to 4GB of
> + * shared data using single refid pointing to top level page.
> + *
> + * Returns refid of top level page.
> + */
This seems to be over-engineered, IMO
> +int xen_be_share_pages(struct page **pages, int domid, int nents,
> +		       void **refs_info)
> +{
> +	grant_ref_t lvl3_gref;
> +	grant_ref_t *lvl2_table;
> +	grant_ref_t *lvl3_table;
> +
> +	/*
> +	 * Calculate number of pages needed for 2nd level addresing:
> +	 */
> +	int n_lvl2_grefs = (nents/REFS_PER_PAGE +
> +			   ((nents % REFS_PER_PAGE) ? 1 : 0));
> +
> +	struct xen_shared_pages_info *sh_pages_info;
> +	int i;
> +
> +	lvl3_table = (grant_ref_t *)__get_free_pages(GFP_KERNEL, 1);
> +	lvl2_table = (grant_ref_t *)__get_free_pages(GFP_KERNEL, n_lvl2_grefs);
> +
> +	sh_pages_info = kmalloc(sizeof(*sh_pages_info), GFP_KERNEL);
> +
> +	if (!sh_pages_info)
> +		return -ENOMEM;
> +
> +	*refs_info = (void *)sh_pages_info;
> +
> +	/* share data pages in readonly mode for security */
> +	for (i = 0; i < nents; i++) {
> +		lvl2_table[i] = gnttab_grant_foreign_access(domid,
> +					pfn_to_mfn(page_to_pfn(pages[i])),
> +					true /* read only */);
> +		if (lvl2_table[i] == -ENOSPC) {
> +			dev_err(hy_drv_priv->dev,
> +				"No more space left in grant table\n");
> +
> +			/* Unshare all already shared pages for lvl2 */
> +			while (i--) {
> +				gnttab_end_foreign_access_ref(lvl2_table[i], 0);
> +				gnttab_free_grant_reference(lvl2_table[i]);
> +			}
> +			goto err_cleanup;
> +		}
> +	}
> +
> +	/* Share 2nd level addressing pages in readonly mode*/
> +	for (i = 0; i < n_lvl2_grefs; i++) {
> +		lvl3_table[i] = gnttab_grant_foreign_access(domid,
> +					virt_to_mfn(
> +					(unsigned long)lvl2_table+i*PAGE_SIZE),
> +					true);
> +
> +		if (lvl3_table[i] == -ENOSPC) {
> +			dev_err(hy_drv_priv->dev,
> +				"No more space left in grant table\n");
> +
> +			/* Unshare all already shared pages for lvl3 */
> +			while (i--) {
> +				gnttab_end_foreign_access_ref(lvl3_table[i], 1);
> +				gnttab_free_grant_reference(lvl3_table[i]);
> +			}
> +
> +			/* Unshare all pages for lvl2 */
> +			while (nents--) {
> +				gnttab_end_foreign_access_ref(
> +							lvl2_table[nents], 0);
> +				gnttab_free_grant_reference(lvl2_table[nents]);
> +			}
> +
> +			goto err_cleanup;
> +		}
> +	}
> +
> +	/* Share lvl3_table in readonly mode*/
> +	lvl3_gref = gnttab_grant_foreign_access(domid,
> +			virt_to_mfn((unsigned long)lvl3_table),
> +			true);
> +
> +	if (lvl3_gref == -ENOSPC) {
> +		dev_err(hy_drv_priv->dev,
> +			"No more space left in grant table\n");
> +
> +		/* Unshare all pages for lvl3 */
> +		while (i--) {
> +			gnttab_end_foreign_access_ref(lvl3_table[i], 1);
> +			gnttab_free_grant_reference(lvl3_table[i]);
> +		}
> +
> +		/* Unshare all pages for lvl2 */
> +		while (nents--) {
> +			gnttab_end_foreign_access_ref(lvl2_table[nents], 0);
> +			gnttab_free_grant_reference(lvl2_table[nents]);
> +		}
> +
> +		goto err_cleanup;
> +	}
> +
> +	/* Store lvl3_table page to be freed later */
> +	sh_pages_info->lvl3_table = lvl3_table;
> +
> +	/* Store lvl2_table pages to be freed later */
> +	sh_pages_info->lvl2_table = lvl2_table;
> +
> +
> +	/* Store exported pages refid to be unshared later */
> +	sh_pages_info->lvl3_gref = lvl3_gref;
> +
> +	dev_dbg(hy_drv_priv->dev, "%s exit\n", __func__);
> +	return lvl3_gref;
> +
> +err_cleanup:
> +	free_pages((unsigned long)lvl2_table, n_lvl2_grefs);
> +	free_pages((unsigned long)lvl3_table, 1);
> +
> +	return -ENOSPC;
> +}
> +
> +int xen_be_unshare_pages(void **refs_info, int nents)
> +{
> +	struct xen_shared_pages_info *sh_pages_info;
> +	int n_lvl2_grefs = (nents/REFS_PER_PAGE +
> +			    ((nents % REFS_PER_PAGE) ? 1 : 0));
> +	int i;
> +
> +	dev_dbg(hy_drv_priv->dev, "%s entry\n", __func__);
> +	sh_pages_info = (struct xen_shared_pages_info *)(*refs_info);
> +
> +	if (sh_pages_info->lvl3_table == NULL ||
> +	    sh_pages_info->lvl2_table ==  NULL ||
> +	    sh_pages_info->lvl3_gref == -1) {
> +		dev_warn(hy_drv_priv->dev,
> +			 "gref table for hyper_dmabuf already cleaned up\n");
> +		return 0;
> +	}
> +
> +	/* End foreign access for data pages, but do not free them */
> +	for (i = 0; i < nents; i++) {
> +		if (gnttab_query_foreign_access(sh_pages_info->lvl2_table[i]))
> +			dev_warn(hy_drv_priv->dev, "refid not shared !!\n");
> +
> +		gnttab_end_foreign_access_ref(sh_pages_info->lvl2_table[i], 0);
> +		gnttab_free_grant_reference(sh_pages_info->lvl2_table[i]);
> +	}
> +
> +	/* End foreign access for 2nd level addressing pages */
> +	for (i = 0; i < n_lvl2_grefs; i++) {
> +		if (gnttab_query_foreign_access(sh_pages_info->lvl3_table[i]))
> +			dev_warn(hy_drv_priv->dev, "refid not shared !!\n");
> +
> +		if (!gnttab_end_foreign_access_ref(
> +					sh_pages_info->lvl3_table[i], 1))
> +			dev_warn(hy_drv_priv->dev, "refid still in use!!!\n");
> +
> +		gnttab_free_grant_reference(sh_pages_info->lvl3_table[i]);
> +	}
> +
> +	/* End foreign access for top level addressing page */
> +	if (gnttab_query_foreign_access(sh_pages_info->lvl3_gref))
> +		dev_warn(hy_drv_priv->dev, "gref not shared !!\n");
> +
> +	gnttab_end_foreign_access_ref(sh_pages_info->lvl3_gref, 1);
> +	gnttab_free_grant_reference(sh_pages_info->lvl3_gref);
> +
> +	/* freeing all pages used for 2 level addressing */
> +	free_pages((unsigned long)sh_pages_info->lvl2_table, n_lvl2_grefs);
> +	free_pages((unsigned long)sh_pages_info->lvl3_table, 1);
> +
> +	sh_pages_info->lvl3_gref = -1;
> +	sh_pages_info->lvl2_table = NULL;
> +	sh_pages_info->lvl3_table = NULL;
> +	kfree(sh_pages_info);
> +	sh_pages_info = NULL;
> +
> +	dev_dbg(hy_drv_priv->dev, "%s exit\n", __func__);
> +	return 0;
> +}
> +
> +/* Maps provided top level ref id and then return array of pages
> + * containing data refs.
> + */
> +struct page **xen_be_map_shared_pages(unsigned long lvl3_gref, int domid,
> +				      int nents, void **refs_info)
> +{
> +	struct page *lvl3_table_page;
> +	struct page **lvl2_table_pages;
> +	struct page **data_pages;
> +	struct xen_shared_pages_info *sh_pages_info;
> +
> +	grant_ref_t *lvl3_table;
> +	grant_ref_t *lvl2_table;
> +
> +	struct gnttab_map_grant_ref lvl3_map_ops;
> +	struct gnttab_unmap_grant_ref lvl3_unmap_ops;
> +
> +	struct gnttab_map_grant_ref *lvl2_map_ops;
> +	struct gnttab_unmap_grant_ref *lvl2_unmap_ops;
> +
> +	struct gnttab_map_grant_ref *data_map_ops;
> +	struct gnttab_unmap_grant_ref *data_unmap_ops;
> +
> +	/* # of grefs in the last page of lvl2 table */
> +	int nents_last = (nents - 1) % REFS_PER_PAGE + 1;
> +	int n_lvl2_grefs = (nents / REFS_PER_PAGE) +
> +			   ((nents_last > 0) ? 1 : 0) -
> +			   (nents_last == REFS_PER_PAGE);
> +	int i, j, k;
> +
> +	dev_dbg(hy_drv_priv->dev, "%s entry\n", __func__);
> +
> +	sh_pages_info = kmalloc(sizeof(*sh_pages_info), GFP_KERNEL);
> +	*refs_info = (void *) sh_pages_info;
> +
> +	lvl2_table_pages = kcalloc(n_lvl2_grefs, sizeof(struct page *),
> +				   GFP_KERNEL);
> +
> +	data_pages = kcalloc(nents, sizeof(struct page *), GFP_KERNEL);
> +
> +	lvl2_map_ops = kcalloc(n_lvl2_grefs, sizeof(*lvl2_map_ops),
> +			       GFP_KERNEL);
> +
> +	lvl2_unmap_ops = kcalloc(n_lvl2_grefs, sizeof(*lvl2_unmap_ops),
> +				 GFP_KERNEL);
> +
> +	data_map_ops = kcalloc(nents, sizeof(*data_map_ops), GFP_KERNEL);
> +	data_unmap_ops = kcalloc(nents, sizeof(*data_unmap_ops), GFP_KERNEL);
> +
> +	/* Map top level addressing page */
> +	if (gnttab_alloc_pages(1, &lvl3_table_page)) {
> +		dev_err(hy_drv_priv->dev, "Cannot allocate pages\n");
> +		return NULL;
> +	}
> +
> +	lvl3_table = (grant_ref_t *)pfn_to_kaddr(page_to_pfn(lvl3_table_page));
> +
> +	gnttab_set_map_op(&lvl3_map_ops, (unsigned long)lvl3_table,
> +			  GNTMAP_host_map | GNTMAP_readonly,
> +			  (grant_ref_t)lvl3_gref, domid);
> +
> +	gnttab_set_unmap_op(&lvl3_unmap_ops, (unsigned long)lvl3_table,
> +			    GNTMAP_host_map | GNTMAP_readonly, -1);
> +
> +	if (gnttab_map_refs(&lvl3_map_ops, NULL, &lvl3_table_page, 1)) {
> +		dev_err(hy_drv_priv->dev,
> +			"HYPERVISOR map grant ref failed");
> +		return NULL;
> +	}
> +
> +	if (lvl3_map_ops.status) {
> +		dev_err(hy_drv_priv->dev,
> +			"HYPERVISOR map grant ref failed status = %d",
> +			lvl3_map_ops.status);
> +
> +		goto error_cleanup_lvl3;
> +	} else {
> +		lvl3_unmap_ops.handle = lvl3_map_ops.handle;
> +	}
> +
> +	/* Map all second level pages */
> +	if (gnttab_alloc_pages(n_lvl2_grefs, lvl2_table_pages)) {
> +		dev_err(hy_drv_priv->dev, "Cannot allocate pages\n");
> +		goto error_cleanup_lvl3;
> +	}
> +
> +	for (i = 0; i < n_lvl2_grefs; i++) {
> +		lvl2_table = (grant_ref_t *)pfn_to_kaddr(
> +					page_to_pfn(lvl2_table_pages[i]));
> +		gnttab_set_map_op(&lvl2_map_ops[i],
> +				  (unsigned long)lvl2_table, GNTMAP_host_map |
> +				  GNTMAP_readonly,
> +				  lvl3_table[i], domid);
> +		gnttab_set_unmap_op(&lvl2_unmap_ops[i],
> +				    (unsigned long)lvl2_table, GNTMAP_host_map |
> +				    GNTMAP_readonly, -1);
> +	}
> +
> +	/* Unmap top level page, as it won't be needed any longer */
> +	if (gnttab_unmap_refs(&lvl3_unmap_ops, NULL,
> +			      &lvl3_table_page, 1)) {
> +		dev_err(hy_drv_priv->dev,
> +			"xen: cannot unmap top level page\n");
> +		return NULL;
> +	}
> +
> +	/* Mark that page was unmapped */
> +	lvl3_unmap_ops.handle = -1;
> +
> +	if (gnttab_map_refs(lvl2_map_ops, NULL,
> +			    lvl2_table_pages, n_lvl2_grefs)) {
> +		dev_err(hy_drv_priv->dev,
> +			"HYPERVISOR map grant ref failed");
> +		return NULL;
> +	}
> +
> +	/* Checks if pages were mapped correctly */
> +	for (i = 0; i < n_lvl2_grefs; i++) {
> +		if (lvl2_map_ops[i].status) {
> +			dev_err(hy_drv_priv->dev,
> +				"HYPERVISOR map grant ref failed status = %d",
> +				lvl2_map_ops[i].status);
> +			goto error_cleanup_lvl2;
> +		} else {
> +			lvl2_unmap_ops[i].handle = lvl2_map_ops[i].handle;
> +		}
> +	}
> +
> +	if (gnttab_alloc_pages(nents, data_pages)) {
> +		dev_err(hy_drv_priv->dev,
> +			"Cannot allocate pages\n");
> +		goto error_cleanup_lvl2;
> +	}
> +
> +	k = 0;
> +
> +	for (i = 0; i < n_lvl2_grefs - 1; i++) {
> +		lvl2_table = pfn_to_kaddr(page_to_pfn(lvl2_table_pages[i]));
> +		for (j = 0; j < REFS_PER_PAGE; j++) {
> +			gnttab_set_map_op(&data_map_ops[k],
> +				(unsigned long)pfn_to_kaddr(
> +						page_to_pfn(data_pages[k])),
> +				GNTMAP_host_map | GNTMAP_readonly,
> +				lvl2_table[j], domid);
> +
> +			gnttab_set_unmap_op(&data_unmap_ops[k],
> +				(unsigned long)pfn_to_kaddr(
> +						page_to_pfn(data_pages[k])),
> +				GNTMAP_host_map | GNTMAP_readonly, -1);
> +			k++;
> +		}
> +	}
> +
> +	/* for grefs in the last lvl2 table page */
> +	lvl2_table = pfn_to_kaddr(page_to_pfn(
> +				lvl2_table_pages[n_lvl2_grefs - 1]));
> +
> +	for (j = 0; j < nents_last; j++) {
> +		gnttab_set_map_op(&data_map_ops[k],
> +			(unsigned long)pfn_to_kaddr(page_to_pfn(data_pages[k])),
> +			GNTMAP_host_map | GNTMAP_readonly,
> +			lvl2_table[j], domid);
> +
> +		gnttab_set_unmap_op(&data_unmap_ops[k],
> +			(unsigned long)pfn_to_kaddr(page_to_pfn(data_pages[k])),
> +			GNTMAP_host_map | GNTMAP_readonly, -1);
> +		k++;
> +	}
> +
> +	if (gnttab_map_refs(data_map_ops, NULL,
> +			    data_pages, nents)) {
> +		dev_err(hy_drv_priv->dev,
> +			"HYPERVISOR map grant ref failed\n");
> +		return NULL;
> +	}
> +
> +	/* unmapping lvl2 table pages */
> +	if (gnttab_unmap_refs(lvl2_unmap_ops,
> +			      NULL, lvl2_table_pages,
> +			      n_lvl2_grefs)) {
> +		dev_err(hy_drv_priv->dev,
> +			"Cannot unmap 2nd level refs\n");
> +		return NULL;
> +	}
> +
> +	/* Mark that pages were unmapped */
> +	for (i = 0; i < n_lvl2_grefs; i++)
> +		lvl2_unmap_ops[i].handle = -1;
> +
> +	for (i = 0; i < nents; i++) {
> +		if (data_map_ops[i].status) {
> +			dev_err(hy_drv_priv->dev,
> +				"HYPERVISOR map grant ref failed status = %d\n",
> +				data_map_ops[i].status);
> +			goto error_cleanup_data;
> +		} else {
> +			data_unmap_ops[i].handle = data_map_ops[i].handle;
> +		}
> +	}
> +
> +	/* store these references for unmapping in the future */
> +	sh_pages_info->unmap_ops = data_unmap_ops;
> +	sh_pages_info->data_pages = data_pages;
> +
> +	gnttab_free_pages(1, &lvl3_table_page);
> +	gnttab_free_pages(n_lvl2_grefs, lvl2_table_pages);
> +	kfree(lvl2_table_pages);
> +	kfree(lvl2_map_ops);
> +	kfree(lvl2_unmap_ops);
> +	kfree(data_map_ops);
> +
> +	dev_dbg(hy_drv_priv->dev, "%s exit\n", __func__);
> +	return data_pages;
> +
> +error_cleanup_data:
> +	gnttab_unmap_refs(data_unmap_ops, NULL, data_pages,
> +			  nents);
> +
> +	gnttab_free_pages(nents, data_pages);
> +
> +error_cleanup_lvl2:
> +	if (lvl2_unmap_ops[0].handle != -1)
> +		gnttab_unmap_refs(lvl2_unmap_ops, NULL,
> +				  lvl2_table_pages, n_lvl2_grefs);
> +	gnttab_free_pages(n_lvl2_grefs, lvl2_table_pages);
> +
> +error_cleanup_lvl3:
> +	if (lvl3_unmap_ops.handle != -1)
> +		gnttab_unmap_refs(&lvl3_unmap_ops, NULL,
> +				  &lvl3_table_page, 1);
> +	gnttab_free_pages(1, &lvl3_table_page);
> +
> +	kfree(lvl2_table_pages);
> +	kfree(lvl2_map_ops);
> +	kfree(lvl2_unmap_ops);
> +	kfree(data_map_ops);
> +
> +
> +	return NULL;
> +}
> +
> +int xen_be_unmap_shared_pages(void **refs_info, int nents)
> +{
> +	struct xen_shared_pages_info *sh_pages_info;
> +
> +	dev_dbg(hy_drv_priv->dev, "%s entry\n", __func__);
> +
> +	sh_pages_info = (struct xen_shared_pages_info *)(*refs_info);
> +
> +	if (sh_pages_info->unmap_ops == NULL ||
> +	    sh_pages_info->data_pages == NULL) {
> +		dev_warn(hy_drv_priv->dev,
> +			 "pages already cleaned up or buffer not imported yet\n");
> +		return 0;
> +	}
> +
> +	if (gnttab_unmap_refs(sh_pages_info->unmap_ops, NULL,
> +			      sh_pages_info->data_pages, nents)) {
> +		dev_err(hy_drv_priv->dev, "Cannot unmap data pages\n");
> +		return -EFAULT;
> +	}
> +
> +	gnttab_free_pages(nents, sh_pages_info->data_pages);
> +
> +	kfree(sh_pages_info->data_pages);
> +	kfree(sh_pages_info->unmap_ops);
> +	sh_pages_info->unmap_ops = NULL;
> +	sh_pages_info->data_pages = NULL;
> +	kfree(sh_pages_info);
> +	sh_pages_info = NULL;
> +
> +	dev_dbg(hy_drv_priv->dev, "%s exit\n", __func__);
> +	return 0;
> +}
> diff --git a/drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_shm.h b/drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_shm.h
> new file mode 100644
> index 000000000000..c39f241351f8
> --- /dev/null
> +++ b/drivers/dma-buf/hyper_dmabuf/backends/xen/hyper_dmabuf_xen_shm.h
> @@ -0,0 +1,46 @@
> +/*
> + * Copyright © 2018 Intel Corporation
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + */
> +
> +#ifndef __HYPER_DMABUF_XEN_SHM_H__
> +#define __HYPER_DMABUF_XEN_SHM_H__
> +
> +/* This collects all reference numbers for 2nd level shared pages and
> + * create a table with those in 1st level shared pages then return reference
> + * numbers for this top level table.
> + */
> +int xen_be_share_pages(struct page **pages, int domid, int nents,
> +		    void **refs_info);
> +
> +int xen_be_unshare_pages(void **refs_info, int nents);
> +
> +/* Maps provided top level ref id and then return array of pages containing
> + * data refs.
> + */
> +struct page **xen_be_map_shared_pages(unsigned long lvl3_gref, int domid,
> +				      int nents,
> +				      void **refs_info);
> +
> +int xen_be_unmap_shared_pages(void **refs_info, int nents);
> +
> +#endif /* __HYPER_DMABUF_XEN_SHM_H__ */
> diff --git a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_drv.c b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_drv.c
> index 18c1cd735ea2..3320f9dcc769 100644
> --- a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_drv.c
> +++ b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_drv.c
> @@ -42,6 +42,10 @@
>   #include "hyper_dmabuf_list.h"
>   #include "hyper_dmabuf_id.h"
>   
> +#ifdef CONFIG_HYPER_DMABUF_XEN
> +#include "backends/xen/hyper_dmabuf_xen_drv.h"
> +#endif
> +
>   MODULE_LICENSE("GPL and additional rights");
>   MODULE_AUTHOR("Intel Corporation");
>   
> @@ -145,7 +149,13 @@ static int __init hyper_dmabuf_drv_init(void)
>   		return ret;
>   	}
>   
> +/* currently only supports XEN hypervisor */
> +#ifdef CONFIG_HYPER_DMABUF_XEN
> +	hy_drv_priv->bknd_ops = &xen_bknd_ops;
> +#else
>   	hy_drv_priv->bknd_ops = NULL;
> +	pr_err("hyper_dmabuf drv currently supports XEN only.\n");
> +#endif
>   
>   	if (hy_drv_priv->bknd_ops == NULL) {
>   		pr_err("Hyper_dmabuf: no backend found\n");
>

  parent reply	other threads:[~2018-04-10  9:27 UTC|newest]

Thread overview: 57+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-02-14  1:49 [RFC PATCH v2 0/9] hyper_dmabuf: Hyper_DMABUF driver Dongwon Kim
2018-02-14  1:49 ` Dongwon Kim
2018-02-14  1:50 ` [RFC PATCH v2 1/9] hyper_dmabuf: initial upload of hyper_dmabuf drv core framework Dongwon Kim
2018-02-14  1:50   ` Dongwon Kim
2018-04-10  8:53   ` [RFC, v2, " Oleksandr Andrushchenko
2018-04-10 10:47     ` [Xen-devel] " Julien Grall
2018-04-10 11:04       ` Oleksandr Andrushchenko
2018-04-10 11:04         ` Oleksandr Andrushchenko
2018-04-10 11:04       ` Oleksandr Andrushchenko
2018-04-10 10:47     ` Julien Grall
2018-04-10  8:53   ` Oleksandr Andrushchenko
2018-02-14  1:50 ` [RFC PATCH v2 " Dongwon Kim
2018-02-14  1:50 ` [RFC PATCH v2 2/9] hyper_dmabuf: architecture specification and reference guide Dongwon Kim
2018-02-14  1:50   ` Dongwon Kim
2018-02-23 16:15   ` [Xen-devel] " Roger Pau Monné
2018-02-23 16:15     ` Roger Pau Monné
2018-02-23 19:02     ` Dongwon Kim
2018-02-23 19:02     ` [Xen-devel] " Dongwon Kim
2018-02-23 19:02       ` Dongwon Kim
2018-04-10  9:52   ` [RFC, v2, " Oleksandr Andrushchenko
2018-04-10  9:52     ` Oleksandr Andrushchenko
2018-04-10  9:52   ` Oleksandr Andrushchenko
2018-02-14  1:50 ` [RFC PATCH v2 " Dongwon Kim
2018-02-14  1:50 ` [RFC PATCH v2 3/9] MAINTAINERS: adding Hyper_DMABUF driver section in MAINTAINERS Dongwon Kim
2018-02-14  1:50 ` Dongwon Kim
2018-02-14  1:50   ` Dongwon Kim
2018-02-14  1:50 ` [RFC PATCH v2 4/9] hyper_dmabuf: user private data attached to hyper_DMABUF Dongwon Kim
2018-02-14  1:50   ` Dongwon Kim
2018-04-10  9:59   ` [RFC, v2, " Oleksandr Andrushchenko
2018-04-10  9:59     ` Oleksandr Andrushchenko
2018-04-10  9:59   ` Oleksandr Andrushchenko
2018-02-14  1:50 ` [RFC PATCH v2 " Dongwon Kim
2018-02-14  1:50 ` [RFC PATCH v2 5/9] hyper_dmabuf: default backend for XEN hypervisor Dongwon Kim
2018-02-14  1:50   ` Dongwon Kim
2018-04-10  9:27   ` [RFC, v2, " Oleksandr Andrushchenko
2018-04-10  9:27   ` Oleksandr Andrushchenko [this message]
2018-02-14  1:50 ` [RFC PATCH v2 " Dongwon Kim
2018-02-14  1:50 ` [RFC PATCH v2 6/9] hyper_dmabuf: hyper_DMABUF synchronization across VM Dongwon Kim
2018-02-14  1:50   ` Dongwon Kim
2018-02-14  1:50 ` Dongwon Kim
2018-02-14  1:50 ` [RFC PATCH v2 7/9] hyper_dmabuf: query ioctl for retreiving various hyper_DMABUF info Dongwon Kim
2018-02-14  1:50 ` Dongwon Kim
2018-02-14  1:50   ` Dongwon Kim
2018-02-14  1:50 ` [RFC PATCH v2 8/9] hyper_dmabuf: event-polling mechanism for detecting a new hyper_DMABUF Dongwon Kim
2018-02-14  1:50 ` Dongwon Kim
2018-02-14  1:50   ` Dongwon Kim
2018-02-14  1:50 ` [RFC PATCH v2 9/9] hyper_dmabuf: threaded interrupt in Xen-backend Dongwon Kim
2018-02-14  1:50   ` Dongwon Kim
2018-04-10 10:04   ` [RFC, v2, " Oleksandr Andrushchenko
2018-04-10 10:04   ` [RFC,v2,9/9] " Oleksandr Andrushchenko
2018-02-14  1:50 ` [RFC PATCH v2 9/9] " Dongwon Kim
2018-02-19 17:01 ` [RFC PATCH v2 0/9] hyper_dmabuf: Hyper_DMABUF driver Daniel Vetter
2018-02-19 17:01   ` Daniel Vetter
2018-02-21 20:18   ` Dongwon Kim
2018-02-21 20:18   ` Dongwon Kim
2018-02-21 20:18     ` Dongwon Kim
2018-02-19 17:01 ` Daniel Vetter

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=590a9e6f-1e04-c832-5fd4-107af94d1ef7@gmail.com \
    --to=andr2000@gmail.com \
    --cc=dongwon.kim@intel.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=linaro-mm-sig@lists.linaro.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mateuszx.potrola@intel.com \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.