All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/8] misc: fastrpc: few fixes
@ 2019-03-07 10:12 Srinivas Kandagatla
  2019-03-07 10:12 ` [PATCH 1/8] misc: fastrpc: Avoid free of DMA buffer in interrupt context Srinivas Kandagatla
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: Srinivas Kandagatla @ 2019-03-07 10:12 UTC (permalink / raw)
  To: gregkh, arnd
  Cc: linux-kernel, bjorn.andersson, bkumar, linux-arm-msm, ktadakam,
	Srinivas Kandagatla

Hi Greg, 

Doing some stress testing and Neural Processing library showed up some bugs
in the code, this patchset fix them.

Thanks to Bharath and Krish for testing and helping me debug the issues.

Thanks,
srini


Srinivas Kandagatla (6):
  misc: fastrpc: make sure memory read and writes are visible
  misc: fastrpc: use correct spinlock variant
  misc: fastrpc: consider address offset before sending to DSP
  misc: fastrpc: take into account of overlapping buffers
  misc: fastrpc: fix remote page size calculation
  misc: fastrpc: increase max init file size to 64 MB

Thierry Escande (2):
  misc: fastrpc: Avoid free of DMA buffer in interrupt context
  misc: fastrpc: Fix a possible double free

 drivers/misc/fastrpc.c | 235 ++++++++++++++++++++++++++++++++---------
 1 file changed, 187 insertions(+), 48 deletions(-)

-- 
2.21.0

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/8] misc: fastrpc: Avoid free of DMA buffer in interrupt context
  2019-03-07 10:12 [PATCH 0/8] misc: fastrpc: few fixes Srinivas Kandagatla
@ 2019-03-07 10:12 ` Srinivas Kandagatla
  2019-03-07 10:12 ` [PATCH 2/8] misc: fastrpc: Fix a possible double free Srinivas Kandagatla
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Srinivas Kandagatla @ 2019-03-07 10:12 UTC (permalink / raw)
  To: gregkh, arnd
  Cc: linux-kernel, bjorn.andersson, bkumar, linux-arm-msm, ktadakam,
	Thierry Escande, Srinivas Kandagatla

From: Thierry Escande <thierry.escande@linaro.org>

When the remote DSP invocation is interrupted by the user, the
associated DMA buffer can be freed in interrupt context causing a kernel
BUG.

This patch adds a worker thread associated to the fastrpc context. It
is scheduled in the rpmsg callback to decrease its refcount out of the
interrupt context.

Fixes: c68cfb718c8f ("misc: fastrpc: Add support for context Invoke method")
Signed-off-by: Thierry Escande <thierry.escande@linaro.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/misc/fastrpc.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 89aec17738ef..82e7217ae87a 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -149,6 +149,7 @@ struct fastrpc_invoke_ctx {
 	struct kref refcount;
 	struct list_head node; /* list of ctxs */
 	struct completion work;
+	struct work_struct put_work;
 	struct fastrpc_msg msg;
 	struct fastrpc_user *fl;
 	struct fastrpc_remote_arg *rpra;
@@ -311,6 +312,14 @@ static void fastrpc_context_put(struct fastrpc_invoke_ctx *ctx)
 	kref_put(&ctx->refcount, fastrpc_context_free);
 }
 
+static void fastrpc_context_put_wq(struct work_struct *work)
+{
+	struct fastrpc_invoke_ctx *ctx =
+			container_of(work, struct fastrpc_invoke_ctx, put_work);
+
+	fastrpc_context_put(ctx);
+}
+
 static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
 			struct fastrpc_user *user, u32 kernel, u32 sc,
 			struct fastrpc_invoke_args *args)
@@ -345,6 +354,7 @@ static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
 	ctx->tgid = user->tgid;
 	ctx->cctx = cctx;
 	init_completion(&ctx->work);
+	INIT_WORK(&ctx->put_work, fastrpc_context_put_wq);
 
 	spin_lock(&user->lock);
 	list_add_tail(&ctx->node, &user->pending);
@@ -1349,7 +1359,13 @@ static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
 
 	ctx->retval = rsp->retval;
 	complete(&ctx->work);
-	fastrpc_context_put(ctx);
+
+	/*
+	 * The DMA buffer associated with the context cannot be freed in
+	 * interrupt context so schedule it through a worker thread to
+	 * avoid a kernel BUG.
+	 */
+	schedule_work(&ctx->put_work);
 
 	return 0;
 }
-- 
2.21.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/8] misc: fastrpc: Fix a possible double free
  2019-03-07 10:12 [PATCH 0/8] misc: fastrpc: few fixes Srinivas Kandagatla
  2019-03-07 10:12 ` [PATCH 1/8] misc: fastrpc: Avoid free of DMA buffer in interrupt context Srinivas Kandagatla
