lkml.org 
[lkml]   [2018]   [Apr]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
SubjectRe: [RFC,v2,5/9] hyper_dmabuf: default backend for XEN hypervisor
From
Date
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");
>

\
 
 \ /
  Last update: 2018-04-10 11:28    [W:0.577 / U:0.404 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site