[PATCH 6/6] misc: fastrpc: Add UAPI flags for extended IOVA mapping

From: Vinayak Katoch

Date: Wed Aug 26 2026 - 09:48:23 EST


Userspace has no way to request that a buffer be mapped through the
extended context bank, so large buffers cannot be placed in the wider
IOVA window even when one is available.

Add two UAPI flags:

FASTRPC_MAP_FD_EXTENDED - map immediately via the extended CB
FASTRPC_MAP_FD_DELAYED_EXTENDED - map on demand via the extended CB

When either flag is set, fastrpc_map_attach() iterates cctx->ext_cb[]
and retries on -ENOMEM, falling over to the next extended CB when one
exhausts its IOVA space. The SID offset passed to the DSP must reflect
the actual CB used, so fastrpc_compute_dma_addr() takes an explicit
session rather than always using fl->sctx — without this the DSP would
fault on access. All existing call sites pass flags=0 and are unaffected.

Signed-off-by: Vinayak Katoch <vinayak.katoch@xxxxxxxxxxxxxxxx>
---
drivers/misc/fastrpc.c | 64 +++++++++++++++++++++++++++++++++------------
include/uapi/misc/fastrpc.h | 7 +++++
2 files changed, 55 insertions(+), 16 deletions(-)

diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 28d89fd9cbbc..2f248667e734 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -83,6 +83,11 @@
#define FASTRPC_MAX_DSP_ATTRIBUTES (256)
#define FASTRPC_MAX_DSP_ATTRIBUTES_LEN (sizeof(u32) * FASTRPC_MAX_DSP_ATTRIBUTES)

+/* Check if the given flag is used for extended UDMA mapping */
+#define IS_EXTENDED_MAP_FLAG(flag) \
+ ((flag) == FASTRPC_MAP_FD_EXTENDED || \
+ (flag) == FASTRPC_MAP_FD_DELAYED_EXTENDED)
+
/* Retrives number of input buffers from the scalars parameter */
#define REMOTE_SCALARS_INBUFS(sc) (((sc) >> 16) & 0x0ff)

@@ -880,16 +885,19 @@ static const struct dma_buf_ops fastrpc_dma_buf_ops = {
.release = fastrpc_release,
};

-static dma_addr_t fastrpc_compute_dma_addr(struct fastrpc_user *fl, dma_addr_t sg_dma_addr)
+static dma_addr_t fastrpc_compute_dma_addr(struct fastrpc_user *fl, dma_addr_t sg_dma_addr,
+ struct fastrpc_session_ctx *sess)
{
- return sg_dma_addr + fastrpc_sid_offset(fl->cctx, fl->sctx);
+ return sg_dma_addr + fastrpc_sid_offset(fl->cctx, sess);
}