@ 2019-03-07 10:12 ` Srinivas Kandagatla
  2019-03-07 10:12 ` [PATCH 3/8] misc: fastrpc: make sure memory read and writes are visible Srinivas Kandagatla
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Srinivas Kandagatla @ 2019-03-07 10:12 UTC (permalink / raw)
  To: gregkh, arnd
  Cc: linux-kernel, bjorn.andersson, bkumar, linux-arm-msm, ktadakam,
	Thierry Escande, Srinivas Kandagatla

From: Thierry Escande <thierry.escande@linaro.org>

This patch fixes the error exit path of fastrpc_init_create_process().
If the DMA allocation or the DSP invoke fails the fastrpc_map was freed
but not removed from the mapping list leading to a double free once the
mapping list is emptied in fastrpc_device_release().

[srinivas kandagatla]: Cleaned up error path labels and reset init mem
to NULL after free
Fixes: d73f71c7c6ee("misc: fastrpc: Add support for create remote init process")
Signed-off-by: Thierry Escande <thierry.escande@linaro.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/misc/fastrpc.c | 31 ++++++++++++++++++++-----------
 1 file changed, 20 insertions(+), 11 deletions(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 82e7217ae87a..8fbcc607a77e 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -853,12 +853,12 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl,
 
 	if (copy_from_user(&init, argp, sizeof(init))) {
 		err = -EFAULT;
-		goto bail;
+		goto err;
 	}
 
 	if (init.filelen > INIT_FILELEN_MAX) {
 		err = -EINVAL;
-		goto bail;
+		goto err;
 	}
 
 	inbuf.pgid = fl->tgid;
@@ -872,17 +872,15 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl,
 	if (init.filelen && init.filefd) {
 		err = fastrpc_map_create(fl, init.filefd, init.filelen, &map);
 		if (err)
-			goto bail;
+			goto err;
 	}
 
 	memlen = ALIGN(max(INIT_FILELEN_MAX, (int)init.filelen * 4),
 		       1024 * 1024);
 	err = fastrpc_buf_alloc(fl, fl->sctx->dev, memlen,
 				&imem);
-	if (err) {
-		fastrpc_map_put(map);
-		goto bail;
-	}
+	if (err)
+		goto err_alloc;
 
 	fl->init_mem = imem;
 	args[0].ptr = (u64)(uintptr_t)&inbuf;
@@ -918,13 +916,24 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl,
 
 	err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE,
 				      sc, args);
+	if (err)
+		goto err_invoke;
 
-	if (err) {
+	kfree(args);
+
+	return 0;
+
+err_invoke:
+	fl->init_mem = NULL;
+	fastrpc_buf_free(imem);
+err_alloc:
+	if (map) {
+		spin_lock(&fl->lock);
+		list_del(&map->node);
+		spin_unlock(&fl->lock);
 		fastrpc_map_put(map);
-		fastrpc_buf_free(imem);
 	}
-
-bail:
+err:
 	kfree(args);
 
 	return err;
-- 
2.21.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 3/8] misc: fastrpc: make sure memory read and writes are visible
  2019-03-07 10:12 [PATCH 0/8] misc: fastrpc: few fixes Srinivas Kandagatla
  2019-03-07 10:12 ` [PATCH 1/8] misc: fastrpc: Avoid free of DMA buffer in interrupt context Srinivas Kandagatla
  2019-03-07 10:12 ` [PATCH 2/8] misc: fastrpc: Fix a possible double free Srinivas Kandagatla
@ 2019-03-07 10:12 ` Srinivas Kandagatla
  2019-03-07 10:12 ` [PATCH 4/8] misc: fastrpc: use correct spinlock variant Srinivas Kandagatla
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Srinivas Kandagatla @ 2019-03-07 10:12 UTC (permalink / raw)
  To: gregkh, arnd
  Cc: linux-kernel, bjorn.andersson, bkumar, linux-arm-msm, ktadakam,
	Srinivas Kandagatla

