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