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

Reply via email to