dma_alloc_coherent buffers could have writes queued in store buffers so
commit them before sending buffer to DSP using correct dma barriers.
Same with vice-versa.

Fixes: c68cfb718c8f ("misc: fastrpc: Add support for context Invoke method")
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/misc/fastrpc.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 8fbcc607a77e..753d62ceb1fb 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -792,6 +792,9 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl,  u32 kernel,
 		if (err)
 			goto bail;
 	}
+
+	/* make sure that all CPU memory writes are seen by DSP */
+	dma_wmb();
 	/* Send invoke buffer to remote dsp */
 	err = fastrpc_invoke_send(fl->sctx, ctx, kernel, handle);
 	if (err)
@@ -808,6 +811,8 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl,  u32 kernel,
 		goto bail;
 
 	if (ctx->nscalars) {
+		/* make sure that all memory writes by DSP are seen by CPU */
+		dma_rmb();
 		/* populate all the output buffers with results */
 		err = fastrpc_put_args(ctx, kernel);
 		if (err)
-- 
2.21.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 4/8] misc: fastrpc: use correct spinlock variant
  2019-03-07 10:12 [PATCH 0/8] misc: fastrpc: few fixes Srinivas Kandagatla
                   ` (2 preceding siblings ...)
  2019-03-07 10:12 ` [PATCH 3/8] misc: fastrpc: make sure memory read and writes are visible Srinivas Kandagatla
@ 2019-03-07 10:12 ` Srinivas Kandagatla
  2019-03-07 10:12 ` [PATCH 5/8] misc: fastrpc: consider address offset before sending to DSP Srinivas Kandagatla
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Srinivas Kandagatla @ 2019-03-07 10:12 UTC (permalink / raw)
  To: gregkh, arnd
  Cc: linux-kernel, bjorn.andersson, bkumar, linux-arm-msm, ktadakam,
	Srinivas Kandagatla

context spin lock can be interrupted from callback path so use correct spinlock
so that we do not hit spinlock recursion.