-static int fastrpc_map_attach(struct fastrpc_user *fl, int fd,
- u64 len, u32 attr, struct fastrpc_map **ppmap)
+static int fastrpc_map_attach_to_dev(struct fastrpc_user *fl, int fd,
+ u64 len, u32 attr,
+ struct fastrpc_session_ctx *sess,
+ struct fastrpc_map **ppmap)
{
- struct fastrpc_session_ctx *sess = fl->sctx;
struct fastrpc_map *map = NULL;
+ struct device *dev = sess->dev;
struct sg_table *table;
struct scatterlist *sgl = NULL;
int err = 0, sgl_index = 0;
@@ -909,9 +917,9 @@ static int fastrpc_map_attach(struct fastrpc_user *fl, int fd,
goto get_err;
}

- map->attach = dma_buf_attach(map->buf, sess->dev);
+ map->attach = dma_buf_attach(map->buf, dev);
if (IS_ERR(map->attach)) {
- dev_err(sess->dev, "Failed to attach dmabuf\n");
+ dev_err(dev, "Failed to attach dmabuf\n");
err = PTR_ERR(map->attach);
goto attach_err;
}
@@ -926,12 +934,13 @@ static int fastrpc_map_attach(struct fastrpc_user *fl, int fd,
if (attr & FASTRPC_ATTR_SECUREMAP)
map->dma_addr = sg_phys(map->table->sgl);
else
- map->dma_addr = fastrpc_compute_dma_addr(fl, sg_dma_address(map->table->sgl));
+ map->dma_addr = fastrpc_compute_dma_addr(fl, sg_dma_address(map->table->sgl), sess);
for_each_sg(map->table->sgl, sgl, map->table->nents,
sgl_index)
map->size += sg_dma_len(sgl);
+
if (len > map->size) {
- dev_dbg(sess->dev, "Bad size passed len 0x%llx map size 0x%llx\n",
+ dev_dbg(dev, "Bad size passed len 0x%llx map size 0x%llx\n",
len, map->size);
err = -EINVAL;
goto map_err;
@@ -954,7 +963,7 @@ static int fastrpc_map_attach(struct fastrpc_user *fl, int fd,
map->attr = attr;
err = qcom_scm_assign_mem(map->dma_addr, (u64)map->len, &src_perms, dst_perms, 2);
if (err) {
- dev_err(sess->dev,
+ dev_err(dev,
"Failed to assign memory with dma_addr %pad size 0x%llx err %d\n",
&map->dma_addr, map->len, err);
goto map_err;
@@ -977,13 +986,36 @@ static int fastrpc_map_attach(struct fastrpc_user *fl, int fd,
return err;
}

+static int fastrpc_map_attach(struct fastrpc_user *fl, int fd,
+ u64 len, u32 attr, u32 flags, struct fastrpc_map **ppmap)
+{
+ if (IS_EXTENDED_MAP_FLAG(flags)) {
+ int i, err = -ENODEV;
+
+ if (!fl->cctx->ext_cb_count) {
+ dev_err(fl->sctx->dev, "no extended context bank found\n");
+ return -ENODEV;
+ }
+
+ for (i = 0; i < fl->cctx->ext_cb_count; i++) {
+ err = fastrpc_map_attach_to_dev(fl, fd, len, attr,
+ fl->cctx->ext_cb[i], ppmap);
+ if (err != -ENOMEM)
+ break;
+ }
+ return err;
+ }
+
+ return fastrpc_map_attach_to_dev(fl, fd, len, attr, fl->sctx, ppmap);
+}
+
static int fastrpc_map_create(struct fastrpc_user *fl, int fd,
- u64 len, u32 attr, struct fastrpc_map **ppmap)
+ u64 len, u32 attr, u32 flags, struct fastrpc_map **ppmap)
{
if (!fastrpc_map_lookup(fl, fd, ppmap, true))
return 0;

- return fastrpc_map_attach(fl, fd, len, attr, ppmap);
+ return fastrpc_map_attach(fl, fd, len, attr, flags, ppmap);
}

/*
@@ -1061,10 +1093,10 @@ static int fastrpc_create_maps(struct fastrpc_invoke_ctx *ctx)

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]);
+ ctx->args[i].length, ctx->args[i].attr, 0, &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]);
+ ctx->args[i].length, ctx->args[i].attr, 0, &ctx->maps[i]);
if (err) {
dev_err(dev, "Error Creating map %d\n", err);
return -EINVAL;
@@ -1628,7 +1660,7 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl,
fl->pd = USER_PD;

if (init.filelen && init.filefd) {
- err = fastrpc_map_create(fl, init.filefd, init.filelen, 0, &map);
+ err = fastrpc_map_create(fl, init.filefd, init.filelen, 0, 0, &map);
if (err)
goto err;
}
@@ -2251,7 +2283,7 @@ static int fastrpc_req_mem_map(struct fastrpc_user *fl, char __user *argp)
return -EFAULT;

/* create SMMU mapping */
- err = fastrpc_map_create(fl, req.fd, req.length, 0, &map);
+ err = fastrpc_map_create(fl, req.fd, req.length, 0, req.flags, &map);
if (err) {
dev_err(dev, "failed to map buffer, fd = %d\n", req.fd);
return err;
diff --git a/include/uapi/misc/fastrpc.h b/include/uapi/misc/fastrpc.h
index ba1ea5ed426c..b39c0e197a45 100644
--- a/include/uapi/misc/fastrpc.h
+++ b/include/uapi/misc/fastrpc.h
@@ -36,6 +36,11 @@
* cache maintenance for the buffer.
* @FASTRPC_MAP_FD_NOMAP: This flag is used to skip CPU mapping,
* otherwise behaves similar to FASTRPC_MAP_FD_DELAYED flag.
+ * @FASTRPC_MAP_FD_EXTENDED: Map buffer in extended SMMU IOVA space (16GB - 1TB)
+ * and DSP VA space (4GB - 512GB). Can be accessed only through uDMA.
+ * @FASTRPC_MAP_FD_DELAYED_EXTENDED: Map buffer in extended SMMU IOVA space
+ * (16GB - 1TB) but skip DSP mapping. DSP mapping will be done later by
+ * the user. Can be accessed only through uDMA.
* @FASTRPC_MAP_MAX: max count for flags
*
*/
@@ -45,6 +50,8 @@ enum fastrpc_map_flags {
FASTRPC_MAP_FD = 2,
FASTRPC_MAP_FD_DELAYED,
FASTRPC_MAP_FD_NOMAP = 16,
+ FASTRPC_MAP_FD_EXTENDED,
+ FASTRPC_MAP_FD_DELAYED_EXTENDED,
FASTRPC_MAP_MAX,
};


--
2.34.1