All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dongwon Kim <dongwon.kim@intel.com>
To: linux-kernel@vger.kernel.org, linaro-mm-sig@lists.linaro.org,
	xen-devel@lists.xenproject.org
Cc: dri-devel@lists.freedesktop.org, dongwon.kim@intel.com,
	mateuszx.potrola@intel.com, sumit.semwal@linaro.org
Subject: [RFC PATCH v2 6/9] hyper_dmabuf: hyper_DMABUF synchronization across VM
Date: Tue, 13 Feb 2018 17:50:05 -0800	[thread overview]
Message-ID: <20180214015008.9513-7-dongwon.kim@intel.com> (raw)
In-Reply-To: <20180214015008.9513-1-dongwon.kim@intel.com>

All of hyper_DMABUF operations now (hyper_dmabuf_ops.c) send a message
to the exporting VM for synchronization between two VMs. For this, every
mapping done by importer will make exporter perform shadow mapping of
original DMA-BUF. Then all consecutive DMA-BUF operations (attach, detach,
map/unmap and so on) will be mimicked on this shadowed DMA-BUF for tracking
and synchronization purpose (e.g. +-reference count to check the status).

Signed-off-by: Dongwon Kim <dongwon.kim@intel.com>
Signed-off-by: Mateusz Polrola <mateuszx.potrola@intel.com>
---
 drivers/dma-buf/hyper_dmabuf/Makefile              |   1 +
 drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_msg.c    |  53 +++-
 drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_msg.h    |   2 +
 drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_ops.c    | 157 +++++++++-
 .../hyper_dmabuf/hyper_dmabuf_remote_sync.c        | 324 +++++++++++++++++++++
 .../hyper_dmabuf/hyper_dmabuf_remote_sync.h        |  32 ++
 6 files changed, 565 insertions(+), 4 deletions(-)
 create mode 100644 drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_remote_sync.c
 create mode 100644 drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_remote_sync.h

diff --git a/drivers/dma-buf/hyper_dmabuf/Makefile b/drivers/dma-buf/hyper_dmabuf/Makefile
index b9ab4eeca6f2..702696f29215 100644
--- a/drivers/dma-buf/hyper_dmabuf/Makefile
+++ b/drivers/dma-buf/hyper_dmabuf/Makefile
@@ -9,6 +9,7 @@ ifneq ($(KERNELRELEASE),)
 				 hyper_dmabuf_ops.o \
 				 hyper_dmabuf_msg.o \
 				 hyper_dmabuf_id.o \
+				 hyper_dmabuf_remote_sync.o \
 
 ifeq ($(CONFIG_HYPER_DMABUF_XEN), y)
 	$(TARGET_MODULE)-objs += backends/xen/hyper_dmabuf_xen_comm.o \
diff --git a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_msg.c b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_msg.c
index 7176fa8fb139..1592d5cfaa52 100644
--- a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_msg.c
+++ b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_msg.c
@@ -34,6 +34,7 @@
 #include <linux/workqueue.h>
 #include "hyper_dmabuf_drv.h"
 #include "hyper_dmabuf_msg.h"