Fixes: c68cfb718c8f ("misc: fastrpc: Add support for context Invoke method")
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/misc/fastrpc.c | 48 +++++++++++++++++++++++++-----------------
 1 file changed, 29 insertions(+), 19 deletions(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 753d62ceb1fb..f71b5faae1dd 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -283,6 +283,7 @@ static void fastrpc_context_free(struct kref *ref)
 {
 	struct fastrpc_invoke_ctx *ctx;
 	struct fastrpc_channel_ctx *cctx;
+	unsigned long flags;
 	int i;
 
 	ctx = container_of(ref, struct fastrpc_invoke_ctx, refcount);
@@ -294,9 +295,9 @@ static void fastrpc_context_free(struct kref *ref)
 	if (ctx->buf)
 		fastrpc_buf_free(ctx->buf);
 
-	spin_lock(&cctx->lock);
+	spin_lock_irqsave(&cctx->lock, flags);
 	idr_remove(&cctx->ctx_idr, ctx->ctxid >> 4);
-	spin_unlock(&cctx->lock);
+	spin_unlock_irqrestore(&cctx->lock, flags);
 
 	kfree(ctx->maps);
 	kfree(ctx);
@@ -326,6 +327,7 @@ static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
 {
 	struct fastrpc_channel_ctx *cctx = user->cctx;
 	struct fastrpc_invoke_ctx *ctx = NULL;
+	unsigned long flags;
 	int ret;
 
 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
@@ -360,15 +362,15 @@ static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
 	list_add_tail(&ctx->node, &user->pending);
 	spin_unlock(&user->lock);
 
-	spin_lock(&cctx->lock);
+	spin_lock_irqsave(&cctx->lock, flags);
 	ret = idr_alloc_cyclic(&cctx->ctx_idr, ctx, 1,
 			       FASTRPC_CTX_MAX, GFP_ATOMIC);
 	if (ret < 0) {
-		spin_unlock(&cctx->lock);
+		spin_unlock_irqrestore(&cctx->lock, flags);
 		goto err_idr;
 	}
 	ctx->ctxid = ret << 4;
-	spin_unlock(&cctx->lock);
+	spin_unlock_irqrestore(&cctx->lock, flags);
 
 	kref_init(&ctx->refcount);
 
@@ -948,9 +950,10 @@ static struct fastrpc_session_ctx *fastrpc_session_alloc(
 					struct fastrpc_channel_ctx *cctx)
 {
 	struct fastrpc_session_ctx *session = NULL;
+	unsigned long flags;
 	int i;
 
-	spin_lock(&cctx->lock);
+	spin_lock_irqsave(&cctx->lock, flags);
 	for (i = 0; i < cctx->sesscount; i++) {
 		if (!cctx->session[i].used && cctx->session[i].valid) {
 			cctx->session[i].used = true;
@@ -958,7 +961,7 @@ static struct fastrpc_session_ctx *fastrpc_session_alloc(
 			break;
 		}
 	}
-	spin_unlock(&cctx->lock);
+	spin_unlock_irqrestore(&cctx->lock, flags);
 
 	return session;
 }
@@ -966,9 +969,11 @@ static struct fastrpc_session_ctx *fastrpc_session_alloc(
 static void fastrpc_session_free(struct fastrpc_channel_ctx *cctx,
 				 struct fastrpc_session_ctx *session)
 {
-	spin_lock(&cctx->lock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&cctx->lock, flags);
 	session->used = false;
-	spin_unlock(&cctx->lock);
+	spin_unlock_irqrestore(&cctx->lock, flags);
 }
 
 static int fastrpc_release_current_dsp_process(struct fastrpc_user *fl)
@@ -994,12 +999,13 @@ static int fastrpc_device_release(struct inode *inode, struct file *file)
 	struct fastrpc_channel_ctx *cctx = fl->cctx;
 	struct fastrpc_invoke_ctx *ctx, *n;
 	struct fastrpc_map *map, *m;
+	unsigned long flags;
 
 	fastrpc_release_current_dsp_process(fl);
 
-	spin_lock(&cctx->lock);
+	spin_lock_irqsave(&cctx->lock, flags);
 	list_del(&fl->user);
-	spin_unlock(&cctx->lock);
+	spin_unlock_irqrestore(&cctx->lock, flags);
 
 	if (fl->init_mem)
 		fastrpc_buf_free(fl->init_mem);
@@ -1027,6 +1033,7 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp)
 {
 	struct fastrpc_channel_ctx *cctx = miscdev_to_cctx(filp->private_data);
 	struct fastrpc_user *fl = NULL;
+	unsigned long flags;
 
 	fl = kzalloc(sizeof(*fl), GFP_KERNEL);
 	if (!fl)
@@ -1050,9 +1057,9 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp)
 		return -EBUSY;
 	}
 
-	spin_lock(&cctx->lock);
+	spin_lock_irqsave(&cctx->lock, flags);
 	list_add_tail(&fl->user, &cctx->users);
-	spin_unlock(&cctx->lock);
+	spin_unlock_irqrestore(&cctx->lock, flags);
 
 	return 0;
 }
@@ -1208,6 +1215,7 @@ static int fastrpc_cb_probe(struct platform_device *pdev)
 	struct fastrpc_session_ctx *sess;
 	struct device *dev = &pdev->dev;
 	int i, sessions = 0;
+	unsigned long flags;
 
 	cctx = dev_get_drvdata(dev->parent);
 	if (!cctx)
@@ -1215,7 +1223,7 @@ static int fastrpc_cb_probe(struct platform_device *pdev)
 
 	of_property_read_u32(dev->of_node, "qcom,nsessions", &sessions);
 
-	spin_lock(&cctx->lock);
+	spin_lock_irqsave(&cctx->lock, flags);
 	sess = &cctx->session[cctx->sesscount];
 	sess->used = false;
 	sess->valid = true;
@@ -1236,7 +1244,7 @@ static int fastrpc_cb_probe(struct platform_device *pdev)
 		}
 	}
 	cctx->sesscount++;
-	spin_unlock(&cctx->lock);
+	spin_unlock_irqrestore(&cctx->lock, flags);
 	dma_set_mask(dev, DMA_BIT_MASK(32));
 
 	return 0;
@@ -1246,16 +1254,17 @@ static int fastrpc_cb_remove(struct platform_device *pdev)
 {
 	struct fastrpc_channel_ctx *cctx = dev_get_drvdata(pdev->dev.parent);
 	struct fastrpc_session_ctx *sess = dev_get_drvdata(&pdev->dev);
+	unsigned long flags;
 	int i;
 
-	spin_lock(&cctx->lock);
+	spin_lock_irqsave(&cctx->lock, flags);
 	for (i = 1; i < FASTRPC_MAX_SESSIONS; i++) {
 		if (cctx->session[i].sid == sess->sid) {
 			cctx->session[i].valid = false;
 			cctx->sesscount--;
 		}
 	}
-	spin_unlock(&cctx->lock);
+	spin_unlock_irqrestore(&cctx->lock, flags);
 
 	return 0;
 }
