drivers/misc/fastrpc.c | 188 ++++++++++++++++++++++++++++++++--------- 1 file changed, 150 insertions(+), 38 deletions(-)
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.gupta@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
On Fri, Jul 04, 2025 at 02:07:26PM +0530, Ekansh Gupta wrote: > 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. Please start by describing a problem first, then the actions to solve it. > > Signed-off-by: Ekansh Gupta <ekansh.gupta@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) Please split the patch into two functional parts: one for refactoring and one for the actual bugfix. It is pretty hard to follow the logic. > { > 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); -- With best wishes Dmitry
On Fri, Jul 04, 2025 at 02:07:26PM +0530, Ekansh Gupta wrote: > 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.gupta@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) uintptr_t is not a valid kernel type, please use our real ones :) "*u64"? > { > 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); No validation of these user-provided values? Or did I miss where that happens? > > - 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; Again, "uintptr_t" isn't for the kernel please. thanks, greg k-h
© 2016 - 2025 Red Hat, Inc.