[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [RFC PATCH v2 5/9] hyper_dmabuf: default backend for XEN hypervisor



From: "Matuesz Polrola" <mateuszx.potrola@xxxxxxxxx>

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@xxxxxxxxx>
Signed-off-by: Mateusz Polrola <mateuszx.potrola@xxxxxxxxx>
---
 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
+        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@xxxxxxxxx>
+ *    Mateusz Polrola <mateuszx.potrola@xxxxxxxxx>
+ *
+ */
+
+#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;
+
+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);
+
+       return xenbus_mkdir(XBT_NIL, buf, "");
+}
+
+/* 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
+ * 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,
+                       "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);
+
+       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);
+
+       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
+        */
+       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);
+
+               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));
+               } 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.
+ *
+ * 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);
+       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);
+               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);
+
+       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);
+}
+
+/* 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;
+       }
+
+       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");
+
+       /* 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--;
+       }
+
+       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
+                */
+               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@xxxxxxxxx>
+ *    Mateusz Polrola <mateuszx.potrola@xxxxxxxxx>
+ *
+ */
+
+#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@xxxxxxxxx>
+ *    Mateusz Polrola <mateuszx.potrola@xxxxxxxxx>
+ *
+ */
+
+#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@xxxxxxxxx>
+ *    Mateusz Polrola <mateuszx.potrola@xxxxxxxxx>
+ *
+ */
+
+#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.
+ */
+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");
-- 
2.16.1


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.