@@ -1337,11 +1346,12 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
 {
 	struct fastrpc_channel_ctx *cctx = dev_get_drvdata(&rpdev->dev);
 	struct fastrpc_user *user;
+	unsigned long flags;
 
-	spin_lock(&cctx->lock);
+	spin_lock_irqsave(&cctx->lock, flags);
 	list_for_each_entry(user, &cctx->users, user)
 		fastrpc_notify_users(user);
-	spin_unlock(&cctx->lock);
+	spin_unlock_irqrestore(&cctx->lock, flags);
 
 	misc_deregister(&cctx->miscdev);
 	of_platform_depopulate(&rpdev->dev);
-- 
2.21.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 5/8] misc: fastrpc: consider address offset before sending to DSP
  2019-03-07 10:12 [PATCH 0/8] misc: fastrpc: few fixes Srinivas Kandagatla
                   ` (3 preceding siblings ...)
  2019-03-07 10:12 ` [PATCH 4/8] misc: fastrpc: use correct spinlock variant Srinivas Kandagatla
@ 2019-03-07 10:12 ` Srinivas Kandagatla
  2019-03-07 10:12 ` [PATCH 6/8] misc: fastrpc: take into account of overlapping buffers Srinivas Kandagatla
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: Srinivas Kandagatla @ 2019-03-07 10:12 UTC (permalink / raw)
  To: gregkh, arnd
  Cc: linux-kernel, bjorn.andersson, bkumar, linux-arm-msm, ktadakam,
	Srinivas Kandagatla

While passing address phy address to DSP, take care of the offset
calculated from virtual address vma.

Fixes: c68cfb718c8f ("misc: fastrpc: Add support for context Invoke method")
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/misc/fastrpc.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index f71b5faae1dd..209f3e63f660 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -679,8 +679,16 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
 		pages[i].size = roundup(len, PAGE_SIZE);
 
 		if (ctx->maps[i]) {
+			struct vm_area_struct *vma = NULL;
+
 			rpra[i].pv = (u64) ctx->args[i].ptr;
 			pages[i].addr = ctx->maps[i]->phys;
+
+			vma = find_vma(current->mm, ctx->args[i].ptr);
+			if (vma)
+				pages[i].addr += ctx->args[i].ptr -
+						 vma->vm_start;
+
 		} else {
 			rlen -= ALIGN(args, FASTRPC_ALIGN) - args;
 			args = ALIGN(args, FASTRPC_ALIGN);
-- 
2.21.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 6/8] misc: fastrpc: take into account of overlapping buffers
  2019-03-07 10:12 [PATCH 0/8] misc: fastrpc: few fixes Srinivas Kandagatla
                   ` (4 preceding siblings ...)
  2019-03-07 10:12 ` [PATCH 5/8] misc: fastrpc: consider address offset before sending to DSP Srinivas Kandagatla
