public inbox for drm-ai-reviews@public-inbox.freedesktop.org
 help / color / mirror / Atom feed
* [PATCH v4 0/4] misc: fastrpc: Add missing bug fixes
@ 2026-04-09  6:26 Jianping Li
  2026-04-09  6:26 ` [PATCH v4 1/4] misc: fastrpc: Fix initial memory allocation for Audio PD memory pool Jianping Li
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Jianping Li @ 2026-04-09  6:26 UTC (permalink / raw)
  To: Srinivas Kandagatla, Amol Maheshwari
  Cc: Arnd Bergmann, Greg Kroah-Hartman, Abel Vesa, Jorge Ramirez-Ortiz,
	linux-arm-msm, dri-devel, linux-kernel, ekansh.gupta,
	quic_chennak, Jianping Li

Add missing bug fixes in memory areas. This patch series fixes multiple memory handling issues in the FastRPC
driver, primarily around the Audio PD remote heap.

The Audio PD uses a reserved memory-region that is shared between HLOS
and the DSP. Allocating and freeing this memory from userspace is unsafe,
as the kernel cannot reliably determine when the DSP has finished using
the buffers.

To address this, the entire reserved memory-region for the Audio PD is
now fully assigned to the DSP during remoteproc boot-up, and its lifetime
is tied to the rpmsg channel.

Patch [v3]: https://lore.kernel.org/all/20260407100508.1027-1-jianping.li@oss.qualcomm.com/

Change in v4:
  - Fail Audio PD static process creation when no reserved memory-region
    is present, instead of silently proceeding

Change in v3:
  - Adjusted the order of the series, placing NULL check changes that are not bug fixes at the end
  - Modified the commit message to describe the bug background in detail
  - Switch buf->list_lock back to fl->lock
  - Add locking to the operation of audio_init_mem

Changes in v2:
  - Remove the if check outside fastrpc_buf_free
  - Store the spinlock pointer in the struct fastrpc_buf instead
  - Allocate entire reserved memory to audio PD through remote heap

Ekansh Gupta (3):
  misc: fastrpc: Fix initial memory allocation for Audio PD memory pool
  misc: fastrpc: Remove buffer from list prior to unmap operation
  misc: fastrpc: Allow fastrpc_buf_free() to accept NULL

Jianping Li (1):
  misc: fastrpc: Allocate entire reserved memory for Audio PD in probe

 drivers/misc/fastrpc.c | 136 ++++++++++++++++++++++-------------------
 1 file changed, 74 insertions(+), 62 deletions(-)

-- 
2.43.0


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

* [PATCH v4 1/4] misc: fastrpc: Fix initial memory allocation for Audio PD memory pool
  2026-04-09  6:26 [PATCH v4 0/4] misc: fastrpc: Add missing bug fixes Jianping Li
@ 2026-04-09  6:26 ` Jianping Li
  2026-04-12  1:44   ` Claude review: " Claude Code Review Bot
  2026-04-09  6:26 ` [PATCH v4 2/4] misc: fastrpc: Remove buffer from list prior to unmap operation Jianping Li
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Jianping Li @ 2026-04-09  6:26 UTC (permalink / raw)
  To: Srinivas Kandagatla, Amol Maheshwari
  Cc: Arnd Bergmann, Greg Kroah-Hartman, Abel Vesa, Jorge Ramirez-Ortiz,
	linux-arm-msm, dri-devel, linux-kernel, ekansh.gupta,
	quic_chennak, stable, Jianping Li

From: Ekansh Gupta <ekansh.gupta@oss.qualcomm.com>

The initial buffer allocated for the Audio PD memory pool is never added
to the pool because pageslen is set to 0. As a result, the buffer is not
registered with Audio PD and is never used, causing a memory leak. Audio
PD immediately falls back to allocating memory from the remote heap since
the pool starts out empty.

Fix this by setting pageslen to 1 so that the initially allocated buffer
is correctly registered and becomes part of the Audio PD memory pool.

Fixes: 0871561055e66 ("misc: fastrpc: Add support for audiopd")
Cc: stable@kernel.org
Co-developed-by: Ekansh Gupta <ekansh.gupta@oss.qualcomm.com>
Signed-off-by: Ekansh Gupta <ekansh.gupta@oss.qualcomm.com>
Signed-off-by: Jianping Li <jianping.li@oss.qualcomm.com>
---
 drivers/misc/fastrpc.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 47356a5d5804..b87a5f97c96f 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -1324,7 +1324,9 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
 		err = PTR_ERR(name);
 		goto err;
 	}
-
+	inbuf.client_id = fl->client_id;
+	inbuf.namelen = init.namelen;
+	inbuf.pageslen = 0;
 	if (!fl->cctx->remote_heap) {
 		err = fastrpc_remote_heap_alloc(fl, fl->sctx->dev, init.memlen,
 						&fl->cctx->remote_heap);
@@ -1347,12 +1349,10 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
 				goto err_map;
 			}
 			scm_done = true;
+			inbuf.pageslen = 1;
 		}
 	}
 
-	inbuf.client_id = fl->client_id;
-	inbuf.namelen = init.namelen;
-	inbuf.pageslen = 0;
 	fl->pd = USER_PD;
 
 	args[0].ptr = (u64)(uintptr_t)&inbuf;
-- 
2.43.0


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

