clear-pkgs-linux-iot-lts2018/0065-media-intel-ipu4-VIRT-...

2608 lines
75 KiB
Diff

From eec8bd7dfe9d4f9102021e7fdc73abafa853520c Mon Sep 17 00:00:00 2001
From: Ong Hock Yu <ong.hock.yu@intel.com>
Date: Tue, 2 Oct 2018 08:50:23 +0800
Subject: [PATCH 065/743] media: intel-ipu4: [VIRT] Add multi streaming support
on guest OS
Change-Id: I416c99a032e9f2a9611c43ca917b28e3ff70fe18
Signed-off-by: Ong Hock Yu <ong.hock.yu@intel.com>
---
.../media/pci/intel/ici/ici-isys-frame-buf.c | 12 +-
drivers/media/pci/intel/ici/ici-isys-stream.h | 1 -
drivers/media/pci/intel/virtio/Makefile.virt | 2 +
.../intel/virtio/intel-ipu4-para-virt-drv.c | 199 +++++-----------
.../intel/virtio/intel-ipu4-para-virt-drv.h | 4 -
.../virtio/intel-ipu4-virtio-be-bridge.c | 179 +++++++--------
.../virtio/intel-ipu4-virtio-be-bridge.h | 5 +-
.../virtio/intel-ipu4-virtio-be-pipeline.c | 203 +++++++++++++---
.../virtio/intel-ipu4-virtio-be-pipeline.h | 20 +-
.../intel-ipu4-virtio-be-request-queue.c | 57 +++++
.../intel-ipu4-virtio-be-request-queue.h | 27 +++
.../virtio/intel-ipu4-virtio-be-stream.c | 216 +++++++++++++-----
.../virtio/intel-ipu4-virtio-be-stream.h | 20 +-
.../pci/intel/virtio/intel-ipu4-virtio-be.c | 152 ++++++------
.../pci/intel/virtio/intel-ipu4-virtio-be.h | 12 +-
.../intel/virtio/intel-ipu4-virtio-common.c | 77 +++++++
.../intel/virtio/intel-ipu4-virtio-common.h | 45 +++-
.../virtio/intel-ipu4-virtio-fe-pipeline.c | 7 +-
.../intel-ipu4-virtio-fe-request-queue.c | 72 ++++++
.../intel-ipu4-virtio-fe-request-queue.h | 14 ++
.../pci/intel/virtio/intel-ipu4-virtio-fe.c | 65 ++++--
21 files changed, 914 insertions(+), 475 deletions(-)
create mode 100644 drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-request-queue.c
create mode 100644 drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-request-queue.h
create mode 100644 drivers/media/pci/intel/virtio/intel-ipu4-virtio-fe-request-queue.c
create mode 100644 drivers/media/pci/intel/virtio/intel-ipu4-virtio-fe-request-queue.h
diff --git a/drivers/media/pci/intel/ici/ici-isys-frame-buf.c b/drivers/media/pci/intel/ici/ici-isys-frame-buf.c
index 8e62c273b35a..bd99ba14a8af 100644
--- a/drivers/media/pci/intel/ici/ici-isys-frame-buf.c
+++ b/drivers/media/pci/intel/ici/ici-isys-frame-buf.c
@@ -495,6 +495,9 @@ int ici_isys_get_buf_virt(struct ici_isys_stream *as,
return 0;
}
+ pr_debug("%s: creating new buf object\n", __func__);
+ pr_debug("%s: mem.userptr %lu", __func__,
+ frame_buf->frame_info.frame_planes[0].mem.userptr);
buf = frame_buf;
@@ -585,6 +588,8 @@ static void frame_buf_done(
list_add_tail(&buf->node, &buf_list->putbuf_list);
spin_unlock_irqrestore(&buf_list->lock, flags);
wake_up_interruptible(&buf_list->wait);
+ pr_debug("%s: Frame data arrived! %lu", __func__,
+ buf->frame_info.frame_planes[0].mem.userptr);
}
void ici_isys_frame_buf_ready(struct ici_isys_pipeline
@@ -639,8 +644,6 @@ void ici_isys_frame_buf_ready(struct ici_isys_pipeline
} else {
buf->frame_info.field = ICI_FIELD_NONE;
frame_buf_done(buf_list, buf);
- if (as->frame_done_notify_queue)
- as->frame_done_notify_queue();
}
dev_dbg(&isys->adev->dev, "buffer: found buffer %p\n", buf);
@@ -720,6 +723,9 @@ int ici_isys_frame_buf_add_next(
buf->state = ICI_BUF_ACTIVE;
mutex_unlock(&buf_list->mutex);
+ pr_debug("%s: add buf to FW! %lu", __func__,
+ buf->frame_info.frame_planes[0].mem.userptr);
+
css_buf->send_irq_sof = 1;
css_buf->output_pins[buf_list->fw_output].addr =
(uint32_t)buf->kframe_info.planes[0].dma_addr;
@@ -797,8 +803,6 @@ void ici_isys_frame_buf_capture_done(
buf->frame_info.field = ip->cur_field;
list_del(&buf->node);
frame_buf_done(buf_list, buf);
- if (as->frame_done_notify_queue)
- as->frame_done_notify_queue();
}
}
}
diff --git a/drivers/media/pci/intel/ici/ici-isys-stream.h b/drivers/media/pci/intel/ici/ici-isys-stream.h
index 77d89ed2ea79..457b123a65db 100644
--- a/drivers/media/pci/intel/ici/ici-isys-stream.h
+++ b/drivers/media/pci/intel/ici/ici-isys-stream.h
@@ -50,7 +50,6 @@ struct ici_isys_stream {
void (*prepare_firmware_stream_cfg)(
struct ici_isys_stream *as,
struct ia_css_isys_stream_cfg_data *cfg);
- int (*frame_done_notify_queue)(void);
};
#define to_intel_ipu4_isys_ici_stream(__buf_list) \
diff --git a/drivers/media/pci/intel/virtio/Makefile.virt b/drivers/media/pci/intel/virtio/Makefile.virt
index c3c30c4bf921..75f481b3b71d 100644
--- a/drivers/media/pci/intel/virtio/Makefile.virt
+++ b/drivers/media/pci/intel/virtio/Makefile.virt
@@ -8,11 +8,13 @@ $(TARGET_MODULE)-objs += ../virtio/intel-ipu4-virtio-common.o
ifdef CONFIG_VIDEO_INTEL_IPU_VIRTIO_BE
+ $(TARGET_MODULE)-objs += ../virtio/intel-ipu4-virtio-be-request-queue.o
$(TARGET_MODULE)-objs += ../virtio/intel-ipu4-virtio-be-pipeline.o
$(TARGET_MODULE)-objs += ../virtio/intel-ipu4-virtio-be-bridge.o
$(TARGET_MODULE)-objs += ../virtio/intel-ipu4-virtio-be.o
$(TARGET_MODULE)-objs += ../virtio/intel-ipu4-virtio-be-stream.o
else
+ $(TARGET_MODULE)-objs += ../virtio/intel-ipu4-virtio-fe-request-queue.o
$(TARGET_MODULE)-objs += ../virtio/intel-ipu4-virtio-fe-pipeline.o
$(TARGET_MODULE)-objs += ../virtio/intel-ipu4-virtio-fe-payload.o
$(TARGET_MODULE)-objs += ../virtio/intel-ipu4-virtio-fe.o
diff --git a/drivers/media/pci/intel/virtio/intel-ipu4-para-virt-drv.c b/drivers/media/pci/intel/virtio/intel-ipu4-para-virt-drv.c
index 3f6d541c87fe..23275846e198 100644
--- a/drivers/media/pci/intel/virtio/intel-ipu4-para-virt-drv.c
+++ b/drivers/media/pci/intel/virtio/intel-ipu4-para-virt-drv.c
@@ -18,6 +18,7 @@
#include "intel-ipu4-para-virt-drv.h"
#include "intel-ipu4-virtio-fe-pipeline.h"
#include "intel-ipu4-virtio-fe-payload.h"
+#include "intel-ipu4-virtio-fe-request-queue.h"
#include "./ici/ici-isys-stream.h"
#include "./ici/ici-isys-pipeline-device.h"
@@ -33,8 +34,6 @@ static int stream_dev_init;
static struct ipu4_virtio_ctx *g_fe_priv;
-struct mutex fop_mutex;
-
#ifdef CONFIG_COMPAT
struct timeval32 {
__u32 tv_sec;
@@ -219,63 +218,6 @@ static struct ici_frame_buf_wrapper *frame_buf_lookup(struct ici_isys_frame_buf_
}
return NULL;
}
-static void put_userpages(struct ici_kframe_plane *kframe_plane)
-{
- struct sg_table *sgt = kframe_plane->sgt;
- struct scatterlist *sgl;
- unsigned int i;
- struct mm_struct *mm = current->active_mm;
-
- if (!mm) {
- pr_err("Failed to get active mm_struct ptr from current process.\n");
- return;
- }
-
- down_read(&mm->mmap_sem);
- for_each_sg(sgt->sgl, sgl, sgt->orig_nents, i) {
- struct page *page = sg_page(sgl);
-
- unsigned int npages = PAGE_ALIGN(sgl->offset + sgl->length) >> PAGE_SHIFT;
- unsigned int page_no;
-
- for (page_no = 0; page_no < npages; ++page_no, ++page) {
- set_page_dirty_lock(page);
- put_page(page);
- }
- }
-
- kfree(sgt);
- kframe_plane->sgt = NULL;
-
- up_read(&mm->mmap_sem);
-}
-
-static void put_dma(struct ici_kframe_plane *kframe_plane)
-{
- struct sg_table *sgt = kframe_plane->sgt;
-
- if (WARN_ON(!kframe_plane->db_attach)) {
- pr_err("trying to unpin a not attached buffer\n");
- return;
- }
-
- if (WARN_ON(!sgt)) {
- pr_err("dmabuf buffer is already unpinned\n");
- return;
- }
-
- if (kframe_plane->kaddr) {
- dma_buf_vunmap(kframe_plane->db_attach->dmabuf,
- kframe_plane->kaddr);
- kframe_plane->kaddr = NULL;
- }
- dma_buf_unmap_attachment(kframe_plane->db_attach, sgt,
- DMA_BIDIRECTIONAL);
-
- kframe_plane->dma_addr = 0;
- kframe_plane->sgt = NULL;
-
-}
static int map_dma(struct device *dev, struct ici_frame_plane *frame_plane,
struct ici_kframe_plane *kframe_plane)
@@ -332,26 +274,6 @@ static int map_dma(struct device *dev, struct ici_frame_plane *frame_plane,
return ret;
}
-static void unmap_buf(struct ici_frame_buf_wrapper *buf)
-{
- int i;
-
- for (i = 0; i < buf->frame_info.num_planes; i++) {
- struct ici_kframe_plane *kframe_plane =
- &buf->kframe_info.planes[i];
- switch (kframe_plane->mem_type) {
- case ICI_MEM_USERPTR:
- put_userpages(kframe_plane);
- break;
- case ICI_MEM_DMABUF:
- put_dma(kframe_plane);
- break;
- default:
- pr_debug("not supported memory type: %d\n", kframe_plane->mem_type);
- break;
- }
- }
-}
struct ici_frame_buf_wrapper *get_buf(struct virtual_stream *vstream, struct ici_frame_info *frame_info)
{
int res;
@@ -450,7 +372,7 @@ static int virt_isys_set_format(struct file *file, void *fh,
pr_debug("Calling Set Format\n");
- req = kcalloc(1, sizeof(*req), GFP_KERNEL);
+ req = ipu4_virtio_fe_req_queue_get();
if (!req)
return -ENOMEM;
op[0] = vstream->virt_dev_id;
@@ -463,10 +385,10 @@ static int virt_isys_set_format(struct file *file, void *fh,
rval = fe_ctx->bknd_ops->send_req(fe_ctx->domid, req, true, IPU_VIRTIO_QUEUE_0);
if (rval) {
dev_err(&strm_dev->dev, "Failed to open virtual device\n");
- kfree(req);
+ ipu4_virtio_fe_req_queue_put(req);
return rval;
}
- kfree(req);
+ ipu4_virtio_fe_req_queue_put(req);
return rval;
}
@@ -480,7 +402,8 @@ static int virt_isys_stream_on(struct file *file, void *fh)
int rval = 0;
int op[10];
pr_debug("Calling Stream ON\n");
- req = kcalloc(1, sizeof(*req), GFP_KERNEL);
+
+ req = ipu4_virtio_fe_req_queue_get();
if (!req)
return -ENOMEM;
op[0] = vstream->virt_dev_id;
@@ -491,14 +414,10 @@ static int virt_isys_stream_on(struct file *file, void *fh)
rval = fe_ctx->bknd_ops->send_req(fe_ctx->domid, req, true, IPU_VIRTIO_QUEUE_0);
if (rval) {
dev_err(&strm_dev->dev, "Failed to open virtual device\n");
- kfree(req);
+ ipu4_virtio_fe_req_queue_put(req);
return rval;
}
- kfree(req);
-
- req = kcalloc(1, sizeof(*req), GFP_KERNEL);
- if (!req && !fe_ctx)
- return -ENOMEM;
+ ipu4_virtio_fe_req_queue_put(req);
return rval;
}
@@ -513,7 +432,7 @@ static int virt_isys_stream_off(struct file *file, void *fh)
int op[10];
pr_debug("Calling Stream OFF\n");
- req = kcalloc(1, sizeof(*req), GFP_KERNEL);
+ req = ipu4_virtio_fe_req_queue_get();
if (!req)
return -ENOMEM;
op[0] = vstream->virt_dev_id;
@@ -524,10 +443,10 @@ static int virt_isys_stream_off(struct file *file, void *fh)
rval = fe_ctx->bknd_ops->send_req(fe_ctx->domid, req, true, IPU_VIRTIO_QUEUE_0);
if (rval) {
dev_err(&strm_dev->dev, "Failed to open virtual device\n");
- kfree(req);
+ ipu4_virtio_fe_req_queue_put(req);
return rval;
}
- kfree(req);
+ ipu4_virtio_fe_req_queue_put(req);
buf_stream_cancel(vstream);
@@ -545,7 +464,7 @@ static int virt_isys_getbuf(struct file *file, void *fh,
int rval = 0;
int op[3];
- pr_debug("Calling Get Buffer\n");
+ pr_debug("%s stream %d", __func__, vstream->virt_dev_id);
buf = get_buf(vstream, user_frame_info);
if (!buf) {
@@ -553,7 +472,7 @@ static int virt_isys_getbuf(struct file *file, void *fh,
return -ENOMEM;
}
- req = kcalloc(1, sizeof(*req), GFP_KERNEL);
+ req = ipu4_virtio_fe_req_queue_get();
if (!req)
return -ENOMEM;
@@ -567,10 +486,12 @@ static int virt_isys_getbuf(struct file *file, void *fh,
rval = fe_ctx->bknd_ops->send_req(fe_ctx->domid, req, true, IPU_VIRTIO_QUEUE_0);
if (rval) {
dev_err(&strm_dev->dev, "Failed to Get Buffer\n");
- kfree(req);
+ ipu4_virtio_fe_req_queue_put(req);
return rval;
}
- kfree(req);
+ ipu4_virtio_fe_req_queue_put(req);
+
+ pr_debug("%s exit stream %d", __func__, vstream->virt_dev_id);
return rval;
}
@@ -585,9 +506,9 @@ static int virt_isys_putbuf(struct file *file, void *fh,
int rval = 0;
int op[2];
- pr_debug("Calling Put Buffer\n");
+ pr_debug("%s stream %d", __func__, vstream->virt_dev_id);
- req = kcalloc(1, sizeof(*req), GFP_KERNEL);
+ req = ipu4_virtio_fe_req_queue_get();
if (!req)
return -ENOMEM;
@@ -600,14 +521,12 @@ static int virt_isys_putbuf(struct file *file, void *fh,
rval = fe_ctx->bknd_ops->send_req(fe_ctx->domid, req, true, IPU_VIRTIO_QUEUE_0);
if (rval) {
dev_err(&strm_dev->dev, "Failed to Get Buffer\n");
- kfree(req);
+ ipu4_virtio_fe_req_queue_put(req);
return rval;
}
- kfree(req);
+ ipu4_virtio_fe_req_queue_put(req);
- req = kcalloc(1, sizeof(*req), GFP_KERNEL);
- if (!req && !fe_ctx)
- return -ENOMEM;
+ pr_debug("%s exit stream %d", __func__, vstream->virt_dev_id);
return rval;
}
@@ -624,7 +543,7 @@ static unsigned int stream_fop_poll(struct file *file, struct ici_stream_device
dev_dbg(&strm_dev->dev, "stream_fop_poll %d\n", vstream->virt_dev_id);
get_device(&dev->dev);
- req = kcalloc(1, sizeof(*req), GFP_KERNEL);
+ req = ipu4_virtio_fe_req_queue_get();
if (!req)
return -ENOMEM;
@@ -633,22 +552,16 @@ static unsigned int stream_fop_poll(struct file *file, struct ici_stream_device
intel_ipu4_virtio_create_req(req, IPU4_CMD_POLL, &op[0]);
- mutex_lock(&fop_mutex);
-
- rval = fe_ctx->bknd_ops->send_req(fe_ctx->domid, req, true, IPU_VIRTIO_QUEUE_1);
+ rval = fe_ctx->bknd_ops->send_req(fe_ctx->domid, req, true,
+ IPU_VIRTIO_QUEUE_0);
if (rval) {
- mutex_unlock(&fop_mutex);
dev_err(&strm_dev->dev, "Failed to open virtual device\n");
- kfree(req);
+ ipu4_virtio_fe_req_queue_put(req);
return rval;
}
+ ipu4_virtio_fe_req_queue_put(req);
- mutex_unlock(&fop_mutex);
-
- rval = req->func_ret;
- kfree(req);
-
- return rval;
+ return req->func_ret;
}
static int virt_stream_fop_open(struct inode *inode, struct file *file)
@@ -667,7 +580,7 @@ static int virt_stream_fop_open(struct inode *inode, struct file *file)
if (!fe_ctx)
return -EINVAL;
- req = kcalloc(1, sizeof(*req), GFP_KERNEL);
+ req = ipu4_virtio_fe_req_queue_get();
if (!req) {
dev_err(&strm_dev->dev, "Virtio Req buffer failed\n");
return -ENOMEM;
@@ -678,18 +591,14 @@ static int virt_stream_fop_open(struct inode *inode, struct file *file)
intel_ipu4_virtio_create_req(req, IPU4_CMD_DEVICE_OPEN, &op[0]);
- mutex_lock(&fop_mutex);
-
- rval = fe_ctx->bknd_ops->send_req(fe_ctx->domid, req, true, IPU_VIRTIO_QUEUE_1);
+ rval = fe_ctx->bknd_ops->send_req(fe_ctx->domid, req, true,
+ IPU_VIRTIO_QUEUE_0);
if (rval) {
- mutex_unlock(&fop_mutex);
dev_err(&strm_dev->dev, "Failed to open virtual device\n");
- kfree(req);
+ ipu4_virtio_fe_req_queue_put(req);
return rval;
}
- kfree(req);
-
- mutex_unlock(&fop_mutex);
+ ipu4_virtio_fe_req_queue_put(req);
return rval;
}
@@ -705,7 +614,7 @@ static int virt_stream_fop_release(struct inode *inode, struct file *file)
pr_debug("%s %d", __func__, vstream->virt_dev_id);
put_device(&strm_dev->dev);
- req = kcalloc(1, sizeof(*req), GFP_KERNEL);
+ req = ipu4_virtio_fe_req_queue_get();
if (!req)
return -ENOMEM;
@@ -714,18 +623,14 @@ static int virt_stream_fop_release(struct inode *inode, struct file *file)
intel_ipu4_virtio_create_req(req, IPU4_CMD_DEVICE_CLOSE, &op[0]);
- mutex_lock(&fop_mutex);
-
- rval = fe_ctx->bknd_ops->send_req(fe_ctx->domid, req, true, IPU_VIRTIO_QUEUE_1);
+ rval = fe_ctx->bknd_ops->send_req(fe_ctx->domid, req, true,
+ IPU_VIRTIO_QUEUE_0);
if (rval) {
- mutex_unlock(&fop_mutex);
dev_err(&strm_dev->dev, "Failed to close virtual device\n");
- kfree(req);
+ ipu4_virtio_fe_req_queue_put(req);
return rval;
}
- kfree(req);
-
- mutex_unlock(&fop_mutex);
+ ipu4_virtio_fe_req_queue_put(req);
return rval;
}
@@ -740,10 +645,7 @@ static unsigned int virt_stream_fop_poll(struct file *file,
res = stream_fop_poll(file, as);
- //res = POLLIN;
-
dev_dbg(&as->dev, "virt_stream_fop_poll res %u\n", res);
-
return res;
}
@@ -1014,7 +916,7 @@ static int virt_pipeline_fop_open(struct inode *inode, struct file *file)
file->private_data = dev;
- req = kcalloc(1, sizeof(*req), GFP_KERNEL);
+ req = ipu4_virtio_fe_req_queue_get();
if (!req)
return -ENOMEM;
@@ -1023,14 +925,14 @@ static int virt_pipeline_fop_open(struct inode *inode, struct file *file)
intel_ipu4_virtio_create_req(req, IPU4_CMD_PIPELINE_OPEN, &op[0]);
- rval = g_fe_priv->bknd_ops->send_req(g_fe_priv->domid, req, true, IPU_VIRTIO_QUEUE_1);
+ rval = g_fe_priv->bknd_ops->send_req(g_fe_priv->domid, req, true,
+ IPU_VIRTIO_QUEUE_0);
if (rval) {
pr_err("Failed to open virtual device\n");
- kfree(req);
+ ipu4_virtio_fe_req_queue_put(req);
return rval;
}
- kfree(req);
-
+ ipu4_virtio_fe_req_queue_put(req);
return rval;
}
@@ -1045,7 +947,7 @@ static int virt_pipeline_fop_release(struct inode *inode, struct file *file)
put_device(&pipe_dev->dev);
- req = kcalloc(1, sizeof(*req), GFP_KERNEL);
+ req = ipu4_virtio_fe_req_queue_get();
if (!req)
return -ENOMEM;
@@ -1054,13 +956,13 @@ static int virt_pipeline_fop_release(struct inode *inode, struct file *file)
intel_ipu4_virtio_create_req(req, IPU4_CMD_PIPELINE_CLOSE, &op[0]);
- rval = g_fe_priv->bknd_ops->send_req(g_fe_priv->domid, req, true, IPU_VIRTIO_QUEUE_1);
+ rval = g_fe_priv->bknd_ops->send_req(g_fe_priv->domid, req, true, IPU_VIRTIO_QUEUE_0);
if (rval) {
pr_err("Failed to close virtual device\n");
- kfree(req);
+ ipu4_virtio_fe_req_queue_put(req);
return rval;
}
- kfree(req);
+ ipu4_virtio_fe_req_queue_put(req);
return rval;
}
@@ -1271,7 +1173,6 @@ static int __init virt_ici_init(void)
if (!vstream)
return -ENOMEM;
mutex_init(&vstream->mutex);
- mutex_init(&fop_mutex);
vstream->strm_dev.mutex = &vstream->mutex;
rval = virt_frame_buf_init(&vstream->buf_list);
@@ -1288,6 +1189,10 @@ static int __init virt_ici_init(void)
goto init_fail;
}
+ rval = ipu4_virtio_fe_req_queue_init();
+ if (rval)
+ goto init_fail;
+
rval = virt_ici_pipeline_init();
if (rval)
goto init_fail;
@@ -1297,7 +1202,6 @@ static int __init virt_ici_init(void)
init_fail:
mutex_destroy(&vstream->mutex);
- mutex_destroy(&fop_mutex);
kfree(vstream);
return rval;
}
@@ -1318,6 +1222,7 @@ static void __exit virt_ici_exit(void)
{
virt_ici_stream_exit();
virt_ici_pipeline_exit();
+ ipu4_virtio_fe_req_queue_free();
}
module_init(virt_ici_init);
diff --git a/drivers/media/pci/intel/virtio/intel-ipu4-para-virt-drv.h b/drivers/media/pci/intel/virtio/intel-ipu4-para-virt-drv.h
index f44954b03be2..d6d9210d937a 100644
--- a/drivers/media/pci/intel/virtio/intel-ipu4-para-virt-drv.h
+++ b/drivers/media/pci/intel/virtio/intel-ipu4-para-virt-drv.h
@@ -18,10 +18,6 @@
#include "./ici/ici-isys-frame-buf.h"
#include "intel-ipu4-virtio-common.h"
-#define MAX_STREAM_DEVICES 64
-#define MAX_PIPELINE_DEVICES 1
-#define MAX_ISYS_VIRT_STREAM 34
-
struct virtual_stream {
struct mutex mutex;
struct ici_stream_device strm_dev;
diff --git a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-bridge.c b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-bridge.c
index b88fe6d75bc2..3b5eae651026 100644
--- a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-bridge.c
+++ b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-bridge.c
@@ -10,15 +10,18 @@
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/syscalls.h>
+#include <linux/kthread.h>
#include "intel-ipu4-virtio-be-bridge.h"
#include "./ici/ici-isys-frame-buf.h"
#include "intel-ipu4-virtio-be-pipeline.h"
#include "intel-ipu4-virtio-be-stream.h"
-int intel_ipu4_virtio_msg_parse(int domid, struct ipu4_virtio_req *req)
+int intel_ipu4_virtio_msg_parse(struct ipu4_virtio_req_info *req_info)
{
int ret = 0;
+ struct ipu4_virtio_req *req = req_info->request;
+
if (!req) {
pr_err("IPU mediator: request is NULL\n");
return -EINVAL;
@@ -28,6 +31,10 @@ int intel_ipu4_virtio_msg_parse(int domid, struct ipu4_virtio_req *req)
pr_err("IPU mediator: invalid command\n");
return -EINVAL;
}
+
+ if (!req_info)
+ return -1;
+
switch (req->cmd) {
case IPU4_CMD_POLL:
/*
@@ -35,9 +42,11 @@ int intel_ipu4_virtio_msg_parse(int domid, struct ipu4_virtio_req *req)
* op0 - virtual device node number
* op1 - Actual device fd. By default set to 0
*/
- pr_debug("%s: process_poll pre", __func__);
- req->stat = process_poll(domid, req);
- pr_debug("%s: process_poll post", __func__);
+ pr_debug("%s: process_poll %d",
+ __func__, req->op[0]);
+ kthread_run(process_poll_thread, req_info,
+ "process_poll");
+ req->stat = IPU4_REQ_PENDING;
break;
case IPU4_CMD_DEVICE_OPEN:
/*
@@ -46,11 +55,9 @@ int intel_ipu4_virtio_msg_parse(int domid, struct ipu4_virtio_req *req)
* op1 - Actual device fd. By default set to 0
*/
pr_debug("DEVICE_OPEN: virtual_dev_id:%d actual_fd:%d\n", req->op[0], req->op[1]);
- ret = process_device_open(domid, req);
- if (ret)
- req->stat = IPU4_REQ_ERROR;
- else
- req->stat = IPU4_REQ_PROCESSED;
+ kthread_run(process_device_open_thread, req_info,
+ "process_device_open");
+ req->stat = IPU4_REQ_PENDING;
break;
case IPU4_CMD_DEVICE_CLOSE:
/*
@@ -59,11 +66,9 @@ int intel_ipu4_virtio_msg_parse(int domid, struct ipu4_virtio_req *req)
* op1 - Actual device fd. By default set to 0
*/
pr_debug("DEVICE_CLOSE: virtual_dev_id:%d actual_fd:%d\n", req->op[0], req->op[1]);
- ret = process_device_close(domid, req);
- if (ret)
- req->stat = IPU4_REQ_ERROR;
- else
- req->stat = IPU4_REQ_PROCESSED;
+ kthread_run(process_device_close_thread, req_info,
+ "process_device_close");
+ req->stat = IPU4_REQ_PENDING;
break;
case IPU4_CMD_STREAM_ON:
/* Start Stream
@@ -71,11 +76,9 @@ int intel_ipu4_virtio_msg_parse(int domid, struct ipu4_virtio_req *req)
* op1 - Actual device fd. By default set to 0
*/
pr_debug("STREAM ON: virtual_dev_id:%d actual_fd:%d\n", req->op[0], req->op[1]);
- ret = process_stream_on(domid, req);
- if (ret)
- req->stat = IPU4_REQ_ERROR;
- else
- req->stat = IPU4_REQ_PROCESSED;
+ kthread_run(process_stream_on_thread, req_info,
+ "process_stream_on");
+ req->stat = IPU4_REQ_PENDING;
break;
case IPU4_CMD_STREAM_OFF:
/* Stop Stream
@@ -83,11 +86,9 @@ int intel_ipu4_virtio_msg_parse(int domid, struct ipu4_virtio_req *req)
* op1 - Actual device fd. By default set to 0
*/
pr_debug("STREAM OFF: virtual_dev_id:%d actual_fd:%d\n", req->op[0], req->op[1]);
- ret = process_stream_off(domid, req);
- if (ret)
- req->stat = IPU4_REQ_ERROR;
- else
- req->stat = IPU4_REQ_PROCESSED;
+ kthread_run(process_stream_off_thread, req_info,
+ "process_stream_off");
+ req->stat = IPU4_REQ_PENDING;
break;
case IPU4_CMD_GET_BUF:
/* Set Format of a given video node
@@ -99,11 +100,11 @@ int intel_ipu4_virtio_msg_parse(int domid, struct ipu4_virtio_req *req)
* op5 - Length of Buffer
*/
- ret = process_get_buf(domid, req);
- if (ret)
- req->stat = IPU4_REQ_ERROR;
- else
- req->stat = IPU4_REQ_PROCESSED;
+ pr_debug("%s process_get_buf %d",
+ __func__, req->op[0]);
+ kthread_run(process_get_buf_thread, req_info,
+ "process_get_buf");
+ req->stat = IPU4_REQ_PENDING;
break;
case IPU4_CMD_PUT_BUF:
/* Set Format of a given video node
@@ -111,88 +112,88 @@ int intel_ipu4_virtio_msg_parse(int domid, struct ipu4_virtio_req *req)
* op1 - Actual device fd. By default set to 0
* op2 - Memory Type 1: USER_PTR 2: DMA_PTR
*/
- ret = process_put_buf(domid, req);
- if (ret)
- req->stat = IPU4_REQ_ERROR;
- else
- req->stat = IPU4_REQ_PROCESSED;
+ pr_debug("%s process_put_buf %d",
+ __func__, req->op[0]);
+ kthread_run(process_put_buf_thread, req_info,
+ "process_put_buf");
+ req->stat = IPU4_REQ_PENDING;
break;
case IPU4_CMD_SET_FORMAT:
- ret = process_set_format(domid, req);
- if (ret)
- req->stat = IPU4_REQ_ERROR;
- else
- req->stat = IPU4_REQ_PROCESSED;
+ pr_debug("%s process_set_format %d",
+ __func__, req->op[0]);
+ kthread_run(process_set_format_thread, req_info,
+ "process_set_format");
+ req->stat = IPU4_REQ_PENDING;
break;
case IPU4_CMD_PIPELINE_OPEN:
- ret = process_pipeline_open(domid, req);
- if (ret)
- req->stat = IPU4_REQ_ERROR;
- else
- req->stat = IPU4_REQ_PROCESSED;
+ pr_debug("%s process_pipeline_open %d",
+ __func__, req->op[0]);
+ kthread_run(process_pipeline_open_thread, req_info,
+ "process_pipeline_open");
+ req->stat = IPU4_REQ_PENDING;
break;
case IPU4_CMD_PIPELINE_CLOSE:
- ret = process_pipeline_close(domid, req);
- if (ret)
- req->stat = IPU4_REQ_ERROR;
- else
- req->stat = IPU4_REQ_PROCESSED;
+ pr_debug("%s process_pipeline_close %d",
+ __func__, req->op[0]);
+ kthread_run(process_pipeline_close_thread, req_info,
+ "process_pipeline_close");
+ req->stat = IPU4_REQ_PENDING;
break;
case IPU4_CMD_ENUM_NODES:
- ret = process_enum_nodes(domid, req);
- if (ret)
- req->stat = IPU4_REQ_ERROR;
- else
- req->stat = IPU4_REQ_PROCESSED;
+ pr_debug("%s process_enum_nodes %d",
+ __func__, req->op[0]);
+ kthread_run(process_enum_nodes_thread, req_info,
+ "process_enum_nodes");
+ req->stat = IPU4_REQ_PENDING;
break;
case IPU4_CMD_ENUM_LINKS:
- ret = process_enum_links(domid, req);
- if (ret)
- req->stat = IPU4_REQ_ERROR;
- else
- req->stat = IPU4_REQ_PROCESSED;
+ pr_debug("%s process_enum_links %d",
+ __func__, req->op[0]);
+ kthread_run(process_enum_links_thread, req_info,
+ "process_enum_links");
+ req->stat = IPU4_REQ_PENDING;
break;
case IPU4_CMD_SETUP_PIPE:
- ret = process_setup_pipe(domid, req);
- if (ret)
- req->stat = IPU4_REQ_ERROR;
- else
- req->stat = IPU4_REQ_PROCESSED;
+ pr_debug("%s process_setup_pipe %d",
+ __func__, req->op[0]);
+ kthread_run(process_setup_pipe_thread, req_info,
+ "process_setup_pipe");
+ req->stat = IPU4_REQ_PENDING;
break;
case IPU4_CMD_SET_FRAMEFMT:
- ret = process_set_framefmt(domid, req);
- if (ret)
- req->stat = IPU4_REQ_ERROR;
- else
- req->stat = IPU4_REQ_PROCESSED;
+ pr_debug("%s process_set_framefmt %d",
+ __func__, req->op[0]);
+ kthread_run(process_set_framefmt_thread, req_info,
+ "process_set_framefmt");
+ req->stat = IPU4_REQ_PENDING;
break;
case IPU4_CMD_GET_FRAMEFMT:
- ret = process_get_framefmt(domid, req);
- if (ret)
- req->stat = IPU4_REQ_ERROR;
- else
- req->stat = IPU4_REQ_PROCESSED;
+ pr_debug("%s process_get_framefmt %d",
+ __func__, req->op[0]);
+ kthread_run(process_get_framefmt_thread, req_info,
+ "process_get_framefmt");
+ req->stat = IPU4_REQ_PENDING;
break;
case IPU4_CMD_GET_SUPPORTED_FRAMEFMT:
- ret = process_get_supported_framefmt(domid, req);
- if (ret)
- req->stat = IPU4_REQ_ERROR;
- else
- req->stat = IPU4_REQ_PROCESSED;
+ pr_debug("%s process_get_supported_framefmt %d",
+ __func__, req->op[0]);
+ kthread_run(process_get_supported_framefmt_thread,
+ req_info, "process_get_supported_framefmt");
+ req->stat = IPU4_REQ_PENDING;
break;
case IPU4_CMD_SET_SELECTION:
- ret = process_pad_set_sel(domid, req);
- if (ret)
- req->stat = IPU4_REQ_ERROR;
- else
- req->stat = IPU4_REQ_PROCESSED;
+ pr_debug("%s process_pad_set_sel %d",
+ __func__, req->op[0]);
+ kthread_run(process_pad_set_sel_thread, req_info,
+ "process_pad_set_sel");
+ req->stat = IPU4_REQ_PENDING;
break;
case IPU4_CMD_GET_SELECTION:
- ret = process_pad_get_sel(domid, req);
- if (ret)
- req->stat = IPU4_REQ_ERROR;
- else
- req->stat = IPU4_REQ_PROCESSED;
+ pr_debug("%s process_pad_get_sel %d",
+ __func__, req->op[0]);
+ kthread_run(process_pad_get_sel_thread, req_info,
+ "process_pad_get_sel");
+ req->stat = IPU4_REQ_PENDING;
break;
default:
return -EINVAL;
diff --git a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-bridge.h b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-bridge.h
index 25238f29bc33..18085882de85 100644
--- a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-bridge.h
+++ b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-bridge.h
@@ -12,14 +12,13 @@
#include <linux/vhm/acrn_vhm_mm.h>
#include "intel-ipu4-virtio-common.h"
+#include "intel-ipu4-virtio-be-request-queue.h"
-int intel_ipu4_virtio_msg_parse(int domid, struct ipu4_virtio_req *req);
+int intel_ipu4_virtio_msg_parse(struct ipu4_virtio_req_info *req_info);
void intel_ipu4_virtio_create_req(struct ipu4_virtio_req *req,
enum intel_ipu4_virtio_command cmd, int *op);
-int intel_ipu4_virtio_msg_parse(int domid, struct ipu4_virtio_req *req);
-
#endif
diff --git a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-pipeline.c b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-pipeline.c
index 3adf5b4c9640..086421151f28 100644
--- a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-pipeline.c
+++ b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-pipeline.c
@@ -14,176 +14,321 @@
#include "intel-ipu4-virtio-be-pipeline.h"
#include "./ici/ici-isys-pipeline.h"
#include "./ici/ici-isys-pipeline-device.h"
+#include "intel-ipu4-virtio-be.h"
+#include "intel-ipu4-virtio-be-request-queue.h"
static struct file *pipeline;
static int guestID = -1;
-int process_pipeline_open(int domid, struct ipu4_virtio_req *req)
+int process_pipeline_open(struct ipu4_virtio_req_info *req_info)
{
+ int domid = req_info->domid;
if (guestID != -1 && guestID != domid) {
pr_err("%s: pipeline device already opened by other guest! %d %d", __func__, guestID, domid);
- return -1;
+ return IPU4_REQ_ERROR;
}
pr_info("process_device_open: /dev/intel_pipeline");
pipeline = filp_open("/dev/intel_pipeline", O_RDWR | O_NONBLOCK, 0);
guestID = domid;
- return 0;
+ return IPU4_REQ_PROCESSED;
}
-int process_pipeline_close(int domid, struct ipu4_virtio_req *req)
+int process_pipeline_close(struct ipu4_virtio_req_info *req_info)
{
+ struct ipu4_virtio_req *req = req_info->request;
+
pr_info("%s: %d", __func__, req->op[0]);
filp_close(pipeline, 0);
guestID = -1;
- return 0;
+ return IPU4_REQ_PROCESSED;
}
-int process_enum_nodes(int domid, struct ipu4_virtio_req *req)
+int process_enum_nodes(struct ipu4_virtio_req_info *req_info)
{
int err = 0;
struct ici_isys_pipeline_device *dev = pipeline->private_data;
struct ici_node_desc *host_virt;
+ struct ipu4_virtio_req *req = req_info->request;
+ int domid = req_info->domid;
pr_debug("%s\n", __func__);
host_virt = (struct ici_node_desc *)map_guest_phys(domid, req->payload, PAGE_SIZE);
if (host_virt == NULL) {
pr_err("process_enum_nodes: NULL host_virt");
- return 0;
+ return IPU4_REQ_ERROR;
}
err = dev->pipeline_ioctl_ops->pipeline_enum_nodes(pipeline, dev, host_virt);
- return err;
+ if (err)
+ return IPU4_REQ_ERROR;
+ else
+ return IPU4_REQ_PROCESSED;
}
-int process_enum_links(int domid, struct ipu4_virtio_req *req)
+int process_enum_links(struct ipu4_virtio_req_info *req_info)
{
int err = 0;
struct ici_isys_pipeline_device *dev = pipeline->private_data;
struct ici_links_query *host_virt;
+ struct ipu4_virtio_req *req = req_info->request;
+ int domid = req_info->domid;
pr_debug("%s\n", __func__);
host_virt = (struct ici_links_query *)map_guest_phys(domid, req->payload, PAGE_SIZE);
if (host_virt == NULL) {
pr_err("%s: NULL host_virt\n", __func__);
- return 0;
+ return IPU4_REQ_ERROR;
}
err = dev->pipeline_ioctl_ops->pipeline_enum_links(pipeline, dev, host_virt);
- return err;
+ if (err)
+ return IPU4_REQ_ERROR;
+ else
+ return IPU4_REQ_PROCESSED;
}
-int process_get_supported_framefmt(int domid, struct ipu4_virtio_req *req)
+int process_get_supported_framefmt(struct ipu4_virtio_req_info *req_info)
{
int err = 0;
struct ici_isys_pipeline_device *dev = pipeline->private_data;
struct ici_pad_supported_format_desc *host_virt;
+ struct ipu4_virtio_req *req = req_info->request;
+ int domid = req_info->domid;
pr_debug("%s\n", __func__);
host_virt = (struct ici_pad_supported_format_desc *)map_guest_phys(domid, req->payload, PAGE_SIZE);
if (host_virt == NULL) {
pr_err("%s: NULL host_virt\n", __func__);
- return 0;
+ return IPU4_REQ_ERROR;
}
err = dev->pipeline_ioctl_ops->pad_get_supported_format(pipeline, dev, host_virt);
- return err;
+ if (err)
+ return IPU4_REQ_ERROR;
+ else
+ return IPU4_REQ_PROCESSED;
}
-int process_set_framefmt(int domid, struct ipu4_virtio_req *req)
+int process_set_framefmt(struct ipu4_virtio_req_info *req_info)
{
int err = 0;
struct ici_isys_pipeline_device *dev = pipeline->private_data;
struct ici_pad_framefmt *host_virt;
+ struct ipu4_virtio_req *req = req_info->request;
+ int domid = req_info->domid;
pr_debug("%s\n", __func__);
host_virt = (struct ici_pad_framefmt *)map_guest_phys(domid, req->payload, PAGE_SIZE);
if (host_virt == NULL) {
pr_err("%s: NULL host_virt\n", __func__);
- return 0;
+ return IPU4_REQ_ERROR;
}
err = dev->pipeline_ioctl_ops->pad_set_ffmt(pipeline, dev, host_virt);
- return err;
+ if (err)
+ return IPU4_REQ_ERROR;
+ else
+ return IPU4_REQ_PROCESSED;
}
-int process_get_framefmt(int domid, struct ipu4_virtio_req *req)
+int process_get_framefmt(struct ipu4_virtio_req_info *req_info)
{
int err = 0;
struct ici_isys_pipeline_device *dev = pipeline->private_data;
struct ici_pad_framefmt *host_virt;
+ struct ipu4_virtio_req *req = req_info->request;
+ int domid = req_info->domid;
pr_debug("%s\n", __func__);
host_virt = (struct ici_pad_framefmt *)map_guest_phys(domid, req->payload, PAGE_SIZE);
if (host_virt == NULL) {
pr_err("%s: NULL host_virt\n", __func__);
- return 0;
+ return IPU4_REQ_ERROR;
}
err = dev->pipeline_ioctl_ops->pad_get_ffmt(pipeline, dev, host_virt);
- return err;
+ if (err)
+ return IPU4_REQ_ERROR;
+ else
+ return IPU4_REQ_PROCESSED;
}
-int process_setup_pipe(int domid, struct ipu4_virtio_req *req)
+int process_setup_pipe(struct ipu4_virtio_req_info *req_info)
{
int err = 0;
struct ici_isys_pipeline_device *dev = pipeline->private_data;
struct ici_link_desc *host_virt;
+ struct ipu4_virtio_req *req = req_info->request;
+ int domid = req_info->domid;
pr_debug("%s\n", __func__);
host_virt = (struct ici_link_desc *)map_guest_phys(domid, req->payload, PAGE_SIZE);
if (host_virt == NULL) {
pr_err("%s: NULL host_virt\n", __func__);
- return 0;
+ return IPU4_REQ_ERROR;
}
err = dev->pipeline_ioctl_ops->pipeline_setup_pipe(pipeline, dev, host_virt);
- return err;
+ if (err)
+ return IPU4_REQ_ERROR;
+ else
+ return IPU4_REQ_PROCESSED;
}
-int process_pad_set_sel(int domid, struct ipu4_virtio_req *req)
+int process_pad_set_sel(struct ipu4_virtio_req_info *req_info)
{
int err = 0;
struct ici_isys_pipeline_device *dev = pipeline->private_data;
struct ici_pad_selection *host_virt;
+ struct ipu4_virtio_req *req = req_info->request;
+ int domid = req_info->domid;
pr_debug("%s\n", __func__);
host_virt = (struct ici_pad_selection *)map_guest_phys(domid, req->payload, PAGE_SIZE);
if (host_virt == NULL) {
pr_err("%s: NULL host_virt\n", __func__);
- return 0;
+ return IPU4_REQ_ERROR;
}
err = dev->pipeline_ioctl_ops->pad_set_sel(pipeline, dev, host_virt);
- return err;
+ if (err)
+ return IPU4_REQ_ERROR;
+ else
+ return IPU4_REQ_PROCESSED;
}
-int process_pad_get_sel(int domid, struct ipu4_virtio_req *req)
+int process_pad_get_sel(struct ipu4_virtio_req_info *req_info)
{
int err = 0;
struct ici_isys_pipeline_device *dev = pipeline->private_data;
struct ici_pad_selection *host_virt;
+ struct ipu4_virtio_req *req = req_info->request;
+ int domid = req_info->domid;
pr_debug("%s\n", __func__);
host_virt = (struct ici_pad_selection *)map_guest_phys(domid, req->payload, PAGE_SIZE);
if (host_virt == NULL) {
pr_err("%s: NULL host_virt\n", __func__);
- return 0;
+ return IPU4_REQ_ERROR;
}
err = dev->pipeline_ioctl_ops->pad_get_sel(pipeline, dev, host_virt);
- return err;
+ if (err)
+ return IPU4_REQ_ERROR;
+ else
+ return IPU4_REQ_PROCESSED;
+}
+
+int process_pipeline_open_thread(void *data)
+{
+ int status;
+
+ status = process_pipeline_open(data);
+ notify_fe(status, data);
+ do_exit(0);
+ return 0;
+}
+
+int process_pipeline_close_thread(void *data)
+{
+ int status;
+
+ status = process_pipeline_close(data);
+ notify_fe(status, data);
+ do_exit(0);
+ return 0;
+}
+
+int process_enum_nodes_thread(void *data)
+{
+ int status;
+
+ status = process_enum_nodes(data);
+ notify_fe(status, data);
+ do_exit(0);
+ return 0;
+}
+
+int process_enum_links_thread(void *data)
+{
+ int status;
+
+ status = process_enum_links(data);
+ notify_fe(status, data);
+ do_exit(0);
+ return 0;
+}
+
+int process_get_supported_framefmt_thread(void *data)
+{
+ int status;
+
+ status = process_get_supported_framefmt(data);
+ notify_fe(status, data);
+ do_exit(0);
+ return 0;
+}
+
+int process_set_framefmt_thread(void *data)
+{
+ int status;
+
+ status = process_set_framefmt(data);
+ notify_fe(status, data);
+ do_exit(0);
+ return 0;
+}
+
+int process_get_framefmt_thread(void *data)
+{
+ int status;
+
+ status = process_get_framefmt(data);
+ notify_fe(status, data);
+ do_exit(0);
+ return 0;
+}
+
+int process_pad_set_sel_thread(void *data)
+{
+ int status;
+
+ status = process_pad_set_sel(data);
+ notify_fe(status, data);
+ do_exit(0);
+ return 0;
+}
+
+int process_pad_get_sel_thread(void *data)
+{
+ int status;
+
+ status = process_pad_get_sel(data);
+ notify_fe(status, data);
+ do_exit(0);
+ return 0;
+}
+
+int process_setup_pipe_thread(void *data)
+{
+ int status;
+
+ status = process_setup_pipe(data);
+ notify_fe(status, data);
+ do_exit(0);
+ return 0;
}
/*
diff --git a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-pipeline.h b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-pipeline.h
index df65e88050ea..3da8c243a2bc 100644
--- a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-pipeline.h
+++ b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-pipeline.h
@@ -11,16 +11,16 @@
#include "intel-ipu4-virtio-common.h"
-int process_pipeline_open(int domid, struct ipu4_virtio_req *req);
-int process_pipeline_close(int domid, struct ipu4_virtio_req *req);
-int process_enum_nodes(int domid, struct ipu4_virtio_req *req);
-int process_enum_links(int domid, struct ipu4_virtio_req *req);
-int process_get_supported_framefmt(int domid, struct ipu4_virtio_req *req);
-int process_set_framefmt(int domid, struct ipu4_virtio_req *req);
-int process_get_framefmt(int domid, struct ipu4_virtio_req *req);
-int process_pad_set_sel(int domid, struct ipu4_virtio_req *req);
-int process_pad_get_sel(int domid, struct ipu4_virtio_req *req);
-int process_setup_pipe(int domid, struct ipu4_virtio_req *req);
+int process_pipeline_open_thread(void *data);
+int process_pipeline_close_thread(void *data);
+int process_enum_nodes_thread(void *data);
+int process_enum_links_thread(void *data);
+int process_get_supported_framefmt_thread(void *data);
+int process_set_framefmt_thread(void *data);
+int process_get_framefmt_thread(void *data);
+int process_pad_set_sel_thread(void *data);
+int process_pad_get_sel_thread(void *data);
+int process_setup_pipe_thread(void *data);
#endif
diff --git a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-request-queue.c b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-request-queue.c
new file mode 100644
index 000000000000..cee9b55518c1
--- /dev/null
+++ b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-request-queue.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
+/*
+ * Copyright (C) 2018 Intel Corporation
+ */
+
+#include <linux/virtio.h>
+#include <linux/spinlock.h>
+#include "intel-ipu4-virtio-common.h"
+#include "intel-ipu4-virtio-be-request-queue.h"
+
+struct ipu4_virtio_ring ipu4_virtio_be_req_queue;
+
+int ipu4_virtio_be_req_queue_init(void)
+{
+ int i;
+ struct ipu4_virtio_req_info *req;
+
+ if (ipu4_virtio_ring_init(&ipu4_virtio_be_req_queue, REQ_RING_SIZE))
+ return -1;
+
+ for (i = 0; i < REQ_RING_SIZE; i++) {
+ req = kcalloc(1, sizeof(struct ipu4_virtio_req_info), GFP_KERNEL);
+ if (req == NULL) {
+ pr_err("%s failed to allocate memory for ipu4_virtio_req_info",
+ __func__);
+ return -1;
+ }
+ ipu4_virtio_ring_push(&ipu4_virtio_be_req_queue, req);
+ }
+ return 0;
+}
+
+void ipu4_virtio_be_req_queue_free(void)
+{
+ int i;
+ struct ipu4_virtio_req_info *req_info;
+
+ for (i = 0; i < REQ_RING_SIZE; i++) {
+ req_info = ipu4_virtio_ring_pop(&ipu4_virtio_be_req_queue);
+ if (req_info)
+ kfree(req_info);
+ else
+ break;
+ }
+ ipu4_virtio_ring_free(&ipu4_virtio_be_req_queue);
+}
+
+struct ipu4_virtio_req_info *ipu4_virtio_be_req_queue_get(void)
+{
+ return ipu4_virtio_ring_pop(&ipu4_virtio_be_req_queue);
+}
+
+int ipu4_virtio_be_req_queue_put(
+ struct ipu4_virtio_req_info *req)
+{
+ return ipu4_virtio_ring_push(&ipu4_virtio_be_req_queue, req);
+}
diff --git a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-request-queue.h b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-request-queue.h
new file mode 100644
index 000000000000..febcf73152e2
--- /dev/null
+++ b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-request-queue.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) */
+/*
+ * Copyright (C) 2018 Intel Corporation
+ */
+
+#ifndef IPU4_VIRTIO_FE_REQUEST_QUEUE_H
+#define IPU4_VIRTIO_FE_REQUEST_QUEUE_H
+
+struct ipu4_virtio_vq_info {
+ int vq_idx;
+ int req_len;
+ uint16_t vq_buf_idx;
+};
+
+struct ipu4_virtio_req_info {
+ struct ipu4_virtio_req *request;
+ struct ipu4_virtio_vq_info vq_info;
+ int domid;
+ int client_id;
+};
+
+int ipu4_virtio_be_req_queue_init(void);
+void ipu4_virtio_be_req_queue_free(void);
+struct ipu4_virtio_req_info *ipu4_virtio_be_req_queue_get(void);
+int ipu4_virtio_be_req_queue_put(struct ipu4_virtio_req_info *req);
+
+#endif
diff --git a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-stream.c b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-stream.c
index 9c6bbf6fb5be..c3257ea0dbd1 100644
--- a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-stream.c
+++ b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-stream.c
@@ -8,9 +8,9 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/poll.h>
-
#include <linux/hashtable.h>
#include <linux/pagemap.h>
+
#include <media/ici.h>
#include <linux/vhm/acrn_vhm_mm.h>
#include "./ici/ici-isys-stream-device.h"
@@ -20,6 +20,7 @@
#include "intel-ipu4-virtio-be.h"
#define MAX_SIZE 6 // max 2^6
+#define POLL_WAIT 500 //500ms
#define dev_to_stream(dev) \
container_of(dev, struct ici_isys_stream, strm_dev)
@@ -33,16 +34,13 @@ struct stream_node {
struct hlist_node node;
};
-int frame_done_callback(void)
-{
- notify_fe();
- return 0;
-}
-
-int process_device_open(int domid, struct ipu4_virtio_req *req)
+int process_device_open(struct ipu4_virtio_req_info *req_info)
{
char node_name[25];
struct stream_node *sn = NULL;
+ struct ici_stream_device *strm_dev;
+ struct ipu4_virtio_req *req = req_info->request;
+ int domid = req_info->domid;
if (!hash_initialised) {
hash_init(STREAM_NODE_HASH);
@@ -52,10 +50,10 @@ int process_device_open(int domid, struct ipu4_virtio_req *req)
if (sn != NULL) {
if (sn->client_id != domid) {
pr_err("process_device_open: stream device %d already opened by other guest!", sn->client_id);
- return -EBUSY;
+ return IPU4_REQ_ERROR;
}
pr_info("process_device_open: stream device %d already opened by client %d", req->op[0], domid);
- return 0;
+ return IPU4_REQ_PROCESSED;
}
}
@@ -63,44 +61,54 @@ int process_device_open(int domid, struct ipu4_virtio_req *req)
pr_info("process_device_open: %s", node_name);
sn = kzalloc(sizeof(struct stream_node), GFP_KERNEL);
sn->f = filp_open(node_name, O_RDWR | O_NONBLOCK, 0);
- sn->client_id = domid;
+ strm_dev = sn->f->private_data;
+ if (strm_dev == NULL) {
+ pr_err("Native IPU stream device not found\n");
+ return IPU4_REQ_ERROR;
+ }
+ strm_dev->virt_dev_id = req->op[0];
+
+ sn->client_id = domid;
hash_add(STREAM_NODE_HASH, &sn->node, req->op[0]);
- return 0;
+ return IPU4_REQ_PROCESSED;
}
-int process_device_close(int domid, struct ipu4_virtio_req *req)
+int process_device_close(struct ipu4_virtio_req_info *req_info)
{
struct stream_node *sn = NULL;
+ struct ipu4_virtio_req *req = req_info->request;
+
if (!hash_initialised)
- return 0; //no node has been opened, do nothing
+ return IPU4_REQ_PROCESSED; //no node has been opened, do nothing
pr_info("process_device_close: %d", req->op[0]);
hash_for_each_possible(STREAM_NODE_HASH, sn, node, req->op[0]) {
if (sn != NULL) {
- pr_err("process_device_close: %d closed", req->op[0]);
hash_del(&sn->node);
filp_close(sn->f, 0);
kfree(sn);
}
}
- return 0;
+ return IPU4_REQ_PROCESSED;
}
-int process_set_format(int domid, struct ipu4_virtio_req *req)
+int process_set_format(struct ipu4_virtio_req_info *req_info)
{
struct stream_node *sn = NULL;
struct ici_stream_device *strm_dev;
struct ici_stream_format *host_virt;
int err, found;
+ struct ipu4_virtio_req *req = req_info->request;
+ int domid = req_info->domid;
pr_debug("process_set_format: %d %d", hash_initialised, req->op[0]);
if (!hash_initialised)
- return -1;
+ return IPU4_REQ_ERROR;
found = 0;
hash_for_each_possible(STREAM_NODE_HASH, sn, node, req->op[0]) {
@@ -113,19 +121,19 @@ int process_set_format(int domid, struct ipu4_virtio_req *req)
if (!found) {
pr_debug("%s: stream not found %d\n", __func__, req->op[0]);
- return -1;
+ return IPU4_REQ_ERROR;
}
strm_dev = sn->f->private_data;
if (strm_dev == NULL) {
pr_err("Native IPU stream device not found\n");
- return -1;
+ return IPU4_REQ_ERROR;
}
host_virt = (struct ici_stream_format *)map_guest_phys(domid, req->payload, PAGE_SIZE);
if (host_virt == NULL) {
pr_err("process_set_format: NULL host_virt");
- return -1;
+ return IPU4_REQ_ERROR;
}
err = strm_dev->ipu_ioctl_ops->ici_set_format(sn->f, strm_dev, host_virt);
@@ -133,33 +141,33 @@ int process_set_format(int domid, struct ipu4_virtio_req *req)
if (err)
pr_err("intel_ipu4_pvirt: internal set fmt failed\n");
- return 0;
+ return IPU4_REQ_PROCESSED;
}
-int process_poll(int domid, struct ipu4_virtio_req *req)
+int process_poll(struct ipu4_virtio_req_info *req_info)
{
struct stream_node *sn = NULL;
struct ici_isys_stream *as;
bool found, empty;
unsigned long flags = 0;
+ struct ipu4_virtio_req *req = req_info->request;
+ int time_remain;
pr_debug("%s: %d %d", __func__, hash_initialised, req->op[0]);
if (!hash_initialised)
- return -1;
+ return IPU4_REQ_ERROR;
found = false;
hash_for_each_possible(STREAM_NODE_HASH, sn, node, req->op[0]) {
if (sn != NULL) {
- pr_debug("process_put_buf: node %d %p", req->op[0], sn);
found = true;
break;
}
}
-
if (!found) {
pr_debug("%s: stream not found %d\n", __func__, req->op[0]);
- return -1;
+ return IPU4_REQ_ERROR;
}
as = dev_to_stream(sn->f->private_data);
@@ -168,22 +176,37 @@ int process_poll(int domid, struct ipu4_virtio_req *req)
spin_unlock_irqrestore(&as->buf_list.lock, flags);
if (!empty) {
req->func_ret = 1;
+ pr_debug("%s: done", __func__);
return IPU4_REQ_PROCESSED;
- } else
- return IPU4_REQ_NEEDS_FOLLOW_UP;
+ } else {
+ time_remain = wait_event_interruptible_timeout(
+ as->buf_list.wait,
+ !list_empty(&as->buf_list.putbuf_list),
+ POLL_WAIT);
+ if (time_remain) {
+ req->func_ret = 1;
+ return IPU4_REQ_PROCESSED;
+ } else {
+ pr_err("%s poll timeout! %d", __func__, req->op[0]);
+ req->func_ret = 0;
+ return IPU4_REQ_ERROR;
+ }
+ }
}
-int process_put_buf(int domid, struct ipu4_virtio_req *req)
+int process_put_buf(struct ipu4_virtio_req_info *req_info)
{
struct stream_node *sn = NULL;
struct ici_stream_device *strm_dev;
struct ici_frame_info *host_virt;
int err, found;
+ struct ipu4_virtio_req *req = req_info->request;
+ int domid = req_info->domid;
pr_debug("process_put_buf: %d %d", hash_initialised, req->op[0]);
if (!hash_initialised)
- return -1;
+ return IPU4_REQ_ERROR;
found = 0;
hash_for_each_possible(STREAM_NODE_HASH, sn, node, req->op[0]) {
@@ -196,29 +219,29 @@ int process_put_buf(int domid, struct ipu4_virtio_req *req)
if (!found) {
pr_debug("%s: stream not found %d\n", __func__, req->op[0]);
- return -1;
+ return IPU4_REQ_ERROR;
}
strm_dev = sn->f->private_data;
if (strm_dev == NULL) {
pr_err("Native IPU stream device not found\n");
- return -1;
+ return IPU4_REQ_ERROR;
}
host_virt = (struct ici_frame_info *)map_guest_phys(domid, req->payload, PAGE_SIZE);
if (host_virt == NULL) {
pr_err("process_put_buf: NULL host_virt");
- return -1;
+ return IPU4_REQ_ERROR;
}
err = strm_dev->ipu_ioctl_ops->ici_put_buf(sn->f, strm_dev, host_virt);
if (err)
pr_err("process_put_buf: ici_put_buf failed\n");
- return 0;
+ return IPU4_REQ_PROCESSED;
}
-int process_get_buf(int domid, struct ipu4_virtio_req *req)
+int process_get_buf(struct ipu4_virtio_req_info *req_info)
{
struct stream_node *sn = NULL;
struct ici_frame_buf_wrapper *shared_buf;
@@ -228,11 +251,13 @@ int process_get_buf(int domid, struct ipu4_virtio_req *req)
u64 *page_table = NULL;
struct page **data_pages = NULL;
int err, found;
+ struct ipu4_virtio_req *req = req_info->request;
+ int domid = req_info->domid;
pr_debug("process_get_buf: %d %d", hash_initialised, req->op[0]);
if (!hash_initialised)
- return -1;
+ return IPU4_REQ_ERROR;
found = 0;
hash_for_each_possible(STREAM_NODE_HASH, sn, node, req->op[0]) {
@@ -245,7 +270,7 @@ int process_get_buf(int domid, struct ipu4_virtio_req *req)
if (!found) {
pr_debug("%s: stream not found %d\n", __func__, req->op[0]);
- return -1;
+ return IPU4_REQ_ERROR;
}
pr_debug("GET_BUF: Mapping buffer\n");
@@ -267,7 +292,7 @@ int process_get_buf(int domid, struct ipu4_virtio_req *req)
pr_err("SOS Failed to map page table\n");
req->stat = IPU4_REQ_ERROR;
kfree(data_pages);
- return -1;
+ return IPU4_REQ_ERROR;
}
else {
@@ -290,7 +315,7 @@ int process_get_buf(int domid, struct ipu4_virtio_req *req)
if (strm_dev == NULL) {
pr_err("Native IPU stream device not found\n");
kfree(data_pages);
- return -1;
+ return IPU4_REQ_ERROR;
}
err = strm_dev->ipu_ioctl_ops->ici_get_buf_virt(sn->f, strm_dev, shared_buf, data_pages);
@@ -298,20 +323,21 @@ int process_get_buf(int domid, struct ipu4_virtio_req *req)
pr_err("process_get_buf: ici_get_buf_virt failed\n");
kfree(data_pages);
- return 0;
+ return IPU4_REQ_PROCESSED;
}
-int process_stream_on(int domid, struct ipu4_virtio_req *req)
+int process_stream_on(struct ipu4_virtio_req_info *req_info)
{
struct stream_node *sn = NULL;
struct ici_isys_stream *as;
struct ici_stream_device *strm_dev;
int err, found;
+ struct ipu4_virtio_req *req = req_info->request;
pr_debug("process_stream_on: %d %d", hash_initialised, req->op[0]);
if (!hash_initialised)
- return -1;
+ return IPU4_REQ_ERROR;
found = 0;
hash_for_each_possible(STREAM_NODE_HASH, sn, node, req->op[0]) {
@@ -324,37 +350,34 @@ int process_stream_on(int domid, struct ipu4_virtio_req *req)
if (!found) {
pr_debug("%s: stream not found %d\n", __func__, req->op[0]);
- return -1;
+ return IPU4_REQ_ERROR;
}
strm_dev = sn->f->private_data;
if (strm_dev == NULL) {
pr_err("Native IPU stream device not found\n");
- return -1;
+ return IPU4_REQ_ERROR;
}
- as = dev_to_stream(strm_dev);
- as->frame_done_notify_queue = frame_done_callback;
-
err = strm_dev->ipu_ioctl_ops->ici_stream_on(sn->f, strm_dev);
if (err)
pr_err("process_stream_on: stream on failed\n");
- return 0;
+ return IPU4_REQ_PROCESSED;
}
-int process_stream_off(int domid, struct ipu4_virtio_req *req)
+int process_stream_off(struct ipu4_virtio_req_info *req_info)
{
struct stream_node *sn = NULL;
struct ici_stream_device *strm_dev;
- struct ici_isys_stream *as;
int err, found;
+ struct ipu4_virtio_req *req = req_info->request;
pr_debug("process_stream_off: %d %d", hash_initialised, req->op[0]);
if (!hash_initialised)
- return -1;
+ return IPU4_REQ_ERROR;
found = 0;
hash_for_each_possible(STREAM_NODE_HASH, sn, node, req->op[0]) {
@@ -367,23 +390,100 @@ int process_stream_off(int domid, struct ipu4_virtio_req *req)
if (!found) {
pr_debug("%s: stream not found %d\n", __func__, req->op[0]);
- return -1;
+ return IPU4_REQ_ERROR;
}
strm_dev = sn->f->private_data;
if (strm_dev == NULL) {
pr_err("Native IPU stream device not found\n");
- return -1;
+ return IPU4_REQ_ERROR;
}
err = strm_dev->ipu_ioctl_ops->ici_stream_off(sn->f, strm_dev);
if (err)
- pr_err("process_stream_off: stream off failed\n");
+ pr_err("%s: stream off failed\n",
+ __func__);
+
+ return IPU4_REQ_PROCESSED;
+}
- as = dev_to_stream(strm_dev);
- as->frame_done_notify_queue();
- as->frame_done_notify_queue = NULL;
+int process_set_format_thread(void *data)
+{
+ int status;
+
+ status = process_set_format(data);
+ notify_fe(status, data);
+ do_exit(0);
+ return 0;
+}
+
+int process_device_open_thread(void *data)
+{
+ int status;
+
+ status = process_device_open(data);
+ notify_fe(status, data);
+ do_exit(0);
+ return 0;
+}
+
+int process_device_close_thread(void *data)
+{
+ int status;
+
+ status = process_device_close(data);
+ notify_fe(status, data);
+ do_exit(0);
+ return 0;
+}
+
+int process_poll_thread(void *data)
+{
+ int status;
+
+ status = process_poll(data);
+ notify_fe(status, data);
+ do_exit(0);
+ return 0;
+}
+
+int process_put_buf_thread(void *data)
+{
+ int status;
+
+ status = process_put_buf(data);
+ notify_fe(status, data);
+ do_exit(0);
+ return 0;
+}
+
+int process_stream_on_thread(void *data)
+{
+ int status;
+
+ status = process_stream_on(data);
+ notify_fe(status, data);
+ do_exit(0);
+ return 0;
+}
+
+int process_stream_off_thread(void *data)
+{
+ int status;
+
+ status = process_stream_off(data);
+ notify_fe(status, data);
+ do_exit(0);
+ return 0;
+}
+
+int process_get_buf_thread(void *data)
+{
+ int status;
+ status = process_get_buf(data);
+ notify_fe(status, data);
+ do_exit(0);
return 0;
}
diff --git a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-stream.h b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-stream.h
index 0d85b3561274..04a84a4c365a 100644
--- a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-stream.h
+++ b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be-stream.h
@@ -10,16 +10,16 @@
#include <linux/errno.h>
#include "intel-ipu4-virtio-common.h"
-
-int process_set_format(int domid, struct ipu4_virtio_req *req);
-int process_device_open(int domid, struct ipu4_virtio_req *req);
-int process_device_close(int domid, struct ipu4_virtio_req *req);
-int process_poll(int domid, struct ipu4_virtio_req *req);
-int process_put_buf(int domid, struct ipu4_virtio_req *req);
-int process_stream_on(int domid, struct ipu4_virtio_req *req);
-int process_stream_off(int domid, struct ipu4_virtio_req *req);
-int process_get_buf(int domid, struct ipu4_virtio_req *req);
-
+#include "intel-ipu4-virtio-be-request-queue.h"
+
+int process_set_format_thread(void *data);
+int process_device_open_thread(void *data);
+int process_device_close_thread(void *data);
+int process_poll_thread(void *data);
+int process_put_buf_thread(void *data);
+int process_stream_on_thread(void *data);
+int process_stream_off_thread(void *data);
+int process_get_buf_thread(void *data);
#endif
diff --git a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be.c b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be.c
index aa64d09adb35..4359d7b99c70 100644
--- a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be.c
+++ b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be.c
@@ -17,6 +17,7 @@
#include "intel-ipu4-virtio-common.h"
#include "intel-ipu4-virtio-be-bridge.h"
#include "intel-ipu4-virtio-be.h"
+#include "intel-ipu4-virtio-be-request-queue.h"
/**
* struct ipu4_virtio_be_priv - Backend of virtio-rng based on VBS-K
@@ -31,8 +32,8 @@ struct ipu4_virtio_be_priv {
struct virtio_dev_info dev;
struct virtio_vq_info vqs[IPU_VIRTIO_QUEUE_MAX];
bool busy;
- struct ipu4_virtio_req *pending_tx_req;
- struct mutex lock;
+ struct mutex mlock;
+ spinlock_t slock;
/*
* Each VBS-K module might serve multiple connections
* from multiple guests/device models/VBS-Us, so better
@@ -42,22 +43,12 @@ struct ipu4_virtio_be_priv {
struct hlist_node node;
};
-struct vq_request_data {
- struct virtio_vq_info *vq;
- struct ipu4_virtio_req *req;
- int len;
- uint16_t idx;
-};
-
-struct vq_request_data vq_req;
-
#define RNG_MAX_HASH_BITS 4 /* MAX is 2^4 */
#define HASH_NAME vbs_hash
DECLARE_HASHTABLE(HASH_NAME, RNG_MAX_HASH_BITS);
static int ipu_vbk_hash_initialized;
static int ipu_vbk_connection_cnt;
-
/* function declarations */
static int handle_kick(int client_id, long unsigned int *req_cnt);
static void ipu_vbk_reset(struct ipu4_virtio_be_priv *rng);
@@ -150,19 +141,23 @@ static int ipu_vbk_hash_del_all(void)
return 0;
}
-static void handle_vq_kick(struct ipu4_virtio_be_priv *priv, int vq_idx)
+static void handle_vq_kick(int client_id, int vq_idx)
{
struct iovec iov;
struct ipu4_virtio_be_priv *be;
struct virtio_vq_info *vq;
+ struct ipu4_virtio_req_info *req_info = NULL;
struct ipu4_virtio_req *req = NULL;
int len;
int ret;
uint16_t idx;
- pr_debug("%s: vq_idx %d\n", __func__, vq_idx);
-
- be = priv;
+ be = ipu_vbk_hash_find(client_id);
+ if (be == NULL) {
+ pr_err("%s: client %d not found!\n",
+ __func__, client_id);
+ return -EINVAL;
+ }
if (!be) {
pr_err("rng is NULL! Cannot proceed!\n");
@@ -174,9 +169,9 @@ static void handle_vq_kick(struct ipu4_virtio_be_priv *priv, int vq_idx)
while (virtio_vq_has_descs(vq)) {
virtio_vq_getchain(vq, &idx, &iov, 1, NULL);
+ pr_debug("%s: vq index: %d vq buf index: %d req ptr: %lu\n",
+ __func__, vq_idx, idx, iov.iov_base);
/* device specific operations, for example: */
- pr_debug("iov base %p len %lx\n", iov.iov_base, iov.iov_len);
-
if (iov.iov_len != sizeof(struct ipu4_virtio_req)) {
if (iov.iov_len == sizeof(int)) {
*((int *)iov.iov_base) = 1;
@@ -195,20 +190,32 @@ static void handle_vq_kick(struct ipu4_virtio_be_priv *priv, int vq_idx)
continue;
}
- req = (struct ipu4_virtio_req *)iov.iov_base;
- ret = intel_ipu4_virtio_msg_parse(1, req);
- len = iov.iov_len;
+ req_info = ipu4_virtio_be_req_queue_get();
+ if (req_info) {
+ req = (struct ipu4_virtio_req *)iov.iov_base;
+ req_info->request = req;
+ req_info->vq_info.req_len = iov.iov_len;
+ req_info->vq_info.vq_buf_idx = idx;
+ req_info->vq_info.vq_idx = vq_idx;
+ req_info->domid = 1;
+ req_info->client_id = client_id;
+ ret = intel_ipu4_virtio_msg_parse(req_info);
+ } else {
+ pr_err("%s: Failed to get request buffer from queue!", __func__);
+ virtio_vq_relchain(vq, idx, iov.iov_len);
+ continue;
+ }
- if (req->stat == IPU4_REQ_NEEDS_FOLLOW_UP) {
- vq_req.vq = vq;
- vq_req.req = req;
- vq_req.idx = idx;
- vq_req.len = len;
- } else
- virtio_vq_relchain(vq, idx, len);
+ if (req->stat != IPU4_REQ_PENDING) {
+ virtio_vq_relchain(vq, idx, iov.iov_len);
+ ipu4_virtio_be_req_queue_put(req_info);
+ }
+ pr_debug("%s ending request for stream %d",
+ __func__, req->op[0]);
}
pr_debug("IPU VBK data process on VQ Done\n");
- if (req && req->stat != IPU4_REQ_NEEDS_FOLLOW_UP)
+ if ((req == NULL) || (req && req->stat !=
+ IPU4_REQ_PENDING))
virtio_vq_endchains(vq, 1);
}
@@ -229,11 +236,11 @@ static int handle_kick(int client_id, long unsigned *ioreqs_map)
return -EINVAL;
}
- count = ipu_virtio_vqs_index_get(&priv->dev, ioreqs_map, val, IPU_VIRTIO_QUEUE_MAX);
+ count = virtio_vqs_index_get(&priv->dev, ioreqs_map, val, IPU_VIRTIO_QUEUE_MAX);
for (i = 0; i < count; i++) {
if (val[i] >= 0) {
- handle_vq_kick(priv, val[i]);
+ handle_vq_kick(client_id, val[i]);
}
}
@@ -273,16 +280,16 @@ static int ipu_vbk_open(struct inode *inode, struct file *f)
virtio_dev_init(dev, vqs, IPU_VIRTIO_QUEUE_MAX);
- priv->pending_tx_req = kcalloc(1, sizeof(struct ipu4_virtio_req),
- GFP_KERNEL);
-
- mutex_init(&priv->lock);
+ mutex_init(&priv->mlock);
+ spin_lock_init(&priv->slock);
f->private_data = priv;
/* init a hash table to maintain multi-connections */
ipu_vbk_hash_init();
+ ipu4_virtio_be_req_queue_init();
+
return 0;
}
@@ -315,6 +322,8 @@ static int ipu_vbk_release(struct inode *inode, struct file *f)
kfree(priv);
+ ipu4_virtio_be_req_queue_free();
+
pr_debug("%s done\n", __func__);
return 0;
}
@@ -381,63 +390,36 @@ static long ipu_vbk_ioctl(struct file *f, unsigned int ioctl,
}
}
-int notify_fe(void)
+int notify_fe(int status, struct ipu4_virtio_req_info *req_info)
{
- if (vq_req.vq) {
- pr_debug("%s: notifying fe", __func__);
- vq_req.req->func_ret = 1;
- virtio_vq_relchain(vq_req.vq, vq_req.idx, vq_req.len);
- virtio_vq_endchains(vq_req.vq, 1);
- vq_req.vq = NULL;
- } else
- pr_debug("%s: NULL vq!", __func__);
-
- return 0;
-}
+ struct virtio_vq_info *vq;
+ struct ipu4_virtio_be_priv *be;
+ unsigned long flags = 0;
-int ipu_virtio_vqs_index_get(struct virtio_dev_info *dev, unsigned long *ioreqs_map,
- int *vqs_index, int max_vqs_index)
-{
- int idx = 0;
- struct vhm_request *req;
- int vcpu;
+ pr_debug("%s: notifying fe %d vq idx: %d cmd: %d",
+ __func__, req_info->request->op[0],
+ req_info->vq_info.vq_idx,
+ req_info->request->cmd);
- if (dev == NULL) {
- pr_err("%s: dev is NULL!\n", __func__);
+ be = ipu_vbk_hash_find(req_info->client_id);
+ if (be == NULL) {
+ pr_err("%s: client %d not found!\n",
+ __func__, req_info->client_id);
return -EINVAL;
}
- while (idx < max_vqs_index) {
- vcpu = find_first_bit(ioreqs_map, dev->_ctx.max_vcpu);
- if (vcpu == dev->_ctx.max_vcpu)
- break;
- req = &dev->_ctx.req_buf[vcpu];
- if (atomic_read(&req->processed) == REQ_STATE_PROCESSING &&
- req->client == dev->_ctx.vhm_client_id) {
- if (req->reqs.pio_request.direction == REQUEST_READ) {
- /* currently we handle kick only,
- * so read will return 0
- */
- pr_debug("%s: read request!\n", __func__);
- if (dev->io_range_type == PIO_RANGE)
- req->reqs.pio_request.value = 0;
- else
- req->reqs.mmio_request.value = 0;
- } else {
- pr_debug("%s: write request! type %d\n",
- __func__, req->type);
- if (dev->io_range_type == PIO_RANGE)
- vqs_index[idx++] = req->reqs.pio_request.value;
- else
- vqs_index[idx++] = req->reqs.mmio_request.value;
- }
- smp_mb();
- atomic_set(&req->processed, REQ_STATE_COMPLETE);
- acrn_ioreq_complete_request(req->client, vcpu);
- }
- }
+ vq = &(be->vqs[req_info->vq_info.vq_idx]);
+
+ req_info->request->stat = status;
- return idx;
+ spin_lock_irqsave(&be->slock, flags);
+ virtio_vq_relchain(vq, req_info->vq_info.vq_buf_idx,
+ req_info->vq_info.req_len);
+ virtio_vq_endchains(vq, 1);
+ ipu4_virtio_be_req_queue_put(req_info);
+ spin_unlock_irqrestore(&be->slock, flags);
+
+ return 0;
}
/* device specific function to cleanup itself */
diff --git a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be.h b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be.h
index 999b543b58f6..14929bb66b02 100644
--- a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be.h
+++ b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-be.h
@@ -8,8 +8,14 @@
#include <linux/vbs/vbs.h>
-int notify_fe(void);
-int ipu_virtio_vqs_index_get(struct virtio_dev_info *dev, unsigned long *ioreqs_map,
- int *vqs_index, int max_vqs_index);
+enum poll_status {
+ IPU4_POLL_PENDING = 0,
+ IPU4_POLL_AVAILABLE,
+ IPU4_POLL_STOP,
+ IPU4_POLL_SLEEP
+};
+
+int notify_fe(int status, struct ipu4_virtio_req_info *req_info);
+void notify_poll_thread(int stream_id, enum poll_status status);
#endif
diff --git a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-common.c b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-common.c
index 457c6bdf78a8..5e3b53c9c6e1 100644
--- a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-common.c
+++ b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-common.c
@@ -59,3 +59,80 @@ struct ipu4_virtio_fe_info *ipu4_virtio_fe_find_by_vmid(int vmid)
return NULL;
}
+
+int ipu4_virtio_fe_remove(int client_id)
+{
+ struct ipu4_virtio_fe_info_entry *info_entry;
+ int bkt;
+
+ hash_for_each(ipu4_virtio_fe_hash, bkt, info_entry, node)
+ if (info_entry->info->client_id == client_id) {
+ hash_del(&info_entry->node);
+ kfree(info_entry);
+ return 0;
+ }
+
+ return -ENOENT;
+}
+
+int ipu4_virtio_ring_init(struct ipu4_virtio_ring *ring,
+ int ring_size)
+{
+ ring->buffer = kcalloc(1, ring_size * sizeof(u64), GFP_KERNEL);
+
+ if (!ring->buffer) {
+ pr_err("%s: failed to allocate memory!", __func__);
+ return -ENOMEM;
+ }
+
+ ring->head = 0;
+ ring->tail = 0;
+ ring->used = 0;
+ ring->ring_size = ring_size;
+ spin_lock_init(&ring->lock);
+
+ return 0;
+}
+
+void ipu4_virtio_ring_free(struct ipu4_virtio_ring *ring)
+{
+ kfree(ring->buffer);
+ ring->buffer = NULL;
+}
+
+int ipu4_virtio_ring_push(struct ipu4_virtio_ring *ring, void *data)
+{
+ int next;
+
+ if (ring->used == ring->ring_size) {//ring full
+ pr_err("%s: Ring is full!! %d", __func__, ring->used);
+ return -1;
+ }
+
+ next = ring->head + 1;
+ next %= ring->ring_size;
+ ring->buffer[ring->head] = (u64)data;
+ ring->head = next;
+ ring->used++;
+
+ return 0;
+}
+
+void *ipu4_virtio_ring_pop(struct ipu4_virtio_ring *ring)
+{
+ int next;
+ void *data;
+
+ if (ring->used == 0)
+ return NULL;
+
+ next = ring->tail + 1;
+ next %= ring->ring_size;
+
+ data = (void *) ring->buffer[ring->tail];
+ ring->tail = next;
+
+ ring->used--;
+
+ return data;
+}
\ No newline at end of file
diff --git a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-common.h b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-common.h
index 8b2260b46169..78f40c3dabad 100644
--- a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-common.h
+++ b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-common.h
@@ -6,20 +6,19 @@
#ifndef __IPU4_VIRTIO_COMMON_H__
#define __IPU4_VIRTIO_COMMON_H__
-
/*
* CWP uses physicall addresses for memory sharing,
* so size of one page ref will be 64-bits
*/
#define REFS_PER_PAGE (PAGE_SIZE/sizeof(u64))
-
/* Defines size of requests circular buffer */
#define REQ_RING_SIZE 128
-
#define MAX_NUMBER_OF_OPERANDS 64
-
#define MAX_ENTRY_FE 7
+#define MAX_STREAM_DEVICES 64
+#define MAX_PIPELINE_DEVICES 1
+#define MAX_ISYS_VIRT_STREAM 34
enum virio_queue_type {
IPU_VIRTIO_QUEUE_0 = 0,
@@ -33,6 +32,8 @@ struct ipu4_virtio_req {
unsigned int cmd;
unsigned int func_ret;
unsigned int op[MAX_NUMBER_OF_OPERANDS];
+ struct completion wait;
+ struct list_head node;
u64 payload;
};
struct test_payload {
@@ -114,10 +115,44 @@ enum intel_ipu4_virtio_command {
enum intel_ipu4_virtio_req_feedback {
IPU4_REQ_PROCESSED,
- IPU4_REQ_NEEDS_FOLLOW_UP,
+ IPU4_REQ_PENDING,
IPU4_REQ_ERROR,
IPU4_REQ_NOT_RESPONDED
};
+
+struct ipu4_virtio_ring {
+ /* Buffer allocated for keeping ring entries */
+ u64 *buffer;
+
+ /* Index pointing to next free element in ring */
+ int head;
+
+ /* Index pointing to last released element in ring */
+ int tail;
+
+ /* Total number of elements that ring can contain */
+ int ring_size;
+
+ /* Number of location in ring has been used */
+ unsigned int used;
+
+ /* Multi thread sync */
+ spinlock_t lock;
+};
+
+/* Create the ring buffer with given size */
+int ipu4_virtio_ring_init(struct ipu4_virtio_ring *ring,
+ int ring_size);
+
+/* Frees the ring buffers */
+void ipu4_virtio_ring_free(struct ipu4_virtio_ring *ring);
+
+/* Add a buffer to ring */
+int ipu4_virtio_ring_push(struct ipu4_virtio_ring *ring, void *data);
+
+/* Grab a buffer from ring */
+void *ipu4_virtio_ring_pop(struct ipu4_virtio_ring *ring);
+
extern struct ipu4_bknd_ops ipu4_virtio_bknd_ops;
void ipu4_virtio_fe_table_init(void);
diff --git a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-fe-pipeline.c b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-fe-pipeline.c
index 0f5d8b6f83ec..8122d8177104 100644
--- a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-fe-pipeline.c
+++ b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-fe-pipeline.c
@@ -11,6 +11,7 @@
#include "intel-ipu4-virtio-fe-payload.h"
#include "intel-ipu4-virtio-fe-pipeline.h"
+#include "intel-ipu4-virtio-fe-request-queue.h"
int process_pipeline(struct file *file, struct ipu4_virtio_ctx *fe_priv,
void *data, int cmd)
@@ -22,7 +23,7 @@ int process_pipeline(struct file *file, struct ipu4_virtio_ctx *fe_priv,
op[0] = 0;
op[1] = 0;
- req = kcalloc(1, sizeof(*req), GFP_KERNEL);
+ req = ipu4_virtio_fe_req_queue_get();
if (!req)
return -ENOMEM;
@@ -33,11 +34,11 @@ int process_pipeline(struct file *file, struct ipu4_virtio_ctx *fe_priv,
rval = fe_priv->bknd_ops->send_req(fe_priv->domid, req, true, IPU_VIRTIO_QUEUE_0);
if (rval) {
pr_err("Failed to send request to BE\n");
- kfree(req);
+ ipu4_virtio_fe_req_queue_put(req);
return rval;
}
- kfree(req);
+ ipu4_virtio_fe_req_queue_put(req);
return rval;
}
diff --git a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-fe-request-queue.c b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-fe-request-queue.c
new file mode 100644
index 000000000000..09294da549ab
--- /dev/null
+++ b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-fe-request-queue.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
+/*
+ * Copyright (C) 2018 Intel Corporation
+ */
+
+#include <linux/virtio.h>
+#include <linux/spinlock.h>
+#include "intel-ipu4-virtio-common.h"
+#include "intel-ipu4-virtio-fe-request-queue.h"
+
+struct ipu4_virtio_ring ipu4_virtio_fe_req_queue;
+
+int ipu4_virtio_fe_req_queue_init(void)
+{
+ int i;
+ struct ipu4_virtio_req *req;
+
+ if (ipu4_virtio_ring_init(&ipu4_virtio_fe_req_queue, REQ_RING_SIZE))
+ return -1;
+
+ for (i = 0; i < REQ_RING_SIZE; i++) {
+ req = kcalloc(1, sizeof(struct ipu4_virtio_req), GFP_KERNEL);
+ if (req == NULL) {
+ pr_err("%s failed to allocate memory for ipu4_virtio_req",
+ __func__);
+ return -1;
+ }
+ init_completion(&req->wait);
+ ipu4_virtio_ring_push(&ipu4_virtio_fe_req_queue, req);
+ }
+ return 0;
+}
+
+void ipu4_virtio_fe_req_queue_free(void)
+{
+ int i;
+ struct ipu4_virtio_req *req;
+
+ for (i = 0; i < REQ_RING_SIZE; i++) {
+ req = ipu4_virtio_ring_pop(&ipu4_virtio_fe_req_queue);
+ if (req)
+ kfree(req);
+ else
+ break;
+ }
+ ipu4_virtio_ring_free(&ipu4_virtio_fe_req_queue);
+}
+
+struct ipu4_virtio_req *ipu4_virtio_fe_req_queue_get(void)
+{
+ struct ipu4_virtio_req *req;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&ipu4_virtio_fe_req_queue.lock, flags);
+ req = ipu4_virtio_ring_pop(&ipu4_virtio_fe_req_queue);
+ spin_unlock_irqrestore(&ipu4_virtio_fe_req_queue.lock, flags);
+ if (req)
+ reinit_completion(&req->wait);
+ return req;
+}
+
+int ipu4_virtio_fe_req_queue_put(
+ struct ipu4_virtio_req *req)
+{
+ unsigned long flags = 0;
+ int status;
+
+ spin_lock_irqsave(&ipu4_virtio_fe_req_queue.lock, flags);
+ status = ipu4_virtio_ring_push(&ipu4_virtio_fe_req_queue, req);
+ spin_unlock_irqrestore(&ipu4_virtio_fe_req_queue.lock, flags);
+ return status;
+}
diff --git a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-fe-request-queue.h b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-fe-request-queue.h
new file mode 100644
index 000000000000..9a36c99f9b5b
--- /dev/null
+++ b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-fe-request-queue.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) */
+/*
+ * Copyright (C) 2018 Intel Corporation
+ */
+
+#ifndef IPU4_VIRTIO_FE_REQUEST_QUEUE_H
+#define IPU4_VIRTIO_FE_REQUEST_QUEUE_H
+
+int ipu4_virtio_fe_req_queue_init(void);
+void ipu4_virtio_fe_req_queue_free(void);
+struct ipu4_virtio_req *ipu4_virtio_fe_req_queue_get(void);
+int ipu4_virtio_fe_req_queue_put(struct ipu4_virtio_req *req);
+
+#endif
diff --git a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-fe.c b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-fe.c
index d95e52a09b32..29b8b4767f02 100644
--- a/drivers/media/pci/intel/virtio/intel-ipu4-virtio-fe.c
+++ b/drivers/media/pci/intel/virtio/intel-ipu4-virtio-fe.c
@@ -17,40 +17,54 @@ static DEFINE_IDA(index_ida);
struct ipu4_virtio_uos {
struct virtqueue *vq[IPU_VIRTIO_QUEUE_MAX];
- struct completion have_data;
char name[25];
unsigned int data_avail;
+ spinlock_t lock;
int index;
bool busy;
int vmid;
};
-struct completion completion_queue[IPU_VIRTIO_QUEUE_MAX];
-
/* Assuming there will be one FE instance per VM */
static struct ipu4_virtio_uos *ipu4_virtio_fe;
static void ipu_virtio_fe_tx_done_vq_0(struct virtqueue *vq)
{
struct ipu4_virtio_uos *priv = (struct ipu4_virtio_uos *)vq->vdev->priv;
+ struct ipu4_virtio_req *req;
+ unsigned long flags = 0;
+
+ do {
+ spin_lock_irqsave(&priv->lock, flags);
+ req = (struct ipu4_virtio_req *)
+ virtqueue_get_buf(vq, &priv->data_avail);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ if (req != NULL &&
+ priv->data_avail == sizeof(struct ipu4_virtio_req)) {
+ complete(&req->wait);
+ }
+ } while (req != NULL);
- /* We can get spurious callbacks, e.g. shared IRQs + virtio_pci. */
- if (!virtqueue_get_buf(vq, &priv->data_avail))
- return;
-
- complete(&completion_queue[0]);
pr_debug("IPU FE:%s vmid:%d TX for VQ 0 done\n", __func__, priv->vmid);
}
static void ipu_virtio_fe_tx_done_vq_1(struct virtqueue *vq)
{
struct ipu4_virtio_uos *priv = (struct ipu4_virtio_uos *)vq->vdev->priv;
+ struct ipu4_virtio_req *req;
+ unsigned long flags = 0;
+
+ do {
+ spin_lock_irqsave(&priv->lock, flags);
+ req = (struct ipu4_virtio_req *)
+ virtqueue_get_buf(vq, &priv->data_avail);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ if (req != NULL &&
+ priv->data_avail == sizeof(struct ipu4_virtio_req)) {
+ complete(&req->wait);
+ }
+ } while (req != NULL);
- /* We can get spurious callbacks, e.g. shared IRQs + virtio_pci. */
- if (!virtqueue_get_buf(vq, &priv->data_avail))
- return;
-
- complete(&completion_queue[1]);
pr_debug("IPU FE:%s vmid:%d TX for VQ 1 done\n", __func__, priv->vmid);
}
@@ -59,6 +73,8 @@ static void ipu_virtio_fe_register_buffer(struct ipu4_virtio_uos *vi, void *buf,
int nqueue)
{
struct scatterlist sg;
+ unsigned long flags = 0;
+
if (nqueue >= IPU_VIRTIO_QUEUE_MAX) {
pr_debug("Number of queue exceeding max queue number\n");
return;
@@ -66,19 +82,25 @@ static void ipu_virtio_fe_register_buffer(struct ipu4_virtio_uos *vi, void *buf,
sg_init_one(&sg, buf, size);
+ spin_lock_irqsave(&vi->lock, flags);
/* There should always be room for one buffer. */
virtqueue_add_inbuf(vi->vq[nqueue], &sg, 1, buf, GFP_KERNEL);
+ spin_unlock_irqrestore(&vi->lock, flags);
+
virtqueue_kick(vi->vq[nqueue]);
}
static int ipu_virtio_fe_probe_common(struct virtio_device *vdev)
{
- int err, index, i;
+ int err, index;
struct ipu4_virtio_uos *priv = NULL;
- vq_callback_t *callbacks[] = {ipu_virtio_fe_tx_done_vq_0,
+ vq_callback_t *callbacks[] = {
+ ipu_virtio_fe_tx_done_vq_0,
ipu_virtio_fe_tx_done_vq_1};
- static const char *names[] = {"csi_queue_0", "csi_queue_1"};
+ static const char * const names[] = {
+ "csi_queue_0",
+ "csi_queue_1"};
priv = kzalloc(sizeof(struct ipu4_virtio_uos), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -89,8 +111,6 @@ static int ipu_virtio_fe_probe_common(struct virtio_device *vdev)
goto err_ida;
}
sprintf(priv->name, "virtio_.%d", index);
- for (i = 0; i < IPU_VIRTIO_QUEUE_MAX; i++)
- init_completion(&completion_queue[i]);
priv->vmid = -1;
vdev->priv = priv;
err = virtio_find_vqs(vdev, IPU_VIRTIO_QUEUE_MAX,
@@ -98,6 +118,8 @@ static int ipu_virtio_fe_probe_common(struct virtio_device *vdev)
if (err)
goto err_find;
+ spin_lock_init(&priv->lock);
+
ipu4_virtio_fe = priv;
return 0;
@@ -112,11 +134,8 @@ static int ipu_virtio_fe_probe_common(struct virtio_device *vdev)
static void ipu_virtio_fe_remove_common(struct virtio_device *vdev)
{
struct ipu4_virtio_uos *priv = vdev->priv;
- int i;
priv->data_avail = 0;
- for (i = 0; i < IPU_VIRTIO_QUEUE_MAX; i++)
- complete(&completion_queue[i]);
vdev->config->reset(vdev);
priv->busy = false;
@@ -135,10 +154,8 @@ static int ipu_virtio_fe_send_req(int vmid, struct ipu4_virtio_req *req,
pr_err("IPU Backend not connected\n");
return -ENOENT;
}
-
- init_completion(&completion_queue[idx]);
ipu_virtio_fe_register_buffer(ipu4_virtio_fe, req, sizeof(*req), idx);
- wait_for_completion(&completion_queue[idx]);
+ wait_for_completion(&req->wait);
return ret;
}
--
2.19.2