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 <[email protected]>
---
 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

Reply via email to