Support mapping userspace allocated buffers. If userspace allocates a buffer using rpcmem or DMABUF and sends it via a map request, fastrpc will map it to SMMU and DSP. Add support for both map and unmap requests.
Signed-off-by: Ekansh Gupta <ekansh.gu...@oss.qualcomm.com> --- drivers/misc/fastrpc.c | 188 ++++++++++++++++++++++++++++++++--------- 1 file changed, 150 insertions(+), 38 deletions(-) diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 378923594f02..3c88c8e9ba51 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -1797,17 +1797,16 @@ static int fastrpc_get_dsp_info(struct fastrpc_user *fl, char __user *argp) return 0; } -static int fastrpc_req_munmap_impl(struct fastrpc_user *fl, struct fastrpc_buf *buf) +static int fastrpc_req_munmap_dsp(struct fastrpc_user *fl, uintptr_t raddr, u64 size) { struct fastrpc_invoke_args args[1] = { [0] = { 0 } }; struct fastrpc_munmap_req_msg req_msg; - struct device *dev = fl->sctx->dev; int err; u32 sc; req_msg.client_id = fl->client_id; - req_msg.size = buf->size; - req_msg.vaddr = buf->raddr; + req_msg.size = size; + req_msg.vaddr = raddr; args[0].ptr = (u64) (uintptr_t) &req_msg; args[0].length = sizeof(req_msg); @@ -1815,6 +1814,16 @@ static int fastrpc_req_munmap_impl(struct fastrpc_user *fl, struct fastrpc_buf * sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MUNMAP, 1, 0); err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE, sc, &args[0]); + + return err; +} + +static int fastrpc_req_munmap_impl(struct fastrpc_user *fl, struct fastrpc_buf *buf) +{ + struct device *dev = fl->sctx->dev; + int err; + + err = fastrpc_req_munmap_dsp(fl, buf->raddr, buf->size); if (!err) { dev_dbg(dev, "unmmap\tpt 0x%09lx OK\n", buf->raddr); spin_lock(&fl->lock); @@ -1831,8 +1840,10 @@ static int fastrpc_req_munmap_impl(struct fastrpc_user *fl, struct fastrpc_buf * static int fastrpc_req_munmap(struct fastrpc_user *fl, char __user *argp) { struct fastrpc_buf *buf = NULL, *iter, *b; + struct fastrpc_map *map = NULL, *iterm, *m; struct fastrpc_req_munmap req; struct device *dev = fl->sctx->dev; + int err; if (copy_from_user(&req, argp, sizeof(req))) return -EFAULT; @@ -1846,35 +1857,91 @@ static int fastrpc_req_munmap(struct fastrpc_user *fl, char __user *argp) } spin_unlock(&fl->lock); - if (!buf) { - dev_err(dev, "mmap\t\tpt 0x%09llx [len 0x%08llx] not in list\n", + if (buf) { + err = fastrpc_req_munmap_impl(fl, buf); + if (err) { + spin_lock(&fl->lock); + list_add_tail(&buf->node, &fl->mmaps); + spin_unlock(&fl->lock); + } + return err; + } + + spin_lock(&fl->lock); + list_for_each_entry_safe(iterm, m, &fl->maps, node) { + if (iterm->raddr == req.vaddrout) { + map = iterm; + list_del(&iterm->node); + break; + } + } + spin_unlock(&fl->lock); + if (!map) { + dev_dbg(dev, "buffer/map not found addr 0x%09llx, len 0x%08llx\n", req.vaddrout, req.size); return -EINVAL; } - return fastrpc_req_munmap_impl(fl, buf); + err = fastrpc_req_munmap_dsp(fl, map->raddr, map->size); + if (err) { + dev_dbg(dev, "unmmap\tpt fd = %d, 0x%09llx error\n", map->fd, map->raddr); + spin_lock(&fl->lock); + list_add_tail(&map->node, &fl->maps); + spin_unlock(&fl->lock); + } else { + fastrpc_map_put(map); + } + return err; } -static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp) +static int fastrpc_req_map_dsp(struct fastrpc_user *fl, u64 phys, + u64 size, u32 flag, uintptr_t vaddrin, + u64 *raddr) { struct fastrpc_invoke_args args[3] = { [0 ... 2] = { 0 } }; - struct fastrpc_buf *buf = NULL; struct fastrpc_mmap_req_msg req_msg; struct fastrpc_mmap_rsp_msg rsp_msg; struct fastrpc_phy_page pages; - struct fastrpc_req_mmap req; - struct device *dev = fl->sctx->dev; int err; u32 sc; - if (copy_from_user(&req, argp, sizeof(req))) - return -EFAULT; + req_msg.client_id = fl->client_id; + req_msg.flags = flag; + req_msg.vaddr = vaddrin; + req_msg.num = sizeof(pages); - if (req.flags != ADSP_MMAP_ADD_PAGES && req.flags != ADSP_MMAP_REMOTE_HEAP_ADDR) { - dev_err(dev, "flag not supported 0x%x\n", req.flags); + args[0].ptr = (u64)(uintptr_t)&req_msg; + args[0].length = sizeof(req_msg); - return -EINVAL; + pages.addr = phys; + pages.size = size; + + args[1].ptr = (u64)(uintptr_t)&pages; + args[1].length = sizeof(pages); + + args[2].ptr = (u64)(uintptr_t)&rsp_msg; + args[2].length = sizeof(rsp_msg); + sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MMAP, 2, 1); + err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE, sc, + &args[0]); + + if (err) { + dev_err(fl->sctx->dev, "mmap error (len 0x%08llx)\n", size); + return err; } + *raddr = rsp_msg.vaddr; + + return 0; +} + +static int fastrpc_req_buf_alloc(struct fastrpc_user *fl, + struct fastrpc_req_mmap req, + char __user *argp) +{ + struct device *dev = fl->sctx->dev; + struct fastrpc_buf *buf = NULL; + u64 raddr = 0; + int err; if (req.vaddrin) { dev_err(dev, "adding user allocated pages is not supported\n"); @@ -1891,26 +1958,8 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp) return err; } - req_msg.client_id = fl->client_id; - req_msg.flags = req.flags; - req_msg.vaddr = req.vaddrin; - req_msg.num = sizeof(pages); - - args[0].ptr = (u64) (uintptr_t) &req_msg; - args[0].length = sizeof(req_msg); - - pages.addr = buf->phys; - pages.size = buf->size; - - args[1].ptr = (u64) (uintptr_t) &pages; - args[1].length = sizeof(pages); - - args[2].ptr = (u64) (uintptr_t) &rsp_msg; - args[2].length = sizeof(rsp_msg); - - sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MMAP, 2, 1); - err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE, sc, - &args[0]); + err = fastrpc_req_map_dsp(fl, buf->phys, buf->size, req.flags, + req.vaddrin, &raddr); if (err) { dev_err(dev, "mmap error (len 0x%08llx)\n", buf->size); fastrpc_buf_free(buf); @@ -1918,10 +1967,10 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp) } /* update the buffer to be able to deallocate the memory on the DSP */ - buf->raddr = (uintptr_t) rsp_msg.vaddr; + buf->raddr = (uintptr_t)raddr; /* let the client know the address to use */ - req.vaddrout = rsp_msg.vaddr; + req.vaddrout = raddr; /* Add memory to static PD pool, protection thru hypervisor */ if (req.flags == ADSP_MMAP_REMOTE_HEAP_ADDR && fl->cctx->vmcount) { @@ -1956,6 +2005,69 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp) return err; } +static int fastrpc_req_map_create(struct fastrpc_user *fl, + struct fastrpc_req_mmap req, + char __user *argp) +{ + struct fastrpc_map *map = NULL; + struct device *dev = fl->sctx->dev; + u64 raddr = 0; + int err; + + err = fastrpc_map_create(fl, req.fd, req.size, 0, &map); + if (err) { + dev_err(dev, "failed to map buffer, fd = %d\n", req.fd); + return err; + } + + err = fastrpc_req_map_dsp(fl, map->phys, map->size, req.flags, + req.vaddrin, &raddr); + if (err) + goto err_invoke; + + /* update the buffer to be able to deallocate the memory on the DSP */ + map->raddr = (uintptr_t)raddr; + + /* let the client know the address to use */ + req.vaddrout = raddr; + dev_dbg(dev, "mmap\t\tpt 0x%09llx OK [len 0x%08llx]\n", + map->raddr, map->size); + + if (copy_to_user((void __user *)argp, &req, sizeof(req))) { + err = -EFAULT; + goto err_copy; + } + + return 0; +err_copy: + fastrpc_req_munmap_dsp(fl, map->raddr, map->size); +err_invoke: + fastrpc_map_put(map); + + return err; +} + +static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp) +{ + struct fastrpc_req_mmap req; + int err; + + if (copy_from_user(&req, argp, sizeof(req))) + return -EFAULT; + + if ((req.flags == ADSP_MMAP_ADD_PAGES || + req.flags == ADSP_MMAP_REMOTE_HEAP_ADDR)) { + err = fastrpc_req_buf_alloc(fl, req, argp); + if (err) + return err; + } else { + err = fastrpc_req_map_create(fl, req, argp); + if (err) + return err; + } + return 0; +} + static int fastrpc_req_mem_unmap_impl(struct fastrpc_user *fl, struct fastrpc_mem_unmap *req) { struct fastrpc_invoke_args args[1] = { [0] = { 0 } }; -- 2.34.1