@ 2019-03-07 10:12 ` Srinivas Kandagatla
  2019-03-07 10:12 ` [PATCH 7/8] misc: fastrpc: fix remote page size calculation Srinivas Kandagatla
  2019-03-07 10:12 ` [PATCH 8/8] misc: fastrpc: increase max init file size to 64 MB Srinivas Kandagatla
  7 siblings, 0 replies; 9+ messages in thread
From: Srinivas Kandagatla @ 2019-03-07 10:12 UTC (permalink / raw)
  To: gregkh, arnd
  Cc: linux-kernel, bjorn.andersson, bkumar, linux-arm-msm, ktadakam,
	Srinivas Kandagatla

Argument buffers that are passed could be derived from a big buffer,
and some of the arguments buffers could overlap each other.
Take care of such instanaces.

This is optimization that DSP expects while sending buffers
which overlap. So make the DSP happy doing it.

Without which DSP seems to crash.

Fixes: c68cfb718c8f ("misc: fastrpc: Add support for context Invoke method")
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/misc/fastrpc.c | 112 +++++++++++++++++++++++++++++++++++------
 1 file changed, 98 insertions(+), 14 deletions(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 209f3e63f660..17bbb017bb08 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <linux/of_address.h>
 #include <linux/of.h>
+#include <linux/sort.h>
 #include <linux/of_platform.h>
 #include <linux/rpmsg.h>
 #include <linux/scatterlist.h>
@@ -104,6 +105,15 @@ struct fastrpc_invoke_rsp {
 	int retval;		/* invoke return value */
 };
 
+struct fastrpc_buf_overlap {
+	u64 start;
+	u64 end;
+	int raix;
+	u64 mstart;
+	u64 mend;
+	u64 offset;
+};
+
 struct fastrpc_buf {
 	struct fastrpc_user *fl;
 	struct dma_buf *dmabuf;
@@ -156,6 +166,7 @@ struct fastrpc_invoke_ctx {
 	struct fastrpc_map **maps;
 	struct fastrpc_buf *buf;
 	struct fastrpc_invoke_args *args;
+	struct fastrpc_buf_overlap *olaps;
 	struct fastrpc_channel_ctx *cctx;
 };
 
@@ -300,6 +311,7 @@ static void fastrpc_context_free(struct kref *ref)
 	spin_unlock_irqrestore(&cctx->lock, flags);
 
 	kfree(ctx->maps);
+	kfree(ctx->olaps);
 	kfree(ctx);
 }
 
@@ -321,6 +333,55 @@ static void fastrpc_context_put_wq(struct work_struct *work)
 	fastrpc_context_put(ctx);
 }
 
+#define CMP(aa, bb) ((aa) == (bb) ? 0 : (aa) < (bb) ? -1 : 1)
+static int olaps_cmp(const void *a, const void *b)
+{
+	struct fastrpc_buf_overlap *pa = (struct fastrpc_buf_overlap *)a;
+	struct fastrpc_buf_overlap *pb = (struct fastrpc_buf_overlap *)b;
+	/* sort with lowest starting buffer first */
+	int st = CMP(pa->start, pb->start);
+	/* sort with highest ending buffer first */
+	int ed = CMP(pb->end, pa->end);
+
+	return st == 0 ? ed : st;
+}
+
+static void fastrpc_get_buff_overlaps(struct fastrpc_invoke_ctx *ctx)
+{
+	u64 max_end = 0;
+	int i;
+
+	for (i = 0; i < ctx->nbufs; ++i) {
+		ctx->olaps[i].start = ctx->args[i].ptr;
+		ctx->olaps[i].end = ctx->olaps[i].start + ctx->args[i].length;
+		ctx->olaps[i].raix = i;
+	}
+
+	sort(ctx->olaps, ctx->nbufs, sizeof(*ctx->olaps), olaps_cmp, NULL);
+
+	for (i = 0; i < ctx->nbufs; ++i) {
+		/* Falling inside previous range */
+		if (ctx->olaps[i].start < max_end) {
+			ctx->olaps[i].mstart = max_end;
+			ctx->olaps[i].mend = ctx->olaps[i].end;
+			ctx->olaps[i].offset = max_end - ctx->olaps[i].start;
+
+			if (ctx->olaps[i].end > max_end) {
+				max_end = ctx->olaps[i].end;
+			} else {
+				ctx->olaps[i].mend = 0;
+				ctx->olaps[i].mstart = 0;
+			}
+
+		} else  {
+			ctx->olaps[i].mend = ctx->olaps[i].end;
+			ctx->olaps[i].mstart = ctx->olaps[i].start;
+			ctx->olaps[i].offset = 0;
+			max_end = ctx->olaps[i].end;
+		}
+	}
+}
+
 static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
 			struct fastrpc_user *user, u32 kernel, u32 sc,
 			struct fastrpc_invoke_args *args)
@@ -347,7 +408,15 @@ static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
 			kfree(ctx);
 			return ERR_PTR(-ENOMEM);
 		}
+		ctx->olaps = kcalloc(ctx->nscalars,
+				    sizeof(*ctx->olaps), GFP_KERNEL);
+		if (!ctx->olaps) {
+			kfree(ctx->maps);
+			kfree(ctx);
+			return ERR_PTR(-ENOMEM);
+		}
 		ctx->args = args;
+		fastrpc_get_buff_overlaps(ctx);
 	}
 
 	ctx->sc = sc;
@@ -380,6 +449,7 @@ static struct fastrpc_invoke_ctx *fastrpc_context_alloc(
 	list_del(&ctx->node);
 	spin_unlock(&user->lock);
 	kfree(ctx->maps);
+	kfree(ctx->olaps);
 	kfree(ctx);
 
 	return ERR_PTR(ret);
@@ -598,8 +668,11 @@ static u64 fastrpc_get_payload_size(struct fastrpc_invoke_ctx *ctx, int metalen)
 	size = ALIGN(metalen, FASTRPC_ALIGN);
 	for (i = 0; i < ctx->nscalars; i++) {
 		if (ctx->args[i].fd == 0 || ctx->args[i].fd == -1) {
-			size = ALIGN(size, FASTRPC_ALIGN);
-			size += ctx->args[i].length;
+
+			if (ctx->olaps[i].offset == 0)
+				size = ALIGN(size, FASTRPC_ALIGN);
+
+			size += (ctx->olaps[i].mend - ctx->olaps[i].mstart);
 		}
 	}
 
@@ -637,12 +710,11 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
 	struct fastrpc_remote_arg *rpra;
 	struct fastrpc_invoke_buf *list;
 	struct fastrpc_phy_page *pages;
-	int inbufs, i, err = 0;
-	u64 rlen, pkt_size;
+	int inbufs, i, oix, err = 0;
+	u64 len, rlen, pkt_size;
 	uintptr_t args;
 	int metalen;
 
-
 	inbufs = REMOTE_SCALARS_INBUFS(ctx->sc);
 	metalen = fastrpc_get_meta_size(ctx);
 	pkt_size = fastrpc_get_payload_size(ctx, metalen);
@@ -665,8 +737,11 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
 	rlen = pkt_size - metalen;
 	ctx->rpra = rpra;
 
-	for (i = 0; i < ctx->nbufs; ++i) {
-		u64 len = ctx->args[i].length;
+	for (oix = 0; oix < ctx->nbufs; ++oix) {
+		int mlen;
+
+		i = ctx->olaps[oix].raix;
+		len = ctx->args[i].length;
 
 		rpra[i].pv = 0;
 		rpra[i].len = len;
@@ -690,16 +765,25 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
 						 vma->vm_start;
 
 		} else {
-			rlen -= ALIGN(args, FASTRPC_ALIGN) - args;
-			args = ALIGN(args, FASTRPC_ALIGN);
-			if (rlen < len)
+
+			if (ctx->olaps[oix].offset == 0) {
+				rlen -= ALIGN(args, FASTRPC_ALIGN) - args;
+				args = ALIGN(args, FASTRPC_ALIGN);
+			}
+
+			mlen = ctx->olaps[oix].mend - ctx->olaps[oix].mstart;
+
+			if (rlen < mlen)
 				goto bail;
 
-			rpra[i].pv = args;
-			pages[i].addr = ctx->buf->phys + (pkt_size - rlen);
+			rpra[i].pv = args - ctx->olaps[oix].offset;
+			pages[i].addr = ctx->buf->phys -
+					ctx->olaps[oix].offset +
+					(pkt_size - rlen);
 			pages[i].addr = pages[i].addr &	PAGE_MASK;
-			args = args + len;
-			rlen -= len;
+
+			args = args + mlen;
+			rlen -= mlen;
 		}
 
 		if (i < inbufs && !ctx->maps[i]) {
-- 
2.21.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 7/8] misc: fastrpc: fix remote page size calculation
  2019-03-07 10:12 [PATCH 0/8] misc: fastrpc: few fixes Srinivas Kandagatla
                   ` (5 preceding siblings ...)
  2019-03-07 10:12 ` [PATCH 6/8] misc: fastrpc: take into account of overlapping buffers Srinivas Kandagatla
@ 2019-03-07 10:12 ` Srinivas Kandagatla
  2019-03-07 10:12 ` [PATCH 8/8] misc: fastrpc: increase max init file size to 64 MB Srinivas Kandagatla
  7 siblings, 0 replies; 9+ messages in thread
From: Srinivas Kandagatla @ 2019-03-07 10:12 UTC (permalink / raw)
  To: gregkh, arnd
  Cc: linux-kernel, bjorn.andersson, bkumar, linux-arm-msm, ktadakam,
	Srinivas Kandagatla

Remote page size should be calculated based on address and size, fix this!
Without this we will endup with one page less in cases where the buffer
is across 3 pages.

Fixes: c68cfb718c8f ("misc: fastrpc: Add support for context Invoke method")
Reported-by: Krishnaiah Tadakamalla <ktadakam@qti.qualcomm.com>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/misc/fastrpc.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 17bbb017bb08..d0e2e2620087 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -712,6 +712,7 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
 	struct fastrpc_phy_page *pages;
 	int inbufs, i, oix, err = 0;
 	u64 len, rlen, pkt_size;
+	u64 pg_start, pg_end;
 	uintptr_t args;
 	int metalen;
 
@@ -751,8 +752,6 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
 		if (!len)
 			continue;
 
-		pages[i].size = roundup(len, PAGE_SIZE);
-
 		if (ctx->maps[i]) {
 			struct vm_area_struct *vma = NULL;
 
@@ -764,6 +763,11 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
 				pages[i].addr += ctx->args[i].ptr -
 						 vma->vm_start;
 
+			pg_start = (ctx->args[i].ptr & PAGE_MASK) >> PAGE_SHIFT;
+			pg_end = ((ctx->args[i].ptr + len - 1) & PAGE_MASK) >>
+				  PAGE_SHIFT;
+			pages[i].size = (pg_end - pg_start + 1) * PAGE_SIZE;
+
 		} else {
 
 			if (ctx->olaps[oix].offset == 0) {
@@ -782,6 +786,9 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
 					(pkt_size - rlen);
 			pages[i].addr = pages[i].addr &	PAGE_MASK;
 
+			pg_start = (args & PAGE_MASK) >> PAGE_SHIFT;
+			pg_end = ((args + len - 1) & PAGE_MASK) >> PAGE_SHIFT;
+			pages[i].size = (pg_end - pg_start + 1) * PAGE_SIZE;
 			args = args + mlen;
 			rlen -= mlen;
 		}
-- 
2.21.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 8/8] misc: fastrpc: increase max init file size to 64 MB
  2019-03-07 10:12 [PATCH 0/8] misc: fastrpc: few fixes Srinivas Kandagatla
                   ` (6 preceding siblings ...)
  2019-03-07 10:12 ` [PATCH 7/8] misc: fastrpc: fix remote page size calculation Srinivas Kandagatla
@ 2019-03-07 10:12 ` Srinivas Kandagatla
  7 siblings, 0 replies; 9+ messages in thread