* [PATCH v4 2/4] misc: fastrpc: Remove buffer from list prior to unmap operation
  2026-04-09  6:26 [PATCH v4 0/4] misc: fastrpc: Add missing bug fixes Jianping Li
  2026-04-09  6:26 ` [PATCH v4 1/4] misc: fastrpc: Fix initial memory allocation for Audio PD memory pool Jianping Li
@ 2026-04-09  6:26 ` Jianping Li
  2026-04-12  1:44   ` Claude review: " Claude Code Review Bot
  2026-04-09  6:26 ` [PATCH v4 3/4] misc: fastrpc: Allocate entire reserved memory for Audio PD in probe Jianping Li
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Jianping Li @ 2026-04-09  6:26 UTC (permalink / raw)
  To: Srinivas Kandagatla, Amol Maheshwari
  Cc: Arnd Bergmann, Greg Kroah-Hartman, Abel Vesa, Jorge Ramirez-Ortiz,
	linux-arm-msm, dri-devel, linux-kernel, ekansh.gupta,
	quic_chennak, stable, Jianping Li

From: Ekansh Gupta <ekansh.gupta@oss.qualcomm.com>

fastrpc_req_munmap_impl() is called to unmap any buffer. The buffer is
getting removed from the list after it is unmapped from DSP. This can
create potential race conditions if any other thread removes the entry
from list while unmap operation is ongoing. Remove the entry before
calling unmap operation.

Fixes: 2419e55e532de ("misc: fastrpc: add mmap/unmap support")
Cc: stable@kernel.org
Co-developed-by: Ekansh Gupta <ekansh.gupta@oss.qualcomm.com>
Signed-off-by: Ekansh Gupta <ekansh.gupta@oss.qualcomm.com>
Signed-off-by: Jianping Li <jianping.li@oss.qualcomm.com>
---
 drivers/misc/fastrpc.c | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index b87a5f97c96f..148085c3b61a 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -1862,9 +1862,6 @@ static int fastrpc_req_munmap_impl(struct fastrpc_user *fl, struct fastrpc_buf *
 				      &args[0]);
 	if (!err) {
 		dev_dbg(dev, "unmmap\tpt 0x%09lx OK\n", buf->raddr);
-		spin_lock(&fl->lock);
-		list_del(&buf->node);
-		spin_unlock(&fl->lock);
 		fastrpc_buf_free(buf);
 	} else {
 		dev_err(dev, "unmmap\tpt 0x%09lx ERROR\n", buf->raddr);
@@ -1878,6 +1875,7 @@ static int fastrpc_req_munmap(struct fastrpc_user *fl, char __user *argp)
 	struct fastrpc_buf *buf = NULL, *iter, *b;
 	struct fastrpc_req_munmap req;
 	struct device *dev = fl->sctx->dev;
+	int err;
 
 	if (copy_from_user(&req, argp, sizeof(req)))
 		return -EFAULT;
@@ -1885,6 +1883,7 @@ static int fastrpc_req_munmap(struct fastrpc_user *fl, char __user *argp)
 	spin_lock(&fl->lock);
 	list_for_each_entry_safe(iter, b, &fl->mmaps, node) {
 		if ((iter->raddr == req.vaddrout) && (iter->size == req.size)) {
+			list_del(&iter->node);
 			buf = iter;
 			break;
 		}
@@ -1897,7 +1896,14 @@ static int fastrpc_req_munmap(struct fastrpc_user *fl, char __user *argp)
 		return -EINVAL;
 	}
 
-	return fastrpc_req_munmap_impl(fl, buf);
+	err = fastrpc_req_munmap_impl(fl, buf);
+	if (err) {
+		spin_lock(&fl->lock);
+		list_add_tail(&buf->node, &fl->mmaps);
+		spin_unlock(&fl->lock);
+	}
+
+	return err;
 }
 
 static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
@@ -1988,14 +1994,17 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
 
 	if (copy_to_user((void __user *)argp, &req, sizeof(req))) {
 		err = -EFAULT;
-		goto err_assign;
+		goto err_copy;
 	}
 
 	dev_dbg(dev, "mmap\t\tpt 0x%09lx OK [len 0x%08llx]\n",
 		buf->raddr, buf->size);
 
 	return 0;
-
+err_copy:
+	spin_lock(&fl->lock);
+	list_del(&buf->node);
+	spin_unlock(&fl->lock);
 err_assign:
 	fastrpc_req_munmap_impl(fl, buf);
 
-- 
2.43.0


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

* [PATCH v4 3/4] misc: fastrpc: Allocate entire reserved memory for Audio PD in probe
  2026-04-09  6:26 [PATCH v4 0/4] misc: fastrpc: Add missing bug fixes Jianping Li
  2026-04-09  6:26 ` [PATCH v4 1/4] misc: fastrpc: Fix initial memory allocation for Audio PD memory pool Jianping Li
  2026-04-09  6:26 ` [PATCH v4 2/4] misc: fastrpc: Remove buffer from list prior to unmap operation Jianping Li
