summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLing Xu <quic_lxu5@quicinc.com>2025-09-12 14:12:36 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2025-10-15 12:00:23 +0200
commit802359a52676176b18713e33caa17572ad009057 (patch)
tree01af073ccb192a8ab34c35f41ebdc791b67c72cb
parent78d33a041555db03903e8037fd053ed74fbd88cb (diff)
downloadlinux-802359a52676176b18713e33caa17572ad009057.tar.gz
linux-802359a52676176b18713e33caa17572ad009057.tar.bz2
linux-802359a52676176b18713e33caa17572ad009057.zip
misc: fastrpc: Skip reference for DMA handles
commit 10df039834f84a297c72ec962c0f9b7c8c5ca31a upstream. If multiple dma handles are passed with same fd over a remote call the kernel driver takes a reference and expects that put for the map will be called as many times to free the map. But DSP only updates the fd one time in the fd list when the DSP refcount goes to zero and hence kernel make put call only once for the fd. This can cause SMMU fault issue as the same fd can be used in future for some other call. Fixes: 35a82b87135d ("misc: fastrpc: Add dma handle implementation") 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: Ling Xu <quic_lxu5@quicinc.com> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> Signed-off-by: Srinivas Kandagatla <srini@kernel.org> Link: https://lore.kernel.org/r/20250912131236.303102-5-srini@kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/misc/fastrpc.c45
1 files changed, 27 insertions, 18 deletions
diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 886eb292663c..9d8e51351ff8 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -363,9 +363,8 @@ static int fastrpc_map_get(struct fastrpc_map *map)
static int fastrpc_map_lookup(struct fastrpc_user *fl, int fd,
- struct fastrpc_map **ppmap, bool take_ref)
+ struct fastrpc_map **ppmap)
{
- struct fastrpc_session_ctx *sess = fl->sctx;
struct fastrpc_map *map = NULL;
struct dma_buf *buf;
int ret = -ENOENT;
@@ -379,15 +378,6 @@ static int fastrpc_map_lookup(struct fastrpc_user *fl, int fd,
if (map->fd != fd || map->buf != buf)
continue;
- if (take_ref) {
- ret = fastrpc_map_get(map);
- if (ret) {
- dev_dbg(sess->dev, "%s: Failed to get map fd=%d ret=%d\n",
- __func__, fd, ret);
- break;
- }
- }
-
*ppmap = map;
ret = 0;
break;
@@ -757,7 +747,7 @@ static const struct dma_buf_ops fastrpc_dma_buf_ops = {
.release = fastrpc_release,
};
-static int fastrpc_map_create(struct fastrpc_user *fl, int fd,
+static int fastrpc_map_attach(struct fastrpc_user *fl, int fd,
u64 len, u32 attr, struct fastrpc_map **ppmap)
{
struct fastrpc_session_ctx *sess = fl->sctx;
@@ -766,9 +756,6 @@ static int fastrpc_map_create(struct fastrpc_user *fl, int fd,
struct scatterlist *sgl = NULL;
int err = 0, sgl_index = 0;
- if (!fastrpc_map_lookup(fl, fd, ppmap, true))
- return 0;
-
map = kzalloc(sizeof(*map), GFP_KERNEL);
if (!map)
return -ENOMEM;
@@ -853,6 +840,24 @@ get_err:
return err;
}
+static int fastrpc_map_create(struct fastrpc_user *fl, int fd,
+ u64 len, u32 attr, struct fastrpc_map **ppmap)
+{
+ struct fastrpc_session_ctx *sess = fl->sctx;
+ int err = 0;
+
+ if (!fastrpc_map_lookup(fl, fd, ppmap)) {
+ if (!fastrpc_map_get(*ppmap))
+ return 0;
+ dev_dbg(sess->dev, "%s: Failed to get map fd=%d\n",
+ __func__, fd);
+ }
+
+ err = fastrpc_map_attach(fl, fd, len, attr, ppmap);
+
+ return err;
+}
+
/*
* Fastrpc payload buffer with metadata looks like:
*
@@ -925,8 +930,12 @@ static int fastrpc_create_maps(struct fastrpc_invoke_ctx *ctx)
ctx->args[i].length == 0)
continue;
- err = fastrpc_map_create(ctx->fl, ctx->args[i].fd,
- ctx->args[i].length, ctx->args[i].attr, &ctx->maps[i]);
+ if (i < ctx->nbufs)
+ err = fastrpc_map_create(ctx->fl, ctx->args[i].fd,
+ ctx->args[i].length, ctx->args[i].attr, &ctx->maps[i]);
+ else
+ err = fastrpc_map_attach(ctx->fl, ctx->args[i].fd,
+ ctx->args[i].length, ctx->args[i].attr, &ctx->maps[i]);
if (err) {
dev_err(dev, "Error Creating map %d\n", err);
return -EINVAL;
@@ -1116,7 +1125,7 @@ cleanup_fdlist:
for (i = 0; i < FASTRPC_MAX_FDLIST; i++) {
if (!fdlist[i])
break;
- if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap, false))
+ if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap))
fastrpc_map_put(mmap);
}