From: Srinivas Kandagatla @ 2019-03-07 10:12 UTC (permalink / raw)
  To: gregkh, arnd
  Cc: linux-kernel, bjorn.andersson, bkumar, linux-arm-msm, ktadakam,
	Srinivas Kandagatla

In some cases where Neural Processing is required the size of init process
exceeds default size of 2MB, increase this size to 64MB which is required
for QCS404 CDSP Neural Processing.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 drivers/misc/fastrpc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index d0e2e2620087..7e0d4528f3b9 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -32,7 +32,7 @@
 #define FASTRPC_CTX_MAX (256)
 #define FASTRPC_INIT_HANDLE	1
 #define FASTRPC_CTXID_MASK (0xFF0)
-#define INIT_FILELEN_MAX (2 * 1024 * 1024)
+#define INIT_FILELEN_MAX (64 * 1024 * 1024)
 #define INIT_MEMLEN_MAX  (8 * 1024 * 1024)
 #define FASTRPC_DEVICE_NAME	"fastrpc"
 
-- 
2.21.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2019-03-07 10:12 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-03-07 10:12 [PATCH 0/8] misc: fastrpc: few fixes Srinivas Kandagatla
2019-03-07 10:12 ` [PATCH 1/8] misc: fastrpc: Avoid free of DMA buffer in interrupt context Srinivas Kandagatla
2019-03-07 10:12 ` [PATCH 2/8] misc: fastrpc: Fix a possible double free Srinivas Kandagatla
2019-03-07 10:12 ` [PATCH 3/8] misc: fastrpc: make sure memory read and writes are visible Srinivas Kandagatla
2019-03-07 10:12 ` [PATCH 4/8] misc: fastrpc: use correct spinlock variant Srinivas Kandagatla
2019-03-07 10:12 ` [PATCH 5/8] misc: fastrpc: consider address offset before sending to DSP Srinivas Kandagatla
2019-03-07 10:12 ` [PATCH 6/8] misc: fastrpc: take into account of overlapping buffers Srinivas Kandagatla
2019-03-07 10:12 ` [PATCH 7/8] misc: fastrpc: fix remote page size calculation Srinivas Kandagatla
2019-03-07 10:12 ` [PATCH 8/8] misc: fastrpc: increase max init file size to 64 MB Srinivas Kandagatla

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.