@ 2026-04-09  6:26 ` Jianping Li
  2026-04-09  7:54   ` Ekansh Gupta
  2026-04-12  1:44   ` Claude review: " Claude Code Review Bot
  2026-04-09  6:26 ` [PATCH v4 4/4] misc: fastrpc: Allow fastrpc_buf_free() to accept NULL Jianping Li
  2026-04-12  1:44 ` Claude review: misc: fastrpc: Add missing bug fixes Claude Code Review Bot
  4 siblings, 2 replies; 11+ messages in thread
From: Jianping Li @ 2026-04-09  6:26 UTC (permalink / raw)
  To: Srinivas Kandagatla, Amol Maheshwari
  Cc: Arnd Bergmann, Greg Kroah-Hartman, Abel Vesa, Jorge Ramirez-Ortiz,
	linux-arm-msm, dri-devel, linux-kernel, ekansh.gupta,
	quic_chennak, Jianping Li

Allocating and freeing Audio PD memory from userspace is unsafe because
the kernel cannot reliably determine when the DSP has finished using the
memory. Userspace may free buffers while they are still in use by the DSP,
and remote free requests cannot be safely trusted.

Allocate the entire Audio PD reserved-memory region upfront during rpmsg
probe and tie its lifetime to the rpmsg channel. This avoids userspace-
controlled alloc/free and ensures memory is reclaimed only when the DSP
shuts down.

Signed-off-by: Jianping Li <jianping.li@oss.qualcomm.com>
---
 drivers/misc/fastrpc.c | 104 +++++++++++++++++++++--------------------
 1 file changed, 53 insertions(+), 51 deletions(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 148085c3b61a..a67ae991c0b0 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -276,6 +276,8 @@ struct fastrpc_channel_ctx {
 	struct kref refcount;
 	/* Flag if dsp attributes are cached */
 	bool valid_attributes;
+	/* Flag if audio PD init mem was allocated */
+	bool audio_init_mem;
 	u32 dsp_attributes[FASTRPC_MAX_DSP_ATTRIBUTES];
 	struct fastrpc_device *secure_fdevice;
 	struct fastrpc_device *fdevice;
@@ -1295,15 +1297,16 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
 	struct fastrpc_init_create_static init;
 	struct fastrpc_invoke_args *args;
 	struct fastrpc_phy_page pages[1];
+	struct fastrpc_channel_ctx *cctx = fl->cctx;
 	char *name;
 	int err;
-	bool scm_done = false;
 	struct {
 		int client_id;
 		u32 namelen;
 		u32 pageslen;
 	} inbuf;
 	u32 sc;
+	unsigned long flags;
 
 	args = kzalloc_objs(*args, FASTRPC_CREATE_STATIC_PROCESS_NARGS);
 	if (!args)
@@ -1327,31 +1330,6 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
 	inbuf.client_id = fl->client_id;
 	inbuf.namelen = init.namelen;
 	inbuf.pageslen = 0;
-	if (!fl->cctx->remote_heap) {
-		err = fastrpc_remote_heap_alloc(fl, fl->sctx->dev, init.memlen,
-						&fl->cctx->remote_heap);
-		if (err)
-			goto err_name;
-
-		/* Map if we have any heap VMIDs associated with this ADSP Static Process. */
-		if (fl->cctx->vmcount) {
-			u64 src_perms = BIT(QCOM_SCM_VMID_HLOS);
-
-			err = qcom_scm_assign_mem(fl->cctx->remote_heap->dma_addr,
-							(u64)fl->cctx->remote_heap->size,
-							&src_perms,
-							fl->cctx->vmperms, fl->cctx->vmcount);
-			if (err) {
-				dev_err(fl->sctx->dev,
-					"Failed to assign memory with dma_addr %pad size 0x%llx err %d\n",
-					&fl->cctx->remote_heap->dma_addr,
-					fl->cctx->remote_heap->size, err);
-				goto err_map;
-			}
-			scm_done = true;
-			inbuf.pageslen = 1;
-		}
-	}
 
 	fl->pd = USER_PD;
 
@@ -1363,8 +1341,25 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
 	args[1].length = inbuf.namelen;
 	args[1].fd = -1;
 
-	pages[0].addr = fl->cctx->remote_heap->dma_addr;
-	pages[0].size = fl->cctx->remote_heap->size;
+	spin_lock_irqsave(&cctx->lock, flags);
+	if (!fl->cctx->audio_init_mem) {
+		if (!fl->cctx->remote_heap ||
+		    !fl->cctx->remote_heap->dma_addr ||
+		    !fl->cctx->remote_heap->size) {
+			spin_unlock_irqrestore(&cctx->lock, flags);
+			err = -ENOMEM;
+			goto err;
+		}
+
+		pages[0].addr = fl->cctx->remote_heap->dma_addr;
+		pages[0].size = fl->cctx->remote_heap->size;
+		fl->cctx->audio_init_mem = true;
+		inbuf.pageslen = 1;
+	} else {
+		pages[0].addr = 0;
+		pages[0].size = 0;
+	}
+	spin_unlock_irqrestore(&cctx->lock, flags);
 
 	args[2].ptr = (u64)(uintptr_t) pages;
 	args[2].length = sizeof(*pages);
@@ -1382,26 +1377,7 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
 
 	return 0;
 err_invoke:
-	if (fl->cctx->vmcount && scm_done) {
-		u64 src_perms = 0;
-		struct qcom_scm_vmperm dst_perms;
-		u32 i;
-
-		for (i = 0; i < fl->cctx->vmcount; i++)
-			src_perms |= BIT(fl->cctx->vmperms[i].vmid);
-
-		dst_perms.vmid = QCOM_SCM_VMID_HLOS;
-		dst_perms.perm = QCOM_SCM_PERM_RWX;
-		err = qcom_scm_assign_mem(fl->cctx->remote_heap->dma_addr,
-						(u64)fl->cctx->remote_heap->size,
-						&src_perms, &dst_perms, 1);
-		if (err)
-			dev_err(fl->sctx->dev, "Failed to assign memory dma_addr %pad size 0x%llx err %d\n",
-				&fl->cctx->remote_heap->dma_addr, fl->cctx->remote_heap->size, err);
-	}
-err_map:
-	fastrpc_buf_free(fl->cctx->remote_heap);
-err_name:
+	fl->cctx->audio_init_mem = false;
 	kfree(name);
 err:
 	kfree(args);
@@ -2390,7 +2366,7 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
 		}
 	}
 
-	if (domain_id == SDSP_DOMAIN_ID) {
+	if (domain_id == SDSP_DOMAIN_ID || domain_id == ADSP_DOMAIN_ID) {
 		struct resource res;
 		u64 src_perms;
 
@@ -2402,6 +2378,15 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
 				    data->vmperms, data->vmcount);
 		}
 
+		if (domain_id == ADSP_DOMAIN_ID) {
+			data->remote_heap =
+				kzalloc_obj(*data->remote_heap, GFP_KERNEL);
+			if (!data->remote_heap)
+				return -ENOMEM;
+
+			data->remote_heap->dma_addr = res.start;
+			data->remote_heap->size = resource_size(&res);
+		}
 	}
 
 	secure_dsp = !(of_property_read_bool(rdev->of_node, "qcom,non-secure-domain"));
@@ -2482,6 +2467,7 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
 	struct fastrpc_buf *buf, *b;
 	struct fastrpc_user *user;
 	unsigned long flags;
+	int err;
 
 	/* No invocations past this point */
 	spin_lock_irqsave(&cctx->lock, flags);
@@ -2499,8 +2485,24 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
 	list_for_each_entry_safe(buf, b, &cctx->invoke_interrupted_mmaps, node)
 		list_del(&buf->node);
 
-	if (cctx->remote_heap)
-		fastrpc_buf_free(cctx->remote_heap);
+	if (cctx->remote_heap && cctx->vmcount) {
+		if (cctx->vmcount) {
+			u64 src_perms = 0;
+			struct qcom_scm_vmperm dst_perms;
+
+			for (u32 i = 0; i < cctx->vmcount; i++)
+				src_perms |= BIT(cctx->vmperms[i].vmid);
+
+			dst_perms.vmid = QCOM_SCM_VMID_HLOS;
+			dst_perms.perm = QCOM_SCM_PERM_RWX;
+
+			err = qcom_scm_assign_mem(cctx->remote_heap->dma_addr,
+						  cctx->remote_heap->size,
+						  &src_perms, &dst_perms, 1);
+			if (!err)
+				fastrpc_buf_free(cctx->remote_heap);
+		}
+	}
 
 	of_platform_depopulate(&rpdev->dev);
 
-- 
2.43.0


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

* [PATCH v4 4/4] misc: fastrpc: Allow fastrpc_buf_free() to accept NULL
  2026-04-09  6:26 [PATCH v4 0/4] misc: fastrpc: Add missing bug fixes Jianping Li
                   ` (2 preceding siblings ...)
  2026-04-09  6:26 ` [PATCH v4 3/4] misc: fastrpc: Allocate entire reserved memory for Audio PD in probe Jianping Li
@ 2026-04-09  6:26 ` Jianping Li
  2026-04-12  1:44   ` Claude review: " Claude Code Review Bot
  2026-04-12  1:44 ` Claude review: misc: fastrpc: Add missing bug fixes Claude Code Review Bot
  4 siblings, 1 reply; 11+ messages in thread