+#include "hyper_dmabuf_remote_sync.h"
 #include "hyper_dmabuf_list.h"
 
 struct cmd_process {
@@ -92,6 +93,25 @@ void hyper_dmabuf_create_req(struct hyper_dmabuf_req *req,
 			req->op[i] = op[i];
 		break;
 
+	case HYPER_DMABUF_OPS_TO_REMOTE:
+		/* notifying dmabuf map/unmap to importer (probably not needed)
+		 * for dmabuf synchronization
+		 */
+		break;
+
+	case HYPER_DMABUF_OPS_TO_SOURCE:
+		/* notifying dmabuf map/unmap to exporter, map will make
+		 * the driver to do shadow mapping or unmapping for
+		 * synchronization with original exporter (e.g. i915)
+		 *
+		 * command : DMABUF_OPS_TO_SOURCE.
+		 * op0~3 : hyper_dmabuf_id
+		 * op4 : map(=1)/unmap(=2)/attach(=3)/detach(=4)
+		 */
+		for (i = 0; i < 5; i++)
+			req->op[i] = op[i];
+		break;
+
 	default:
 		/* no command found */
 		return;
@@ -201,6 +221,12 @@ static void cmd_process_work(struct work_struct *work)
 
 		break;
 
+	case HYPER_DMABUF_OPS_TO_REMOTE:
+		/* notifying dmabuf map/unmap to importer
+		 * (probably not needed) for dmabuf synchronization
+		 */
+		break;
+
 	default:
 		/* shouldn't get here */
 		break;
@@ -217,6 +243,7 @@ int hyper_dmabuf_msg_parse(int domid, struct hyper_dmabuf_req *req)
 	struct imported_sgt_info *imported;
 	struct exported_sgt_info *exported;
 	hyper_dmabuf_id_t hid;
+	int ret;
 
 	if (!req) {
 		dev_err(hy_drv_priv->dev, "request is NULL\n");
@@ -229,7 +256,7 @@ int hyper_dmabuf_msg_parse(int domid, struct hyper_dmabuf_req *req)
 	hid.rng_key[2] = req->op[3];
 
 	if ((req->cmd < HYPER_DMABUF_EXPORT) ||
-		(req->cmd > HYPER_DMABUF_NOTIFY_UNEXPORT)) {
+		(req->cmd > HYPER_DMABUF_OPS_TO_SOURCE)) {
 		dev_err(hy_drv_priv->dev, "invalid command\n");
 		return -EINVAL;
 	}
@@ -271,6 +298,30 @@ int hyper_dmabuf_msg_parse(int domid, struct hyper_dmabuf_req *req)
 		return req->cmd;
 	}
 
+	/* dma buf remote synchronization */
+	if (req->cmd == HYPER_DMABUF_OPS_TO_SOURCE) {
+		/* notifying dmabuf map/unmap to exporter, map will
+		 * make the driver to do shadow mapping
+		 * or unmapping for synchronization with original
+		 * exporter (e.g. i915)
+		 *
+		 * command : DMABUF_OPS_TO_SOURCE.
+		 * op0~3 : hyper_dmabuf_id
+		 * op1 : enum hyper_dmabuf_ops {....}
+		 */
+		dev_dbg(hy_drv_priv->dev,
+			"%s: HYPER_DMABUF_OPS_TO_SOURCE\n", __func__);
+
+		ret = hyper_dmabuf_remote_sync(hid, req->op[4]);
+
+		if (ret)
+			req->stat = HYPER_DMABUF_REQ_ERROR;
+		else
+			req->stat = HYPER_DMABUF_REQ_PROCESSED;
+
+		return req->cmd;
+	}
+
 	/* synchronous dma_buf_fd export */
 	if (req->cmd == HYPER_DMABUF_EXPORT_FD) {
 		/* find a corresponding SGT for the id */
diff --git a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_msg.h b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_msg.h
index 63a39d068d69..82d2900d3077 100644
--- a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_msg.h
+++ b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_msg.h
@@ -48,6 +48,8 @@ enum hyper_dmabuf_command {
 	HYPER_DMABUF_EXPORT_FD,
 	HYPER_DMABUF_EXPORT_FD_FAILED,
 	HYPER_DMABUF_NOTIFY_UNEXPORT,
+	HYPER_DMABUF_OPS_TO_REMOTE,
+	HYPER_DMABUF_OPS_TO_SOURCE,
 };
 
 enum hyper_dmabuf_ops {
diff --git a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_ops.c b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_ops.c
index b4d3c2caad73..02d42c099ad9 100644
--- a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_ops.c
+++ b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_ops.c
@@ -51,16 +51,71 @@ static int dmabuf_refcount(struct dma_buf *dma_buf)
 	return -EINVAL;
 }
 
+static int sync_request(hyper_dmabuf_id_t hid, int dmabuf_ops)
+{
+	struct hyper_dmabuf_req *req;
+	struct hyper_dmabuf_bknd_ops *bknd_ops = hy_drv_priv->bknd_ops;
+	int op[5];
+	int i;
+	int ret;
+
+	op[0] = hid.id;
+
+	for (i = 0; i < 3; i++)
+		op[i+1] = hid.rng_key[i];
+
+	op[4] = dmabuf_ops;
+
+	req = kcalloc(1, sizeof(*req), GFP_KERNEL);
+
+	if (!req)
+		return -ENOMEM;
+
+	hyper_dmabuf_create_req(req, HYPER_DMABUF_OPS_TO_SOURCE, &op[0]);
+
+	/* send request and wait for a response */
+	ret = bknd_ops->send_req(HYPER_DMABUF_DOM_ID(hid), req,
+				 WAIT_AFTER_SYNC_REQ);
+
+	if (ret < 0) {
+		dev_dbg(hy_drv_priv->dev,
+			"dmabuf sync request failed:%d\n", req->op[4]);
+	}
+
+	kfree(req);
+
+	return ret;
+}
+
 static int hyper_dmabuf_ops_attach(struct dma_buf *dmabuf,
 				   struct device *dev,
 				   struct dma_buf_attachment *attach)
 {
-	return 0;
+	struct imported_sgt_info *imported;
+	int ret;
+
+	if (!attach->dmabuf->priv)
+		return -EINVAL;
+
+	imported = (struct imported_sgt_info *)attach->dmabuf->priv;
+
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_ATTACH);
+
+	return ret;
 }
 
 static void hyper_dmabuf_ops_detach(struct dma_buf *dmabuf,
 				    struct dma_buf_attachment *attach)
 {
+	struct imported_sgt_info *imported;
+	int ret;
+
+	if (!attach->dmabuf->priv)
+		return;
+
+	imported = (struct imported_sgt_info *)attach->dmabuf->priv;
+
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_DETACH);
 }
 
 static struct sg_table *hyper_dmabuf_ops_map(
@@ -70,6 +125,7 @@ static struct sg_table *hyper_dmabuf_ops_map(
 	struct sg_table *st;
 	struct imported_sgt_info *imported;
 	struct pages_info *pg_info;
+	int ret;
 
 	if (!attachment->dmabuf->priv)
 		return NULL;
@@ -91,6 +147,8 @@ static struct sg_table *hyper_dmabuf_ops_map(
 	if (!dma_map_sg(attachment->dev, st->sgl, st->nents, dir))
 		goto err_free_sg;
 
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_MAP);
+
 	kfree(pg_info->pgs);
 	kfree(pg_info);
 
@@ -113,6 +171,7 @@ static void hyper_dmabuf_ops_unmap(struct dma_buf_attachment *attachment,
 				   enum dma_data_direction dir)
 {
 	struct imported_sgt_info *imported;
+	int ret;
 
 	if (!attachment->dmabuf->priv)
 		return;
@@ -123,12 +182,15 @@ static void hyper_dmabuf_ops_unmap(struct dma_buf_attachment *attachment,
 
 	sg_free_table(sg);
 	kfree(sg);
+
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_UNMAP);
 }
 
 static void hyper_dmabuf_ops_release(struct dma_buf *dma_buf)
 {
 	struct imported_sgt_info *imported;
 	struct hyper_dmabuf_bknd_ops *bknd_ops = hy_drv_priv->bknd_ops;
+	int ret;
 	int finish;
 
 	if (!dma_buf->priv)
@@ -155,6 +217,8 @@ static void hyper_dmabuf_ops_release(struct dma_buf *dma_buf)
 	finish = imported && !imported->valid &&
 		 !imported->importers;
 
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_RELEASE);
+
 	/*
 	 * Check if buffer is still valid and if not remove it
 	 * from imported list. That has to be done after sending
@@ -169,18 +233,48 @@ static void hyper_dmabuf_ops_release(struct dma_buf *dma_buf)
 static int hyper_dmabuf_ops_begin_cpu_access(struct dma_buf *dmabuf,
 					     enum dma_data_direction dir)
 {
-	return 0;
+	struct imported_sgt_info *imported;
+	int ret;
+
+	if (!dmabuf->priv)
+		return -EINVAL;
+
+	imported = (struct imported_sgt_info *)dmabuf->priv;
+
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_BEGIN_CPU_ACCESS);
+
+	return ret;
 }
 
 static int hyper_dmabuf_ops_end_cpu_access(struct dma_buf *dmabuf,
 					   enum dma_data_direction dir)
 {
+	struct imported_sgt_info *imported;
+	int ret;
+
+	if (!dmabuf->priv)
+		return -EINVAL;
+
+	imported = (struct imported_sgt_info *)dmabuf->priv;
+
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_END_CPU_ACCESS);
+
 	return 0;
 }
 
 static void *hyper_dmabuf_ops_kmap_atomic(struct dma_buf *dmabuf,
 					  unsigned long pgnum)
 {
+	struct imported_sgt_info *imported;
+	int ret;
+
+	if (!dmabuf->priv)
+		return NULL;
+
+	imported = (struct imported_sgt_info *)dmabuf->priv;
+
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_KMAP_ATOMIC);
+
 	/* TODO: NULL for now. Need to return the addr of mapped region */
 	return NULL;
 }
@@ -188,10 +282,29 @@ static void *hyper_dmabuf_ops_kmap_atomic(struct dma_buf *dmabuf,
 static void hyper_dmabuf_ops_kunmap_atomic(struct dma_buf *dmabuf,
 					   unsigned long pgnum, void *vaddr)
 {
+	struct imported_sgt_info *imported;
+	int ret;
+
+	if (!dmabuf->priv)
+		return;
+
+	imported = (struct imported_sgt_info *)dmabuf->priv;
+
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_KUNMAP_ATOMIC);
 }
 
 static void *hyper_dmabuf_ops_kmap(struct dma_buf *dmabuf, unsigned long pgnum)
 {
+	struct imported_sgt_info *imported;
+	int ret;
+
+	if (!dmabuf->priv)
+		return NULL;
+
+	imported = (struct imported_sgt_info *)dmabuf->priv;
+
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_KMAP);
+
 	/* for now NULL.. need to return the address of mapped region */
 	return NULL;
 }
@@ -199,21 +312,59 @@ static void *hyper_dmabuf_ops_kmap(struct dma_buf *dmabuf, unsigned long pgnum)
 static void hyper_dmabuf_ops_kunmap(struct dma_buf *dmabuf, unsigned long pgnum,
 				    void *vaddr)
 {
+	struct imported_sgt_info *imported;
+	int ret;
+
+	if (!dmabuf->priv)
+		return;
+
+	imported = (struct imported_sgt_info *)dmabuf->priv;
+
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_KUNMAP);
 }
 
 static int hyper_dmabuf_ops_mmap(struct dma_buf *dmabuf,
 				 struct vm_area_struct *vma)
 {
-	return 0;
+	struct imported_sgt_info *imported;
+	int ret;
+
+	if (!dmabuf->priv)
+		return -EINVAL;
+
+	imported = (struct imported_sgt_info *)dmabuf->priv;
+
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_MMAP);
+
+	return ret;
 }
 
 static void *hyper_dmabuf_ops_vmap(struct dma_buf *dmabuf)
 {
+	struct imported_sgt_info *imported;
+	int ret;
+
+	if (!dmabuf->priv)
+		return NULL;
+
+	imported = (struct imported_sgt_info *)dmabuf->priv;
+
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_VMAP);
+
 	return NULL;
 }
 
 static void hyper_dmabuf_ops_vunmap(struct dma_buf *dmabuf, void *vaddr)
 {
+	struct imported_sgt_info *imported;
+	int ret;
+
+	if (!dmabuf->priv)
+		return;
+
+	imported = (struct imported_sgt_info *)dmabuf->priv;
+
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_VUNMAP);
 }
 
 static const struct dma_buf_ops hyper_dmabuf_ops = {
diff --git a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_remote_sync.c b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_remote_sync.c
new file mode 100644
index 000000000000..55c2c1828859
--- /dev/null
+++ b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_remote_sync.c
@@ -0,0 +1,324 @@
+/*
+ * 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.
+ *
+ * SPDX-License-Identifier: (MIT OR GPL-2.0)
+ *
+ * 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/dma-buf.h>
+#include "hyper_dmabuf_drv.h"
+#include "hyper_dmabuf_struct.h"
+#include "hyper_dmabuf_list.h"
+#include "hyper_dmabuf_msg.h"
+#include "hyper_dmabuf_id.h"
+#include "hyper_dmabuf_sgl_proc.h"
+
+/* Whenever importer does dma operations from remote domain,
+ * a notification is sent to the exporter so that exporter
+ * issues equivalent dma operation on the original dma buf
+ * for indirect synchronization via shadow operations.
+ *
+ * All ptrs and references (e.g struct sg_table*,
+ * struct dma_buf_attachment) created via these operations on
+ * exporter's side are kept in stack (implemented as circular
+ * linked-lists) separately so that those can be re-referenced
+ * later when unmapping operations are invoked to free those.
+ *
+ * The very first element on the bottom of each stack holds
+ * is what is created when initial exporting is issued so it
+ * should not be modified or released by this fuction.
+ */
+int hyper_dmabuf_remote_sync(hyper_dmabuf_id_t hid, int ops)
+{
+	struct exported_sgt_info *exported;
+	struct sgt_list *sgtl;
+	struct attachment_list *attachl;
+	struct kmap_vaddr_list *va_kmapl;
+	struct vmap_vaddr_list *va_vmapl;
+	int ret;
+
+	/* find a coresponding SGT for the id */
+	exported = hyper_dmabuf_find_exported(hid);
+
+	if (!exported) {
+		dev_err(hy_drv_priv->dev,
+			"dmabuf remote sync::can't find exported list\n");
+		return -ENOENT;
+	}
+
+	switch (ops) {
+	case HYPER_DMABUF_OPS_ATTACH:
+		attachl = kcalloc(1, sizeof(*attachl), GFP_KERNEL);
+
+		if (!attachl)
+			return -ENOMEM;
+
+		attachl->attach = dma_buf_attach(exported->dma_buf,
+						 hy_drv_priv->dev);
+
+		if (!attachl->attach) {
+			kfree(attachl);
+			dev_err(hy_drv_priv->dev,
+				"remote sync::HYPER_DMABUF_OPS_ATTACH\n");
+			return -ENOMEM;
+		}
+
+		list_add(&attachl->list, &exported->active_attached->list);
+		break;
+
+	case HYPER_DMABUF_OPS_DETACH:
+		if (list_empty(&exported->active_attached->list)) {
+			dev_err(hy_drv_priv->dev,
+				"remote sync::HYPER_DMABUF_OPS_DETACH\n");
+			dev_err(hy_drv_priv->dev,
+				"no more dmabuf attachment left to be detached\n");
+			return -EFAULT;
+		}
+
+		attachl = list_first_entry(&exported->active_attached->list,
+					   struct attachment_list, list);
+
+		dma_buf_detach(exported->dma_buf, attachl->attach);
+		list_del(&attachl->list);
+		kfree(attachl);
+		break;
+
+	case HYPER_DMABUF_OPS_MAP:
+		if (list_empty(&exported->active_attached->list)) {
+			dev_err(hy_drv_priv->dev,
+				"remote sync::HYPER_DMABUF_OPS_MAP\n");
+			dev_err(hy_drv_priv->dev,
+				"no more dmabuf attachment left to be mapped\n");
+			return -EFAULT;
+		}
+
+		attachl = list_first_entry(&exported->active_attached->list,
+					   struct attachment_list, list);
+
+		sgtl = kcalloc(1, sizeof(*sgtl), GFP_KERNEL);
+
+		if (!sgtl)
+			return -ENOMEM;
+
+		sgtl->sgt = dma_buf_map_attachment(attachl->attach,
+						   DMA_BIDIRECTIONAL);
+		if (!sgtl->sgt) {
+			kfree(sgtl);
+			dev_err(hy_drv_priv->dev,
+				"remote sync::HYPER_DMABUF_OPS_MAP\n");
+			return -ENOMEM;
+		}
+		list_add(&sgtl->list, &exported->active_sgts->list);
+		break;
+
+	case HYPER_DMABUF_OPS_UNMAP:
+		if (list_empty(&exported->active_sgts->list) ||
+		    list_empty(&exported->active_attached->list)) {
+			dev_err(hy_drv_priv->dev,
+				"remote sync::HYPER_DMABUF_OPS_UNMAP\n");
+			dev_err(hy_drv_priv->dev,
+				"no SGT or attach left to be unmapped\n");
+			return -EFAULT;
+		}
+
+		attachl = list_first_entry(&exported->active_attached->list,
+					   struct attachment_list, list);
+		sgtl = list_first_entry(&exported->active_sgts->list,
+					struct sgt_list, list);
+
+		dma_buf_unmap_attachment(attachl->attach, sgtl->sgt,
+					 DMA_BIDIRECTIONAL);
+		list_del(&sgtl->list);
+		kfree(sgtl);
+		break;
+
+	case HYPER_DMABUF_OPS_RELEASE:
+		dev_dbg(hy_drv_priv->dev,
+			"id:%d key:%d %d %d} released, ref left: %d\n",
+			 exported->hid.id, exported->hid.rng_key[0],
+			 exported->hid.rng_key[1], exported->hid.rng_key[2],
+			 exported->active - 1);
+
+		exported->active--;
+
+		/* If there are still importers just break, if no then
+		 * continue with final cleanup
+		 */
+		if (exported->active)
+			break;
+
+		/* Importer just released buffer fd, check if there is
+		 * any other importer still using it.
+		 * If not and buffer was unexported, clean up shared
+		 * data and remove that buffer.
+		 */
+		dev_dbg(hy_drv_priv->dev,
+			"Buffer {id:%d key:%d %d %d} final released\n",
+			exported->hid.id, exported->hid.rng_key[0],
+			exported->hid.rng_key[1], exported->hid.rng_key[2]);
+
+		if (!exported->valid && !exported->active &&
+		    !exported->unexport_sched) {
+			hyper_dmabuf_cleanup_sgt_info(exported, false);
+			hyper_dmabuf_remove_exported(hid);
+			kfree(exported);
+			/* store hyper_dmabuf_id in the list for reuse */
+			hyper_dmabuf_store_hid(hid);
+		}
+
+		break;
+
+	case HYPER_DMABUF_OPS_BEGIN_CPU_ACCESS:
+		ret = dma_buf_begin_cpu_access(exported->dma_buf,
+					       DMA_BIDIRECTIONAL);
+		if (ret) {
+			dev_err(hy_drv_priv->dev,
+				"HYPER_DMABUF_OPS_BEGIN_CPU_ACCESS\n");
+			return ret;
+		}
+		break;
+
+	case HYPER_DMABUF_OPS_END_CPU_ACCESS:
+		ret = dma_buf_end_cpu_access(exported->dma_buf,
+					     DMA_BIDIRECTIONAL);
+		if (ret) {
+			dev_err(hy_drv_priv->dev,
+				"HYPER_DMABUF_OPS_END_CPU_ACCESS\n");
+			return ret;
+		}
+		break;
+
+	case HYPER_DMABUF_OPS_KMAP_ATOMIC:
+	case HYPER_DMABUF_OPS_KMAP:
+		va_kmapl = kcalloc(1, sizeof(*va_kmapl), GFP_KERNEL);
+		if (!va_kmapl)
+			return -ENOMEM;
+
+		/* dummy kmapping of 1 page */
+		if (ops == HYPER_DMABUF_OPS_KMAP_ATOMIC)
+			va_kmapl->vaddr = dma_buf_kmap_atomic(
+						exported->dma_buf, 1);
+		else
+			va_kmapl->vaddr = dma_buf_kmap(
+						exported->dma_buf, 1);
+
+		if (!va_kmapl->vaddr) {
+			kfree(va_kmapl);
+			dev_err(hy_drv_priv->dev,
+				"HYPER_DMABUF_OPS_KMAP(_ATOMIC)\n");
+			return -ENOMEM;
+		}
+		list_add(&va_kmapl->list, &exported->va_kmapped->list);
+		break;
+
+	case HYPER_DMABUF_OPS_KUNMAP_ATOMIC:
+	case HYPER_DMABUF_OPS_KUNMAP:
+		if (list_empty(&exported->va_kmapped->list)) {
+			dev_err(hy_drv_priv->dev,
+				"HYPER_DMABUF_OPS_KUNMAP(_ATOMIC)\n");
+			dev_err(hy_drv_priv->dev,
+				"no more dmabuf VA to be freed\n");
+			return -EFAULT;
+		}
+
+		va_kmapl = list_first_entry(&exported->va_kmapped->list,
+					    struct kmap_vaddr_list, list);
+		if (!va_kmapl->vaddr) {
+			dev_err(hy_drv_priv->dev,
+				"HYPER_DMABUF_OPS_KUNMAP(_ATOMIC)\n");
+			return PTR_ERR(va_kmapl->vaddr);
+		}
+
+		/* unmapping 1 page */
+		if (ops == HYPER_DMABUF_OPS_KUNMAP_ATOMIC)
+			dma_buf_kunmap_atomic(exported->dma_buf,
+					      1, va_kmapl->vaddr);
+		else
+			dma_buf_kunmap(exported->dma_buf,
+				       1, va_kmapl->vaddr);
+
+		list_del(&va_kmapl->list);
+		kfree(va_kmapl);
+		break;
+
+	case HYPER_DMABUF_OPS_MMAP:
+		/* currently not supported: looking for a way to create
+		 * a dummy vma
+		 */
+		dev_warn(hy_drv_priv->dev,
+			 "remote sync::sychronized mmap is not supported\n");
+		break;
+
+	case HYPER_DMABUF_OPS_VMAP:
+		va_vmapl = kcalloc(1, sizeof(*va_vmapl), GFP_KERNEL);
+
+		if (!va_vmapl)
+			return -ENOMEM;
+
+		/* dummy vmapping */
+		va_vmapl->vaddr = dma_buf_vmap(exported->dma_buf);
+
+		if (!va_vmapl->vaddr) {
+			kfree(va_vmapl);
+			dev_err(hy_drv_priv->dev,
+				"remote sync::HYPER_DMABUF_OPS_VMAP\n");
+			return -ENOMEM;
+		}
+		list_add(&va_vmapl->list, &exported->va_vmapped->list);
+		break;
+
+	case HYPER_DMABUF_OPS_VUNMAP:
+		if (list_empty(&exported->va_vmapped->list)) {
+			dev_err(hy_drv_priv->dev,
+				"remote sync::HYPER_DMABUF_OPS_VUNMAP\n");
+			dev_err(hy_drv_priv->dev,
+				"no more dmabuf VA to be freed\n");
+			return -EFAULT;
+		}
+		va_vmapl = list_first_entry(&exported->va_vmapped->list,
+					struct vmap_vaddr_list, list);
+		if (!va_vmapl || va_vmapl->vaddr == NULL) {
+			dev_err(hy_drv_priv->dev,
+				"remote sync::HYPER_DMABUF_OPS_VUNMAP\n");
+			return -EFAULT;
+		}
+
+		dma_buf_vunmap(exported->dma_buf, va_vmapl->vaddr);
+
+		list_del(&va_vmapl->list);
+		kfree(va_vmapl);
+		break;
+
+	default:
+		/* program should not get here */
+		break;
+	}
+
+	return 0;
+}
diff --git a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_remote_sync.h b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_remote_sync.h
new file mode 100644
index 000000000000..a659c83c8f27
--- /dev/null
+++ b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_remote_sync.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ *
+ * SPDX-License-Identifier: (MIT OR GPL-2.0)
+ *
+ */
+
+#ifndef __HYPER_DMABUF_REMOTE_SYNC_H__
+#define __HYPER_DMABUF_REMOTE_SYNC_H__
+
+int hyper_dmabuf_remote_sync(hyper_dmabuf_id_t hid, int ops);
+
+#endif // __HYPER_DMABUF_REMOTE_SYNC_H__
-- 
2.16.1

WARNING: multiple messages have this Message-ID (diff)
From: Dongwon Kim <dongwon.kim@intel.com>
To: linux-kernel@vger.kernel.org, linaro-mm-sig@lists.linaro.org,
	xen-devel@lists.xenproject.org
Cc: dongwon.kim@intel.com, dri-devel@lists.freedesktop.org,
	mateuszx.potrola@intel.com
Subject: [RFC PATCH v2 6/9] hyper_dmabuf: hyper_DMABUF synchronization across VM
Date: Tue, 13 Feb 2018 17:50:05 -0800	[thread overview]
Message-ID: <20180214015008.9513-7-dongwon.kim@intel.com> (raw)
In-Reply-To: <20180214015008.9513-1-dongwon.kim@intel.com>

All of hyper_DMABUF operations now (hyper_dmabuf_ops.c) send a message
to the exporting VM for synchronization between two VMs. For this, every
mapping done by importer will make exporter perform shadow mapping of
original DMA-BUF. Then all consecutive DMA-BUF operations (attach, detach,
map/unmap and so on) will be mimicked on this shadowed DMA-BUF for tracking
and synchronization purpose (e.g. +-reference count to check the status).

Signed-off-by: Dongwon Kim <dongwon.kim@intel.com>
Signed-off-by: Mateusz Polrola <mateuszx.potrola@intel.com>
---
 drivers/dma-buf/hyper_dmabuf/Makefile              |   1 +
 drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_msg.c    |  53 +++-
 drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_msg.h    |   2 +
 drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_ops.c    | 157 +++++++++-
 .../hyper_dmabuf/hyper_dmabuf_remote_sync.c        | 324 +++++++++++++++++++++
 .../hyper_dmabuf/hyper_dmabuf_remote_sync.h        |  32 ++
 6 files changed, 565 insertions(+), 4 deletions(-)
 create mode 100644 drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_remote_sync.c
 create mode 100644 drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_remote_sync.h

diff --git a/drivers/dma-buf/hyper_dmabuf/Makefile b/drivers/dma-buf/hyper_dmabuf/Makefile
index b9ab4eeca6f2..702696f29215 100644
--- a/drivers/dma-buf/hyper_dmabuf/Makefile
+++ b/drivers/dma-buf/hyper_dmabuf/Makefile
@@ -9,6 +9,7 @@ ifneq ($(KERNELRELEASE),)
 				 hyper_dmabuf_ops.o \
 				 hyper_dmabuf_msg.o \
 				 hyper_dmabuf_id.o \
+				 hyper_dmabuf_remote_sync.o \
 
 ifeq ($(CONFIG_HYPER_DMABUF_XEN), y)
 	$(TARGET_MODULE)-objs += backends/xen/hyper_dmabuf_xen_comm.o \
diff --git a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_msg.c b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_msg.c
index 7176fa8fb139..1592d5cfaa52 100644
--- a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_msg.c
+++ b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_msg.c
@@ -34,6 +34,7 @@
 #include <linux/workqueue.h>
 #include "hyper_dmabuf_drv.h"
 #include "hyper_dmabuf_msg.h"
+#include "hyper_dmabuf_remote_sync.h"
 #include "hyper_dmabuf_list.h"
 
 struct cmd_process {
@@ -92,6 +93,25 @@ void hyper_dmabuf_create_req(struct hyper_dmabuf_req *req,
 			req->op[i] = op[i];
 		break;
 
+	case HYPER_DMABUF_OPS_TO_REMOTE:
+		/* notifying dmabuf map/unmap to importer (probably not needed)
+		 * for dmabuf synchronization
+		 */
+		break;
+
+	case HYPER_DMABUF_OPS_TO_SOURCE:
+		/* notifying dmabuf map/unmap to exporter, map will make
+		 * the driver to do shadow mapping or unmapping for
+		 * synchronization with original exporter (e.g. i915)
+		 *
+		 * command : DMABUF_OPS_TO_SOURCE.
+		 * op0~3 : hyper_dmabuf_id
+		 * op4 : map(=1)/unmap(=2)/attach(=3)/detach(=4)
+		 */
+		for (i = 0; i < 5; i++)
+			req->op[i] = op[i];
+		break;
+
 	default:
 		/* no command found */
 		return;
@@ -201,6 +221,12 @@ static void cmd_process_work(struct work_struct *work)
 
 		break;
 
+	case HYPER_DMABUF_OPS_TO_REMOTE:
+		/* notifying dmabuf map/unmap to importer
+		 * (probably not needed) for dmabuf synchronization
+		 */
+		break;
+
 	default:
 		/* shouldn't get here */
 		break;
@@ -217,6 +243,7 @@ int hyper_dmabuf_msg_parse(int domid, struct hyper_dmabuf_req *req)
 	struct imported_sgt_info *imported;
 	struct exported_sgt_info *exported;
 	hyper_dmabuf_id_t hid;
+	int ret;
 
 	if (!req) {
 		dev_err(hy_drv_priv->dev, "request is NULL\n");
@@ -229,7 +256,7 @@ int hyper_dmabuf_msg_parse(int domid, struct hyper_dmabuf_req *req)
 	hid.rng_key[2] = req->op[3];
 
 	if ((req->cmd < HYPER_DMABUF_EXPORT) ||
-		(req->cmd > HYPER_DMABUF_NOTIFY_UNEXPORT)) {
+		(req->cmd > HYPER_DMABUF_OPS_TO_SOURCE)) {
 		dev_err(hy_drv_priv->dev, "invalid command\n");
 		return -EINVAL;
 	}
@@ -271,6 +298,30 @@ int hyper_dmabuf_msg_parse(int domid, struct hyper_dmabuf_req *req)
 		return req->cmd;
 	}
 
+	/* dma buf remote synchronization */
+	if (req->cmd == HYPER_DMABUF_OPS_TO_SOURCE) {
+		/* notifying dmabuf map/unmap to exporter, map will
+		 * make the driver to do shadow mapping
+		 * or unmapping for synchronization with original
+		 * exporter (e.g. i915)
+		 *
+		 * command : DMABUF_OPS_TO_SOURCE.
+		 * op0~3 : hyper_dmabuf_id
+		 * op1 : enum hyper_dmabuf_ops {....}
+		 */
+		dev_dbg(hy_drv_priv->dev,
+			"%s: HYPER_DMABUF_OPS_TO_SOURCE\n", __func__);
+
+		ret = hyper_dmabuf_remote_sync(hid, req->op[4]);
+
+		if (ret)
+			req->stat = HYPER_DMABUF_REQ_ERROR;
+		else
+			req->stat = HYPER_DMABUF_REQ_PROCESSED;
+
+		return req->cmd;
+	}
+
 	/* synchronous dma_buf_fd export */
 	if (req->cmd == HYPER_DMABUF_EXPORT_FD) {
 		/* find a corresponding SGT for the id */
diff --git a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_msg.h b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_msg.h
index 63a39d068d69..82d2900d3077 100644
--- a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_msg.h
+++ b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_msg.h
@@ -48,6 +48,8 @@ enum hyper_dmabuf_command {
 	HYPER_DMABUF_EXPORT_FD,
 	HYPER_DMABUF_EXPORT_FD_FAILED,
 	HYPER_DMABUF_NOTIFY_UNEXPORT,
+	HYPER_DMABUF_OPS_TO_REMOTE,
+	HYPER_DMABUF_OPS_TO_SOURCE,
 };
 
 enum hyper_dmabuf_ops {
diff --git a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_ops.c b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_ops.c
index b4d3c2caad73..02d42c099ad9 100644
--- a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_ops.c
+++ b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_ops.c
@@ -51,16 +51,71 @@ static int dmabuf_refcount(struct dma_buf *dma_buf)
 	return -EINVAL;
 }
 
+static int sync_request(hyper_dmabuf_id_t hid, int dmabuf_ops)
+{
+	struct hyper_dmabuf_req *req;
+	struct hyper_dmabuf_bknd_ops *bknd_ops = hy_drv_priv->bknd_ops;
+	int op[5];
+	int i;
+	int ret;
+
+	op[0] = hid.id;
+
+	for (i = 0; i < 3; i++)
+		op[i+1] = hid.rng_key[i];
+
+	op[4] = dmabuf_ops;
+
+	req = kcalloc(1, sizeof(*req), GFP_KERNEL);
+
+	if (!req)
+		return -ENOMEM;
+
+	hyper_dmabuf_create_req(req, HYPER_DMABUF_OPS_TO_SOURCE, &op[0]);
+
+	/* send request and wait for a response */
+	ret = bknd_ops->send_req(HYPER_DMABUF_DOM_ID(hid), req,
+				 WAIT_AFTER_SYNC_REQ);
+
+	if (ret < 0) {
+		dev_dbg(hy_drv_priv->dev,
+			"dmabuf sync request failed:%d\n", req->op[4]);
+	}
+
+	kfree(req);
+
+	return ret;
+}
+
 static int hyper_dmabuf_ops_attach(struct dma_buf *dmabuf,
 				   struct device *dev,
 				   struct dma_buf_attachment *attach)
 {
-	return 0;
+	struct imported_sgt_info *imported;
+	int ret;
+
+	if (!attach->dmabuf->priv)
+		return -EINVAL;
+
+	imported = (struct imported_sgt_info *)attach->dmabuf->priv;
+
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_ATTACH);
+
+	return ret;
 }
 
 static void hyper_dmabuf_ops_detach(struct dma_buf *dmabuf,
 				    struct dma_buf_attachment *attach)
 {
+	struct imported_sgt_info *imported;
+	int ret;
+
+	if (!attach->dmabuf->priv)
+		return;
+
+	imported = (struct imported_sgt_info *)attach->dmabuf->priv;
+
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_DETACH);
 }
 
 static struct sg_table *hyper_dmabuf_ops_map(
@@ -70,6 +125,7 @@ static struct sg_table *hyper_dmabuf_ops_map(
 	struct sg_table *st;
 	struct imported_sgt_info *imported;
 	struct pages_info *pg_info;
+	int ret;
 
 	if (!attachment->dmabuf->priv)
 		return NULL;
@@ -91,6 +147,8 @@ static struct sg_table *hyper_dmabuf_ops_map(
 	if (!dma_map_sg(attachment->dev, st->sgl, st->nents, dir))
 		goto err_free_sg;
 
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_MAP);
+
 	kfree(pg_info->pgs);
 	kfree(pg_info);
 
@@ -113,6 +171,7 @@ static void hyper_dmabuf_ops_unmap(struct dma_buf_attachment *attachment,
 				   enum dma_data_direction dir)
 {
 	struct imported_sgt_info *imported;
+	int ret;
 
 	if (!attachment->dmabuf->priv)
 		return;
@@ -123,12 +182,15 @@ static void hyper_dmabuf_ops_unmap(struct dma_buf_attachment *attachment,
 
 	sg_free_table(sg);
 	kfree(sg);
+
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_UNMAP);
 }
 
 static void hyper_dmabuf_ops_release(struct dma_buf *dma_buf)
 {
 	struct imported_sgt_info *imported;
 	struct hyper_dmabuf_bknd_ops *bknd_ops = hy_drv_priv->bknd_ops;
+	int ret;
 	int finish;
 
 	if (!dma_buf->priv)
@@ -155,6 +217,8 @@ static void hyper_dmabuf_ops_release(struct dma_buf *dma_buf)
 	finish = imported && !imported->valid &&
 		 !imported->importers;
 
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_RELEASE);
+
 	/*
 	 * Check if buffer is still valid and if not remove it
 	 * from imported list. That has to be done after sending
@@ -169,18 +233,48 @@ static void hyper_dmabuf_ops_release(struct dma_buf *dma_buf)
 static int hyper_dmabuf_ops_begin_cpu_access(struct dma_buf *dmabuf,
 					     enum dma_data_direction dir)
 {
-	return 0;
+	struct imported_sgt_info *imported;
+	int ret;
+
+	if (!dmabuf->priv)
+		return -EINVAL;
+
+	imported = (struct imported_sgt_info *)dmabuf->priv;
+
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_BEGIN_CPU_ACCESS);
+
+	return ret;
 }
 
 static int hyper_dmabuf_ops_end_cpu_access(struct dma_buf *dmabuf,
 					   enum dma_data_direction dir)
 {
+	struct imported_sgt_info *imported;
+	int ret;
+
+	if (!dmabuf->priv)
+		return -EINVAL;
+
+	imported = (struct imported_sgt_info *)dmabuf->priv;
+
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_END_CPU_ACCESS);
+
 	return 0;
 }
 
 static void *hyper_dmabuf_ops_kmap_atomic(struct dma_buf *dmabuf,
 					  unsigned long pgnum)
 {
+	struct imported_sgt_info *imported;
+	int ret;
+
+	if (!dmabuf->priv)
+		return NULL;
+
+	imported = (struct imported_sgt_info *)dmabuf->priv;
+
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_KMAP_ATOMIC);
+
 	/* TODO: NULL for now. Need to return the addr of mapped region */
 	return NULL;
 }
@@ -188,10 +282,29 @@ static void *hyper_dmabuf_ops_kmap_atomic(struct dma_buf *dmabuf,
 static void hyper_dmabuf_ops_kunmap_atomic(struct dma_buf *dmabuf,
 					   unsigned long pgnum, void *vaddr)
 {
+	struct imported_sgt_info *imported;
+	int ret;
+
+	if (!dmabuf->priv)
+		return;
+
+	imported = (struct imported_sgt_info *)dmabuf->priv;
+
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_KUNMAP_ATOMIC);
 }
 
 static void *hyper_dmabuf_ops_kmap(struct dma_buf *dmabuf, unsigned long pgnum)
 {
+	struct imported_sgt_info *imported;
+	int ret;
+
+	if (!dmabuf->priv)
+		return NULL;
+
+	imported = (struct imported_sgt_info *)dmabuf->priv;
+
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_KMAP);
+
 	/* for now NULL.. need to return the address of mapped region */
 	return NULL;
 }
@@ -199,21 +312,59 @@ static void *hyper_dmabuf_ops_kmap(struct dma_buf *dmabuf, unsigned long pgnum)
 static void hyper_dmabuf_ops_kunmap(struct dma_buf *dmabuf, unsigned long pgnum,
 				    void *vaddr)
 {
+	struct imported_sgt_info *imported;
+	int ret;
+
+	if (!dmabuf->priv)
+		return;
+
+	imported = (struct imported_sgt_info *)dmabuf->priv;
+
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_KUNMAP);
 }
 
 static int hyper_dmabuf_ops_mmap(struct dma_buf *dmabuf,
 				 struct vm_area_struct *vma)
 {
-	return 0;
+	struct imported_sgt_info *imported;
+	int ret;
+
+	if (!dmabuf->priv)
+		return -EINVAL;
+
+	imported = (struct imported_sgt_info *)dmabuf->priv;
+
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_MMAP);
+
+	return ret;
 }
 
 static void *hyper_dmabuf_ops_vmap(struct dma_buf *dmabuf)
 {
+	struct imported_sgt_info *imported;
+	int ret;
+
+	if (!dmabuf->priv)
+		return NULL;
+
+	imported = (struct imported_sgt_info *)dmabuf->priv;
+
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_VMAP);
+
 	return NULL;
 }
 
 static void hyper_dmabuf_ops_vunmap(struct dma_buf *dmabuf, void *vaddr)
 {
+	struct imported_sgt_info *imported;
+	int ret;
+
+	if (!dmabuf->priv)
+		return;
+
+	imported = (struct imported_sgt_info *)dmabuf->priv;
+
+	ret = sync_request(imported->hid, HYPER_DMABUF_OPS_VUNMAP);
 }
 
 static const struct dma_buf_ops hyper_dmabuf_ops = {
diff --git a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_remote_sync.c b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_remote_sync.c
new file mode 100644
index 000000000000..55c2c1828859
--- /dev/null
+++ b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_remote_sync.c
@@ -0,0 +1,324 @@
+/*
+ * 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.
+ *
+ * SPDX-License-Identifier: (MIT OR GPL-2.0)
+ *
+ * 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/dma-buf.h>
+#include "hyper_dmabuf_drv.h"
+#include "hyper_dmabuf_struct.h"
+#include "hyper_dmabuf_list.h"
+#include "hyper_dmabuf_msg.h"
+#include "hyper_dmabuf_id.h"
+#include "hyper_dmabuf_sgl_proc.h"
+
+/* Whenever importer does dma operations from remote domain,
+ * a notification is sent to the exporter so that exporter
+ * issues equivalent dma operation on the original dma buf
+ * for indirect synchronization via shadow operations.
+ *
+ * All ptrs and references (e.g struct sg_table*,
+ * struct dma_buf_attachment) created via these operations on
+ * exporter's side are kept in stack (implemented as circular
+ * linked-lists) separately so that those can be re-referenced
+ * later when unmapping operations are invoked to free those.
+ *
+ * The very first element on the bottom of each stack holds
+ * is what is created when initial exporting is issued so it
+ * should not be modified or released by this fuction.
+ */
+int hyper_dmabuf_remote_sync(hyper_dmabuf_id_t hid, int ops)
+{
+	struct exported_sgt_info *exported;
+	struct sgt_list *sgtl;
+	struct attachment_list *attachl;
+	struct kmap_vaddr_list *va_kmapl;
+	struct vmap_vaddr_list *va_vmapl;
+	int ret;
+
+	/* find a coresponding SGT for the id */
+	exported = hyper_dmabuf_find_exported(hid);
+
+	if (!exported) {
+		dev_err(hy_drv_priv->dev,
+			"dmabuf remote sync::can't find exported list\n");
+		return -ENOENT;
+	}
+
+	switch (ops) {
+	case HYPER_DMABUF_OPS_ATTACH:
+		attachl = kcalloc(1, sizeof(*attachl), GFP_KERNEL);
+
+		if (!attachl)
+			return -ENOMEM;
+
+		attachl->attach = dma_buf_attach(exported->dma_buf,
+						 hy_drv_priv->dev);
+
+		if (!attachl->attach) {
+			kfree(attachl);
+			dev_err(hy_drv_priv->dev,
+				"remote sync::HYPER_DMABUF_OPS_ATTACH\n");
+			return -ENOMEM;
+		}
+
+		list_add(&attachl->list, &exported->active_attached->list);
+		break;
+
+	case HYPER_DMABUF_OPS_DETACH:
+		if (list_empty(&exported->active_attached->list)) {
+			dev_err(hy_drv_priv->dev,
+				"remote sync::HYPER_DMABUF_OPS_DETACH\n");
+			dev_err(hy_drv_priv->dev,
+				"no more dmabuf attachment left to be detached\n");
+			return -EFAULT;
+		}
+
+		attachl = list_first_entry(&exported->active_attached->list,
+					   struct attachment_list, list);
+
+		dma_buf_detach(exported->dma_buf, attachl->attach);
+		list_del(&attachl->list);
+		kfree(attachl);
+		break;
+
+	case HYPER_DMABUF_OPS_MAP:
+		if (list_empty(&exported->active_attached->list)) {
+			dev_err(hy_drv_priv->dev,
+				"remote sync::HYPER_DMABUF_OPS_MAP\n");
+			dev_err(hy_drv_priv->dev,
+				"no more dmabuf attachment left to be mapped\n");
+			return -EFAULT;
+		}
+
+		attachl = list_first_entry(&exported->active_attached->list,
+					   struct attachment_list, list);
+
+		sgtl = kcalloc(1, sizeof(*sgtl), GFP_KERNEL);
+
+		if (!sgtl)
+			return -ENOMEM;
+
+		sgtl->sgt = dma_buf_map_attachment(attachl->attach,
+						   DMA_BIDIRECTIONAL);
+		if (!sgtl->sgt) {
+			kfree(sgtl);
+			dev_err(hy_drv_priv->dev,
+				"remote sync::HYPER_DMABUF_OPS_MAP\n");
+			return -ENOMEM;
+		}
+		list_add(&sgtl->list, &exported->active_sgts->list);
+		break;
+
+	case HYPER_DMABUF_OPS_UNMAP:
+		if (list_empty(&exported->active_sgts->list) ||
+		    list_empty(&exported->active_attached->list)) {
+			dev_err(hy_drv_priv->dev,
+				"remote sync::HYPER_DMABUF_OPS_UNMAP\n");
+			dev_err(hy_drv_priv->dev,
+				"no SGT or attach left to be unmapped\n");
+			return -EFAULT;
+		}
+
+		attachl = list_first_entry(&exported->active_attached->list,
+					   struct attachment_list, list);
+		sgtl = list_first_entry(&exported->active_sgts->list,
+					struct sgt_list, list);
+
+		dma_buf_unmap_attachment(attachl->attach, sgtl->sgt,
+					 DMA_BIDIRECTIONAL);
+		list_del(&sgtl->list);
+		kfree(sgtl);
+		break;
+
+	case HYPER_DMABUF_OPS_RELEASE:
+		dev_dbg(hy_drv_priv->dev,
+			"id:%d key:%d %d %d} released, ref left: %d\n",
+			 exported->hid.id, exported->hid.rng_key[0],
+			 exported->hid.rng_key[1], exported->hid.rng_key[2],
+			 exported->active - 1);
+
+		exported->active--;
+
+		/* If there are still importers just break, if no then
+		 * continue with final cleanup
+		 */
+		if (exported->active)
+			break;
+
+		/* Importer just released buffer fd, check if there is
+		 * any other importer still using it.
+		 * If not and buffer was unexported, clean up shared
+		 * data and remove that buffer.
+		 */
+		dev_dbg(hy_drv_priv->dev,
+			"Buffer {id:%d key:%d %d %d} final released\n",
+			exported->hid.id, exported->hid.rng_key[0],
+			exported->hid.rng_key[1], exported->hid.rng_key[2]);
+
+		if (!exported->valid && !exported->active &&
+		    !exported->unexport_sched) {
+			hyper_dmabuf_cleanup_sgt_info(exported, false);
+			hyper_dmabuf_remove_exported(hid);
+			kfree(exported);
+			/* store hyper_dmabuf_id in the list for reuse */
+			hyper_dmabuf_store_hid(hid);
+		}
+
+		break;
+
+	case HYPER_DMABUF_OPS_BEGIN_CPU_ACCESS:
+		ret = dma_buf_begin_cpu_access(exported->dma_buf,
+					       DMA_BIDIRECTIONAL);
+		if (ret) {
+			dev_err(hy_drv_priv->dev,
+				"HYPER_DMABUF_OPS_BEGIN_CPU_ACCESS\n");
+			return ret;
+		}
+		break;
+
+	case HYPER_DMABUF_OPS_END_CPU_ACCESS:
+		ret = dma_buf_end_cpu_access(exported->dma_buf,
+					     DMA_BIDIRECTIONAL);
+		if (ret) {
+			dev_err(hy_drv_priv->dev,
+				"HYPER_DMABUF_OPS_END_CPU_ACCESS\n");
+			return ret;
+		}
+		break;
+
+	case HYPER_DMABUF_OPS_KMAP_ATOMIC:
+	case HYPER_DMABUF_OPS_KMAP:
+		va_kmapl = kcalloc(1, sizeof(*va_kmapl), GFP_KERNEL);
+		if (!va_kmapl)
+			return -ENOMEM;
+
+		/* dummy kmapping of 1 page */
+		if (ops == HYPER_DMABUF_OPS_KMAP_ATOMIC)
+			va_kmapl->vaddr = dma_buf_kmap_atomic(
+						exported->dma_buf, 1);
+		else
+			va_kmapl->vaddr = dma_buf_kmap(
+						exported->dma_buf, 1);
+
+		if (!va_kmapl->vaddr) {
+			kfree(va_kmapl);
+			dev_err(hy_drv_priv->dev,
+				"HYPER_DMABUF_OPS_KMAP(_ATOMIC)\n");
+			return -ENOMEM;
+		}
+		list_add(&va_kmapl->list, &exported->va_kmapped->list);
+		break;
+
+	case HYPER_DMABUF_OPS_KUNMAP_ATOMIC:
+	case HYPER_DMABUF_OPS_KUNMAP:
+		if (list_empty(&exported->va_kmapped->list)) {
+			dev_err(hy_drv_priv->dev,
+				"HYPER_DMABUF_OPS_KUNMAP(_ATOMIC)\n");
+			dev_err(hy_drv_priv->dev,
+				"no more dmabuf VA to be freed\n");
+			return -EFAULT;
+		}
+
+		va_kmapl = list_first_entry(&exported->va_kmapped->list,
+					    struct kmap_vaddr_list, list);
+		if (!va_kmapl->vaddr) {
+			dev_err(hy_drv_priv->dev,
+				"HYPER_DMABUF_OPS_KUNMAP(_ATOMIC)\n");
+			return PTR_ERR(va_kmapl->vaddr);
+		}
+
+		/* unmapping 1 page */
+		if (ops == HYPER_DMABUF_OPS_KUNMAP_ATOMIC)
+			dma_buf_kunmap_atomic(exported->dma_buf,
+					      1, va_kmapl->vaddr);
+		else
+			dma_buf_kunmap(exported->dma_buf,
+				       1, va_kmapl->vaddr);
+
+		list_del(&va_kmapl->list);
+		kfree(va_kmapl);
+		break;
+
+	case HYPER_DMABUF_OPS_MMAP:
+		/* currently not supported: looking for a way to create
+		 * a dummy vma
+		 */
+		dev_warn(hy_drv_priv->dev,
+			 "remote sync::sychronized mmap is not supported\n");
+		break;
+
+	case HYPER_DMABUF_OPS_VMAP:
+		va_vmapl = kcalloc(1, sizeof(*va_vmapl), GFP_KERNEL);
+
+		if (!va_vmapl)
+			return -ENOMEM;
+
+		/* dummy vmapping */
+		va_vmapl->vaddr = dma_buf_vmap(exported->dma_buf);
+
+		if (!va_vmapl->vaddr) {
+			kfree(va_vmapl);
+			dev_err(hy_drv_priv->dev,
+				"remote sync::HYPER_DMABUF_OPS_VMAP\n");
+			return -ENOMEM;
+		}
+		list_add(&va_vmapl->list, &exported->va_vmapped->list);
+		break;
+
+	case HYPER_DMABUF_OPS_VUNMAP:
+		if (list_empty(&exported->va_vmapped->list)) {
+			dev_err(hy_drv_priv->dev,
+				"remote sync::HYPER_DMABUF_OPS_VUNMAP\n");
+			dev_err(hy_drv_priv->dev,
+				"no more dmabuf VA to be freed\n");
+			return -EFAULT;
+		}
+		va_vmapl = list_first_entry(&exported->va_vmapped->list,
+					struct vmap_vaddr_list, list);
+		if (!va_vmapl || va_vmapl->vaddr == NULL) {
+			dev_err(hy_drv_priv->dev,
+				"remote sync::HYPER_DMABUF_OPS_VUNMAP\n");
+			return -EFAULT;
+		}
+
+		dma_buf_vunmap(exported->dma_buf, va_vmapl->vaddr);
+
+		list_del(&va_vmapl->list);
+		kfree(va_vmapl);
+		break;
+
+	default:
+		/* program should not get here */
+		break;
+	}
+
+	return 0;
+}
diff --git a/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_remote_sync.h b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_remote_sync.h
new file mode 100644
index 000000000000..a659c83c8f27
--- /dev/null
+++ b/drivers/dma-buf/hyper_dmabuf/hyper_dmabuf_remote_sync.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ *
+ * SPDX-License-Identifier: (MIT OR GPL-2.0)
+ *
+ */
+
+#ifndef __HYPER_DMABUF_REMOTE_SYNC_H__
+#define __HYPER_DMABUF_REMOTE_SYNC_H__
+
+int hyper_dmabuf_remote_sync(hyper_dmabuf_id_t hid, int ops);
+
+#endif // __HYPER_DMABUF_REMOTE_SYNC_H__
-- 
2.16.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

  parent reply	other threads:[~2018-02-14  1:52 UTC|newest]

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

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=20180214015008.9513-7-dongwon.kim@intel.com \
    --to=dongwon.kim@intel.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=linaro-mm-sig@lists.linaro.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mateuszx.potrola@intel.com \
    --cc=sumit.semwal@linaro.org \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

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

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