* [PATCH v2 3/4] misc: fastrpc: add extended context bank support
2026-10-07 11:37 [PATCH v2 0/4] misc: fastrpc: add extended IOVA mapping support Vinayak Katoch
2026-10-07 11:37 ` [PATCH v2 1/4] dt-bindings: misc: qcom,fastrpc: add iommu-ranges support for context bank Vinayak Katoch
2026-10-07 11:37 ` [PATCH v2 2/4] misc: fastrpc: handle multi-cell reg in context bank probe Vinayak Katoch
@ 2026-10-07 11:37 ` Vinayak Katoch
2026-10-07 11:37 ` [PATCH v2 4/4] misc: fastrpc: add UAPI flags for extended IOVA mapping Vinayak Katoch
3 siblings, 0 replies; 5+ messages in thread
From: Vinayak Katoch @ 2026-10-07 11:37 UTC (permalink / raw)
To: Srinivas Kandagatla, Ekansh Gupta, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Arnd Bergmann,
Greg Kroah-Hartman
Cc: Bharath Kumar, Chenna Kesava Raju, linux-arm-msm, dri-devel,
devicetree, linux-kernel, Vinayak Katoch
Detect extended context banks by the presence of iommu-ranges on the
context bank node. Register them in a separate ext_cb array so the
mapping layer can direct large allocations into the wider IOVA window.
Signed-off-by: Vinayak Katoch <vinayak.katoch@oss.qualcomm.com>
---
drivers/misc/fastrpc.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index 5c7bb56cf46d..d40cdcd5dec3 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -307,6 +307,8 @@ struct fastrpc_channel_ctx {
struct qcom_scm_vmperm vmperms[FASTRPC_MAX_VMIDS];
struct rpmsg_device *rpdev;
struct fastrpc_session_ctx session[FASTRPC_MAX_SESSIONS];
+ struct fastrpc_session_ctx **ext_cb;
+ int ext_cb_count;
spinlock_t lock;
struct idr ctx_idr;
struct list_head users;
@@ -538,9 +540,13 @@ static int fastrpc_remote_heap_alloc(struct fastrpc_user *fl, struct device *dev
static void fastrpc_channel_ctx_free(struct kref *ref)
{
struct fastrpc_channel_ctx *cctx;
+ int i;
cctx = container_of(ref, struct fastrpc_channel_ctx, refcount);
+ for (i = 0; i < cctx->ext_cb_count; i++)
+ kfree(cctx->ext_cb[i]);
+ kfree(cctx->ext_cb);
idr_destroy(&cctx->ctx_idr);
kfree(cctx);
}
@@ -2343,6 +2349,7 @@ static int fastrpc_cb_init(struct platform_device *pdev)
u32 dma_bits;
u32 sid = 0;
int rc;
+ bool is_extended_cb = false;
cctx = dev_get_drvdata(dev->parent);
if (!cctx)
@@ -2352,6 +2359,43 @@ static int fastrpc_cb_init(struct platform_device *pdev)
of_n_addr_cells(dev->of_node) - 1, &sid))
dev_info(dev, "FastRPC Session ID not specified in DT\n");
+ if (of_property_present(dev->of_node, "iommu-ranges"))
+ is_extended_cb = true;
+
+ if (is_extended_cb) {
+ struct fastrpc_session_ctx **new_ext;
+
+ sess = kzalloc_obj(*sess);
+ if (!sess)
+ return -ENOMEM;
+
+ rc = dma_set_mask(dev, DMA_BIT_MASK(40));
+ if (rc) {
+ dev_err(dev, "40-bit DMA enable failed\n");
+ kfree(sess);
+ return rc;
+ }
+
+ new_ext = krealloc(cctx->ext_cb,
+ (cctx->ext_cb_count + 1) * sizeof(*cctx->ext_cb),
+ GFP_KERNEL);
+ if (!new_ext) {
+ kfree(sess);
+ return -ENOMEM;
+ }
+
+ spin_lock_irqsave(&cctx->lock, flags);
+ cctx->ext_cb = new_ext;
+ sess->valid = true;
+ sess->dev = dev;
+ sess->sid = sid;
+ dev_set_drvdata(dev, sess);
+ cctx->ext_cb[cctx->ext_cb_count++] = sess;
+ spin_unlock_irqrestore(&cctx->lock, flags);
+
+ return 0;
+ }
+
spin_lock_irqsave(&cctx->lock, flags);
if (cctx->sesscount >= FASTRPC_MAX_SESSIONS) {
spin_unlock_irqrestore(&cctx->lock, flags);
@@ -2391,6 +2435,8 @@ static void fastrpc_cb_devices_destroy(struct rpmsg_device *rpdev)
spin_lock_irqsave(&cctx->lock, flags);
for (i = 0; i < cctx->sesscount; i++)
cctx->session[i].valid = false;
+ for (i = 0; i < cctx->ext_cb_count; i++)
+ cctx->ext_cb[i]->valid = false;
spin_unlock_irqrestore(&cctx->lock, flags);
for_each_available_child_of_node(rdev->of_node, np) {
--
2.34.1
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH v2 4/4] misc: fastrpc: add UAPI flags for extended IOVA mapping
2026-10-07 11:37 [PATCH v2 0/4] misc: fastrpc: add extended IOVA mapping support Vinayak Katoch
` (2 preceding siblings ...)
2026-10-07 11:37 ` [PATCH v2 3/4] misc: fastrpc: add extended context bank support Vinayak Katoch
@ 2026-10-07 11:37 ` Vinayak Katoch
3 siblings, 0 replies; 5+ messages in thread
From: Vinayak Katoch @ 2026-10-07 11:37 UTC (permalink / raw)
To: Srinivas Kandagatla, Ekansh Gupta, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Arnd Bergmann,
Greg Kroah-Hartman
Cc: Bharath Kumar, Chenna Kesava Raju, linux-arm-msm, dri-devel,
devicetree, linux-kernel, Vinayak Katoch
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.
Store the mapping flags in struct fastrpc_map. fastrpc_map_create()
validates the cached entry's flags against the request; a mismatched
entry is dropped and a fresh attachment is made to the correct CB type,
preventing a cached regular-CB map from being returned for an
extended-CB request.
All existing call sites pass flags=0 and are unaffected.
Signed-off-by: Vinayak Katoch <vinayak.katoch@oss.qualcomm.com>
---
drivers/misc/fastrpc.c | 83 ++++++++++++++++++++++++++++++++++-----------
include/uapi/misc/fastrpc.h | 7 ++++
2 files changed, 71 insertions(+), 19 deletions(-)
diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
index d40cdcd5dec3..4ba07a5b28bb 100644
--- a/drivers/misc/fastrpc.c
+++ b/drivers/misc/fastrpc.c
@@ -81,6 +81,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)
@@ -252,6 +257,7 @@ struct fastrpc_map {
u64 len;
u64 raddr;
u32 attr;
+ u32 flags;
struct kref refcount;
};
@@ -398,7 +404,7 @@ static void fastrpc_free_map(struct kref *ref)
err = qcom_scm_assign_mem(map->dma_addr, map->len,
&src_perms, &perm, 1);
if (err) {
- dev_err(map->fl->sctx->dev,
+ dev_err(map->attach->dev,
"Failed to assign memory dma_addr %pad size 0x%llx err %d\n",
&map->dma_addr, map->len, err);
return;
@@ -882,16 +888,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, u32 flags,
+ 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;
@@ -911,9 +920,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;
}
@@ -928,18 +937,20 @@ 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 get_err;
}
map->va = sg_virt(map->table->sgl);
map->len = len;
+ map->flags = flags;
if (attr & FASTRPC_ATTR_SECUREMAP) {
/*
@@ -956,7 +967,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 get_err;
@@ -979,13 +990,47 @@ 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)) {
+ struct fastrpc_session_ctx **ext_cb;
+ int i, count, err = -ENODEV;
+ unsigned long lock_flags;
+
+ spin_lock_irqsave(&fl->cctx->lock, lock_flags);
+ count = fl->cctx->ext_cb_count;
+ ext_cb = fl->cctx->ext_cb;
+ spin_unlock_irqrestore(&fl->cctx->lock, lock_flags);
+
+ if (!count) {
+ dev_err(fl->sctx->dev, "no extended context bank found\n");
+ return -ENODEV;
+ }
+
+ for (i = 0; i < count; i++) {
+ err = fastrpc_map_attach_to_dev(fl, fd, len, attr, flags,
+ ext_cb[i], ppmap);
+ if (err != -ENOMEM)
+ break;
+ }
+ return err;
+ }
+
+ return fastrpc_map_attach_to_dev(fl, fd, len, attr, flags, 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;
+ if (!fastrpc_map_lookup(fl, fd, ppmap, true)) {
+ if ((*ppmap)->flags == flags)
+ return 0;
+ fastrpc_map_put(*ppmap);
+ *ppmap = NULL;
+ }
- return fastrpc_map_attach(fl, fd, len, attr, ppmap);
+ return fastrpc_map_attach(fl, fd, len, attr, flags, ppmap);
}
/*
@@ -1063,10 +1108,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;
@@ -1615,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;
}
@@ -2221,7 +2266,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
^ permalink raw reply [flat|nested] 5+ messages in thread