From: Jianping Li @ 2026-04-09  6:26 UTC (permalink / raw)
  To: Srinivas Kandagatla, Amol Maheshwari
  Cc: Arnd Bergmann, Greg Kroah-Hartman, Abel Vesa, Jorge Ramirez-Ortiz,
	linux-arm-msm, dri-devel, linux-kernel, ekansh.gupta,
	quic_chennak, Jianping Li

From: Ekansh Gupta <ekansh.gupta@oss.qualcomm.com>

Make fastrpc_buf_free() a no-op when passed a NULL pointer, allowing
callers to avoid open-coded NULL checks.

Co-developed-by: Ekansh Gupta <ekansh.gupta@oss.qualcomm.com>
Signed-off-by: Ekansh Gupta <ekansh.gupta@oss.qualcomm.com>
Signed-off-by: Jianping Li <jianping.li@oss.qualcomm.com>
---
 drivers/misc/fastrpc.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index a67ae991c0b0..3cce81d0cd8b 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -416,6 +416,9 @@ static int fastrpc_map_lookup(struct fastrpc_user *fl, int fd,
 
 static void fastrpc_buf_free(struct fastrpc_buf *buf)
 {
+	if (!buf)
+		return;
+
 	dma_free_coherent(buf->dev, buf->size, buf->virt,
 			  fastrpc_ipa_to_dma_addr(buf->fl->cctx, buf->dma_addr));
 	kfree(buf);
@@ -512,8 +515,7 @@ static void fastrpc_context_free(struct kref *ref)
 	for (i = 0; i < ctx->nbufs; i++)
 		fastrpc_map_put(ctx->maps[i]);
 
-	if (ctx->buf)
-		fastrpc_buf_free(ctx->buf);
+	fastrpc_buf_free(ctx->buf);
 
 	spin_lock_irqsave(&cctx->lock, flags);
 	idr_remove(&cctx->ctx_idr, ctx->ctxid >> 4);
@@ -1565,8 +1567,7 @@ static int fastrpc_device_release(struct inode *inode, struct file *file)
 	list_del(&fl->user);
 	spin_unlock_irqrestore(&cctx->lock, flags);
 
-	if (fl->init_mem)
-		fastrpc_buf_free(fl->init_mem);
+	fastrpc_buf_free(fl->init_mem);
 
 	list_for_each_entry_safe(ctx, n, &fl->pending, node) {
 		list_del(&ctx->node);
-- 
2.43.0


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

* Re: [PATCH v4 3/4] misc: fastrpc: Allocate entire reserved memory for Audio PD in probe
  2026-04-09  6:26 ` [PATCH v4 3/4] misc: fastrpc: Allocate entire reserved memory for Audio PD in probe Jianping Li
@ 2026-04-09  7:54   ` Ekansh Gupta
  2026-04-12  1:44   ` Claude review: " Claude Code Review Bot
  1 sibling, 0 replies; 11+ messages in thread
From: Ekansh Gupta @ 2026-04-09  7:54 UTC (permalink / raw)
  To: Jianping Li, Srinivas Kandagatla, Amol Maheshwari
  Cc: Arnd Bergmann, Greg Kroah-Hartman, Abel Vesa, Jorge Ramirez-Ortiz,
	linux-arm-msm, dri-devel, linux-kernel, quic_chennak

On 09-04-2026 11:56, Jianping Li wrote:
> Allocating and freeing Audio PD memory from userspace is unsafe because
> the kernel cannot reliably determine when the DSP has finished using the
> memory. Userspace may free buffers while they are still in use by the DSP,
> and remote free requests cannot be safely trusted.
> 
> Allocate the entire Audio PD reserved-memory region upfront during rpmsg
> probe and tie its lifetime to the rpmsg channel. This avoids userspace-
> controlled alloc/free and ensures memory is reclaimed only when the DSP
> shuts down.
> 
> Signed-off-by: Jianping Li <jianping.li@oss.qualcomm.com>
> ---
>  drivers/misc/fastrpc.c | 104 +++++++++++++++++++++--------------------
>  1 file changed, 53 insertions(+), 51 deletions(-)
> 
> diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
> index 148085c3b61a..a67ae991c0b0 100644
> --- a/drivers/misc/fastrpc.c
> +++ b/drivers/misc/fastrpc.c
> @@ -276,6 +276,8 @@ struct fastrpc_channel_ctx {
>  	struct kref refcount;
>  	/* Flag if dsp attributes are cached */
>  	bool valid_attributes;
> +	/* Flag if audio PD init mem was allocated */
> +	bool audio_init_mem;
>  	u32 dsp_attributes[FASTRPC_MAX_DSP_ATTRIBUTES];
>  	struct fastrpc_device *secure_fdevice;
>  	struct fastrpc_device *fdevice;
> @@ -1295,15 +1297,16 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
>  	struct fastrpc_init_create_static init;
>  	struct fastrpc_invoke_args *args;
>  	struct fastrpc_phy_page pages[1];
> +	struct fastrpc_channel_ctx *cctx = fl->cctx;
>  	char *name;
>  	int err;
> -	bool scm_done = false;
>  	struct {
>  		int client_id;
>  		u32 namelen;
>  		u32 pageslen;
>  	} inbuf;
>  	u32 sc;
> +	unsigned long flags;
>  
>  	args = kzalloc_objs(*args, FASTRPC_CREATE_STATIC_PROCESS_NARGS);
>  	if (!args)
> @@ -1327,31 +1330,6 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
>  	inbuf.client_id = fl->client_id;
>  	inbuf.namelen = init.namelen;
>  	inbuf.pageslen = 0;
> -	if (!fl->cctx->remote_heap) {
> -		err = fastrpc_remote_heap_alloc(fl, fl->sctx->dev, init.memlen,
> -						&fl->cctx->remote_heap);
> -		if (err)
> -			goto err_name;
> -
> -		/* Map if we have any heap VMIDs associated with this ADSP Static Process. */
> -		if (fl->cctx->vmcount) {
> -			u64 src_perms = BIT(QCOM_SCM_VMID_HLOS);
> -
> -			err = qcom_scm_assign_mem(fl->cctx->remote_heap->dma_addr,
> -							(u64)fl->cctx->remote_heap->size,
> -							&src_perms,
> -							fl->cctx->vmperms, fl->cctx->vmcount);
> -			if (err) {
> -				dev_err(fl->sctx->dev,
> -					"Failed to assign memory with dma_addr %pad size 0x%llx err %d\n",
> -					&fl->cctx->remote_heap->dma_addr,
> -					fl->cctx->remote_heap->size, err);
> -				goto err_map;
> -			}
> -			scm_done = true;
> -			inbuf.pageslen = 1;
> -		}
> -	}
>  
>  	fl->pd = USER_PD;
>  
> @@ -1363,8 +1341,25 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
>  	args[1].length = inbuf.namelen;
>  	args[1].fd = -1;
>  
> -	pages[0].addr = fl->cctx->remote_heap->dma_addr;
> -	pages[0].size = fl->cctx->remote_heap->size;
> +	spin_lock_irqsave(&cctx->lock, flags);
> +	if (!fl->cctx->audio_init_mem) {
> +		if (!fl->cctx->remote_heap ||
> +		    !fl->cctx->remote_heap->dma_addr ||
> +		    !fl->cctx->remote_heap->size) {
> +			spin_unlock_irqrestore(&cctx->lock, flags);
> +			err = -ENOMEM;
> +			goto err;
> +		}
> +
> +		pages[0].addr = fl->cctx->remote_heap->dma_addr;
> +		pages[0].size = fl->cctx->remote_heap->size;
> +		fl->cctx->audio_init_mem = true;
> +		inbuf.pageslen = 1;
> +	} else {
> +		pages[0].addr = 0;
> +		pages[0].size = 0;
> +	}
> +	spin_unlock_irqrestore(&cctx->lock, flags);
>  
>  	args[2].ptr = (u64)(uintptr_t) pages;
>  	args[2].length = sizeof(*pages);
> @@ -1382,26 +1377,7 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl,
>  
>  	return 0;
>  err_invoke:
> -	if (fl->cctx->vmcount && scm_done) {
> -		u64 src_perms = 0;
> -		struct qcom_scm_vmperm dst_perms;
> -		u32 i;
> -
> -		for (i = 0; i < fl->cctx->vmcount; i++)
> -			src_perms |= BIT(fl->cctx->vmperms[i].vmid);
> -
> -		dst_perms.vmid = QCOM_SCM_VMID_HLOS;
> -		dst_perms.perm = QCOM_SCM_PERM_RWX;
> -		err = qcom_scm_assign_mem(fl->cctx->remote_heap->dma_addr,
> -						(u64)fl->cctx->remote_heap->size,
> -						&src_perms, &dst_perms, 1);
> -		if (err)
> -			dev_err(fl->sctx->dev, "Failed to assign memory dma_addr %pad size 0x%llx err %d\n",
> -				&fl->cctx->remote_heap->dma_addr, fl->cctx->remote_heap->size, err);
> -	}
> -err_map:
> -	fastrpc_buf_free(fl->cctx->remote_heap);
> -err_name:
> +	fl->cctx->audio_init_mem = false;
>  	kfree(name);
>  err:
>  	kfree(args);
> @@ -2390,7 +2366,7 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
>  		}
>  	}
>  
> -	if (domain_id == SDSP_DOMAIN_ID) {
> +	if (domain_id == SDSP_DOMAIN_ID || domain_id == ADSP_DOMAIN_ID) {
>  		struct resource res;
>  		u64 src_perms;
>  
> @@ -2402,6 +2378,15 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev)
>  				    data->vmperms, data->vmcount);
>  		}
>  
> +		if (domain_id == ADSP_DOMAIN_ID) {
> +			data->remote_heap =
> +				kzalloc_obj(*data->remote_heap, GFP_KERNEL);
> +			if (!data->remote_heap)
> +				return -ENOMEM;
> +
> +			data->remote_heap->dma_addr = res.start;
> +			data->remote_heap->size = resource_size(&res);
> +		}
>  	}
>  
>  	secure_dsp = !(of_property_read_bool(rdev->of_node, "qcom,non-secure-domain"));
> @@ -2482,6 +2467,7 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
>  	struct fastrpc_buf *buf, *b;
>  	struct fastrpc_user *user;
>  	unsigned long flags;
> +	int err;
>  
>  	/* No invocations past this point */
>  	spin_lock_irqsave(&cctx->lock, flags);
> @@ -2499,8 +2485,24 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
>  	list_for_each_entry_safe(buf, b, &cctx->invoke_interrupted_mmaps, node)
>  		list_del(&buf->node);
>  
> -	if (cctx->remote_heap)
> -		fastrpc_buf_free(cctx->remote_heap);
> +	if (cctx->remote_heap && cctx->vmcount) {
> +		if (cctx->vmcount) {
this if check is not needed
> +			u64 src_perms = 0;
> +			struct qcom_scm_vmperm dst_perms;
> +
> +			for (u32 i = 0; i < cctx->vmcount; i++)
> +				src_perms |= BIT(cctx->vmperms[i].vmid);
> +
> +			dst_perms.vmid = QCOM_SCM_VMID_HLOS;
> +			dst_perms.perm = QCOM_SCM_PERM_RWX;
> +
> +			err = qcom_scm_assign_mem(cctx->remote_heap->dma_addr,
> +						  cctx->remote_heap->size,
> +						  &src_perms, &dst_perms, 1);
> +			if (!err)
> +				fastrpc_buf_free(cctx->remote_heap);
> +		}
> +	}
>  
>  	of_platform_depopulate(&rpdev->dev);
>  


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

* Claude review: misc: fastrpc: Add missing bug fixes
  2026-04-09  6:26 [PATCH v4 0/4] misc: fastrpc: Add missing bug fixes Jianping Li
                   ` (3 preceding siblings ...)
  2026-04-09  6:26 ` [PATCH v4 4/4] misc: fastrpc: Allow fastrpc_buf_free() to accept NULL Jianping Li
@ 2026-04-12  1:44 ` Claude Code Review Bot
  4 siblings, 0 replies; 11+ messages in thread
From: Claude Code Review Bot @ 2026-04-12  1:44 UTC (permalink / raw)
  To: dri-devel-reviews

Overall Series Review

Subject: misc: fastrpc: Add missing bug fixes
Author: Jianping Li <jianping.li@oss.qualcomm.com>
Patches: 6
Reviewed: 2026-04-12T11:44:33.724906

---

This v4 series addresses memory handling issues in the FastRPC driver's Audio PD remote heap. Patch 1 is a clear, correct bugfix. Patch 2 is a reasonable race-condition fix. Patch 4 is a clean, standard cleanup. However, **Patch 3 has critical bugs** that will cause kernel crashes at module removal time: the `remote_heap` allocated via `kzalloc` in probe has `NULL` `dev` and `fl` fields, so calling `fastrpc_buf_free()` on it dereferences NULL pointers. There are also resource leak issues and use of potentially uninitialized data. The series should not be merged until Patch 3 is reworked.

---

---
Generated by Claude Code Patch Reviewer

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

* Claude review: misc: fastrpc: Fix initial memory allocation for Audio PD memory pool
  2026-04-09  6:26 ` [PATCH v4 1/4] misc: fastrpc: Fix initial memory allocation for Audio PD memory pool Jianping Li
@ 2026-04-12  1:44   ` Claude Code Review Bot
  0 siblings, 0 replies; 11+ messages in thread
From: Claude Code Review Bot @ 2026-04-12  1:44 UTC (permalink / raw)
  To: dri-devel-reviews

Patch Review

**Verdict: Looks correct.**

The bug analysis is sound. In the original code, `inbuf.pageslen` is unconditionally set to 0 *after* the remote_heap allocation block:

```c
// Original code (after the allocation/SCM block):
inbuf.client_id = fl->client_id;
inbuf.namelen = init.namelen;
inbuf.pageslen = 0;  // always 0, even if heap was just allocated
```

This means the buffer page info is never passed to the DSP, so the memory pool starts empty and the initial allocation is leaked.

The fix moves the `inbuf` initialization before the allocation block and conditionally sets `pageslen = 1` when SCM assignment succeeds:

```c
inbuf.pageslen = 0;
if (!fl->cctx->remote_heap) {
    // allocate + SCM...
    scm_done = true;
    inbuf.pageslen = 1;  // <-- now set when memory is actually registered
}
```

This correctly distinguishes first-time allocation (pageslen=1, send page info) from subsequent calls where the heap already exists (pageslen=0). Note that Patch 3 later removes and replaces this code entirely, but each patch in the series is independently correct.

**Minor nit:** The blank line after `goto err;` followed by `}` and the removed blank line before `if (!fl->cctx->remote_heap)` changes the spacing slightly. No functional issue.

---

---
Generated by Claude Code Patch Reviewer

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

* Claude review: misc: fastrpc: Remove buffer from list prior to unmap operation
  2026-04-09  6:26 ` [PATCH v4 2/4] misc: fastrpc: Remove buffer from list prior to unmap operation Jianping Li
@ 2026-04-12  1:44   ` Claude Code Review Bot
  0 siblings, 0 replies; 11+ messages in thread
From: Claude Code Review Bot @ 2026-04-12  1:44 UTC (permalink / raw)
  To: dri-devel-reviews

Patch Review

**Verdict: Reasonable fix with one concern.**

The change moves the `list_del` out of `fastrpc_req_munmap_impl()` and into the caller `fastrpc_req_munmap()`, done under the spinlock before the DSP unmap RPC:

```c
spin_lock(&fl->lock);
list_for_each_entry_safe(iter, b, &fl->mmaps, node) {
    if ((iter->raddr == req.vaddrout) && (iter->size == req.size)) {
        list_del(&iter->node);   // remove before unlocking
        buf = iter;
        break;
    }
}
spin_unlock(&fl->lock);
```

If the DSP unmap fails, the buffer is re-added:

```c
err = fastrpc_req_munmap_impl(fl, buf);
if (err) {
    spin_lock(&fl->lock);
    list_add_tail(&buf->node, &fl->mmaps);
    spin_unlock(&fl->lock);
}
```

This prevents a race where two threads could both find and try to unmap the same buffer. The remove-first, re-add-on-failure pattern is reasonable.

The `fastrpc_req_mmap` error path change is also correct: when `copy_to_user` fails, the buffer (already added to the list) must be removed before calling `fastrpc_req_munmap_impl` (which no longer does `list_del`):

```c
err_copy:
    spin_lock(&fl->lock);
    list_del(&buf->node);
    spin_unlock(&fl->lock);
err_assign:
    fastrpc_req_munmap_impl(fl, buf);
```

**Concern:** After removing the `list_del` from `fastrpc_req_munmap_impl`, ensure all callers handle list removal. There are at least two callers: `fastrpc_req_munmap` (handled) and the `err_assign` path in `fastrpc_req_mmap` (handled via new `err_copy`). The `fastrpc_device_release` path iterates the list and calls `fastrpc_buf_free` directly (not through `_impl`), so it's not affected. This looks complete.

---

---
Generated by Claude Code Patch Reviewer

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

* Claude review: misc: fastrpc: Allocate entire reserved memory for Audio PD in probe
  2026-04-09  6:26 ` [PATCH v4 3/4] misc: fastrpc: Allocate entire reserved memory for Audio PD in probe Jianping Li
  2026-04-09  7:54   ` Ekansh Gupta
@ 2026-04-12  1:44   ` Claude Code Review Bot
  1 sibling, 0 replies; 11+ messages in thread
From: Claude Code Review Bot @ 2026-04-12  1:44 UTC (permalink / raw)
  To: dri-devel-reviews

Patch Review

**Verdict: Has critical bugs. Needs rework.**

The design intent is sound: allocate the Audio PD reserved memory once in `fastrpc_rpmsg_probe()` and tie its lifetime to the rpmsg channel, rather than allowing unsafe userspace-controlled alloc/free. However, the implementation has several issues:

**Bug 1 (Critical): `fastrpc_buf_free()` will crash on the probe-allocated `remote_heap`.**

In `fastrpc_rpmsg_probe`, the buffer is allocated with bare `kzalloc`:

```c
data->remote_heap =
    kzalloc_obj(*data->remote_heap, GFP_KERNEL);
// ...
data->remote_heap->dma_addr = res.start;
data->remote_heap->size = resource_size(&res);
```

This leaves `buf->fl` and `buf->dev` as `NULL`. But `fastrpc_buf_free()` dereferences both:

```c
static void fastrpc_buf_free(struct fastrpc_buf *buf)
{
    dma_free_coherent(buf->dev, buf->size, buf->virt,           // buf->dev is NULL
                      fastrpc_ipa_to_dma_addr(buf->fl->cctx,    // buf->fl is NULL → crash
                                              buf->dma_addr));
    kfree(buf);
}
```

In `fastrpc_rpmsg_remove`, `fastrpc_buf_free(cctx->remote_heap)` is called, which will NULL-dereference `buf->fl->cctx`. Additionally, `dma_free_coherent(NULL, ...)` would also crash. This buffer is a tracking struct for reserved DT memory, not a DMA-coherent allocation — it should be freed with `kfree()`, not `fastrpc_buf_free()`.

**Bug 2: Uninitialized `res` used for ADSP when reserved memory is absent.**

The code structure is:

```c
if (domain_id == SDSP_DOMAIN_ID || domain_id == ADSP_DOMAIN_ID) {
    struct resource res;
    err = of_reserved_mem_region_to_resource(rdev->of_node, 0, &res);
    if (!err) {
        // SCM assign using res...
    }
    if (domain_id == ADSP_DOMAIN_ID) {
        // ...
        data->remote_heap->dma_addr = res.start;       // used unconditionally
        data->remote_heap->size = resource_size(&res);  // used unconditionally
    }
}
```

If `of_reserved_mem_region_to_resource()` fails (no reserved memory in DT), `res` is uninitialized stack data. The ADSP block still runs and stores garbage into `dma_addr` and `size`. The check in `fastrpc_init_create_static_process` (`!fl->cctx->remote_heap->dma_addr || !fl->cctx->remote_heap->size`) only catches zero values, not arbitrary garbage. The ADSP `kzalloc` block must be inside the `if (!err)` guard, or separately check `err`.

**Bug 3: `return -ENOMEM` leaks `data`.**

```c
if (!data->remote_heap)
    return -ENOMEM;
```

At this point in probe, `data` has been allocated via `kzalloc_obj`. A bare `return` skips `err_free_data` cleanup. Should be:

```c
if (!data->remote_heap) {
    err = -ENOMEM;
    goto err_free_data;
}
```

**Bug 4: Redundant condition and leak in remove.**

```c
if (cctx->remote_heap && cctx->vmcount) {
    if (cctx->vmcount) {           // always true — redundant
```

Also, if `qcom_scm_assign_mem` fails, `cctx->remote_heap` is never freed (neither the struct nor the reserved memory is reclaimed). And if `cctx->remote_heap` is set but `!cctx->vmcount`, the struct leaks entirely.

**Issue 5: `audio_init_mem = false` on error without locking.**

```c
err_invoke:
    fl->cctx->audio_init_mem = false;
```

This write is outside the `cctx->lock` spinlock, while the read in the success path is inside `spin_lock_irqsave(&cctx->lock, ...)`. This is a data race, although the practical impact may be low if concurrent static process creation is unlikely.

**Suggestion for rework:** Consider not using `struct fastrpc_buf` at all for the probe-allocated reserved memory tracking. A simpler approach would be to store `dma_addr` and `size` directly in `fastrpc_channel_ctx`, or use a dedicated struct that doesn't carry `fl`/`dev`/`virt` baggage. If `fastrpc_buf` must be used, the cleanup in `fastrpc_rpmsg_remove` should use `kfree()` instead of `fastrpc_buf_free()`.

---

---
Generated by Claude Code Patch Reviewer

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

* Claude review: misc: fastrpc: Allow fastrpc_buf_free() to accept NULL
  2026-04-09  6:26 ` [PATCH v4 4/4] misc: fastrpc: Allow fastrpc_buf_free() to accept NULL Jianping Li
@ 2026-04-12  1:44   ` Claude Code Review Bot
  0 siblings, 0 replies; 11+ messages in thread
From: Claude Code Review Bot @ 2026-04-12  1:44 UTC (permalink / raw)
  To: dri-devel-reviews

Patch Review

**Verdict: Clean, correct.**

This follows the standard kernel pattern (like `kfree`, `vfree`, etc.) of making free functions accept NULL:

```c
static void fastrpc_buf_free(struct fastrpc_buf *buf)
{
    if (!buf)
        return;
    // ...
}
```

The two callsite simplifications (`fastrpc_context_free` and `fastrpc_device_release`) are straightforward and correct. No functional change.

Note that this patch does **not** help with Patch 3's bugs — the issue there is calling `fastrpc_buf_free` on a non-NULL but improperly initialized `fastrpc_buf`, not passing NULL.

---
Generated by Claude Code Patch Reviewer

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

end of thread, other threads:[~2026-04-12  1:44 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-09  6:26 [PATCH v4 0/4] misc: fastrpc: Add missing bug fixes Jianping Li
2026-04-09  6:26 ` [PATCH v4 1/4] misc: fastrpc: Fix initial memory allocation for Audio PD memory pool Jianping Li
2026-04-12  1:44   ` Claude review: " Claude Code Review Bot
2026-04-09  6:26 ` [PATCH v4 2/4] misc: fastrpc: Remove buffer from list prior to unmap operation Jianping Li
2026-04-12  1:44   ` Claude review: " Claude Code Review Bot
2026-04-09  6:26 ` [PATCH v4 3/4] misc: fastrpc: Allocate entire reserved memory for Audio PD in probe Jianping Li
2026-04-09  7:54   ` Ekansh Gupta
2026-04-12  1:44   ` Claude review: " Claude Code Review Bot
2026-04-09  6:26 ` [PATCH v4 4/4] misc: fastrpc: Allow fastrpc_buf_free() to accept NULL Jianping Li
2026-04-12  1:44   ` Claude review: " Claude Code Review Bot
2026-04-12  1:44 ` Claude review: misc: fastrpc: Add missing bug fixes Claude Code Review Bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox