From: Ekansh Gupta <ekansh.gupta@oss.qualcomm.com>
To: "Oded Gabbay" <ogabbay@kernel.org>,
"Jonathan Corbet" <corbet@lwn.net>,
"Shuah Khan" <skhan@linuxfoundation.org>,
"Randy Dunlap" <rdunlap@infradead.org>,
"Ekansh Gupta" <ekansh.gupta@oss.qualcomm.com>,
"Srinivas Kandagatla" <srini@kernel.org>,
"Arnd Bergmann" <arnd@arndb.de>,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
"David Airlie" <airlied@gmail.com>,
"Simona Vetter" <simona@ffwll.ch>,
"Maarten Lankhorst" <maarten.lankhorst@linux.intel.com>,
"Maxime Ripard" <mripard@kernel.org>,
"Thomas Zimmermann" <tzimmermann@suse.de>,
"Sumit Semwal" <sumit.semwal@linaro.org>,
"Christian König" <christian.koenig@amd.com>,
"Philipp Stanner" <phasta@kernel.org>,
dmitry.baryshkov@oss.qualcomm.com, andersson@kernel.org,
krzk@kernel.org, rob.clark@oss.qualcomm.com, jgg@ziepe.ca
Cc: lingtong@qti.qualcomm.com, cacar@qti.qualcomm.com,
sandheep@qti.qualcomm.com,
Bharath Kumar <bkumar@qti.qualcomm.com>,
Chenna Kesava Raju <chennak@qti.qualcomm.com>,
dri-devel@lists.freedesktop.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org,
Bharath Kumar <quic_bkumar@quicinc.com>,
Chenna Kesava Raju <quic_chennak@quicinc.com>,
Ekansh Gupta <ekangupt@qti.qualcomm.com>
Subject: [PATCH v4 19/25] accel/qda: Add remote memory map and unmap to the legacy shim
Date: Mon, 02 Nov 2026 03:51:32 +0530 [thread overview]
Message-ID: <20261102-v4-v4-19-88f2f24a5f0b@qti.qualcomm.com> (raw)
In-Reply-To: <20261102-v4-v4-0-88f2f24a5f0b@qti.qualcomm.com>
From: Ekansh Gupta <ekangupt@qti.qualcomm.com>
Applications written for the /dev/fastrpc-* interface name buffers by
file descriptor rather than GEM handle, and have no handle table to
keep a mapped buffer alive between the map and unmap calls. Serve the
four legacy map and unmap ioctls by importing the descriptor as usual,
and track the live mapping on the open file so the buffer stays
referenced for as long as the DSP has it mapped, exactly the job a GEM
handle does for the native UAPI.
The buffer reaches the shared mapping code already imported, in place
of a handle. As for a buffer named by handle, it must be mapped in the
calling session's context bank, since a descriptor can name a buffer
another session exported, and the requested length must fit in it.
Two lists are kept per open file, since the two legacy unmap paths name
a mapping differently: MUNMAP only ever gets back the address map
returned, while MEM_UNMAP uses the file descriptor as the identifier
the DSP tracks the buffer by. A mapping is recorded with the address
and length it was made with, and an unmap must match them: the length
the DSP is asked to unmap is the recorded one, and MUNMAP with a
different length is refused. The same descriptor cannot be mapped
twice with MEM_MAP, as the DSP could not tell the two apart on unmap,
and a negative buffer offset is refused.
If the DSP cannot unmap a mapping, it stays recorded so the unmap can
be retried. If the mapping cannot be reported back to the caller, it is
taken down again rather than left unreachable. Mappings still
outstanding when the file closes are unmapped on the DSP before the
buffers they hold are released, so the DSP is never left using memory
that has been freed.
Signed-off-by: Ekansh Gupta <ekangupt@qti.qualcomm.com>
---
drivers/accel/qda/qda_fastrpc.c | 40 ++++--
drivers/accel/qda/qda_fastrpc.h | 17 +++
drivers/accel/qda/qda_fastrpc_shim.c | 262 +++++++++++++++++++++++++++++++++++
drivers/accel/qda/qda_ioctl.c | 64 ++++++---
drivers/accel/qda/qda_ioctl.h | 4 +
drivers/accel/qda/qda_legacy_ops.c | 77 ++++++++++
drivers/accel/qda/qda_legacy_ops.h | 11 ++
7 files changed, 447 insertions(+), 28 deletions(-)
diff --git a/drivers/accel/qda/qda_fastrpc.c b/drivers/accel/qda/qda_fastrpc.c
index dbd14cd07cb2..b35604fce630 100644
--- a/drivers/accel/qda/qda_fastrpc.c
+++ b/drivers/accel/qda/qda_fastrpc.c
@@ -633,7 +633,7 @@ void qda_fastrpc_flush_pending(struct qda_dev *qdev)
*/
void qda_fastrpc_return_result(struct qda_fastrpc_invoke_ctx *ctx, void *argp)
{
- struct drm_qda_mem_map *margs = argp;
+ struct qda_mem_map_args *map_args = argp;
struct qda_fastrpc_map_rsp_msg *rsp;
int idx;
@@ -650,7 +650,7 @@ void qda_fastrpc_return_result(struct qda_fastrpc_invoke_ctx *ctx, void *argp)
rsp = (struct qda_fastrpc_map_rsp_msg *)
((u8 *)to_qda_gem_obj(ctx->gem_objs[idx])->virt + ctx->args[idx].offset);
- margs->vaddrout = rsp->vaddrout;
+ map_args->map.vaddrout = rsp->vaddrout;
}
/**
@@ -935,19 +935,33 @@ static int qda_fastrpc_prepare_args_init_create(struct qda_fastrpc_invoke_ctx *c
* buffer is held by the context until the request is done, so that closing its
* handle meanwhile cannot free memory the DSP is being told to map. The
* region must fit in the buffer, as the DSP would otherwise map past its end.
+ *
+ * A caller with no handle table supplies the buffer already imported. It is
+ * checked as a buffer named by handle would be: an fd can name a buffer that
+ * another session exported, which resolves to the original object, still
+ * mapped in that session's context bank.
*/
-static int setup_mmap_pages(struct qda_fastrpc_invoke_ctx *ctx, struct drm_qda_mem_map *margs,
+static int setup_mmap_pages(struct qda_fastrpc_invoke_ctx *ctx, struct qda_mem_map_args *args,
struct qda_phy_page *pages)
{
+ struct drm_qda_mem_map *margs = &args->map;
struct qda_gem_obj *qda_gem_obj;
int err;
- if (!margs->handle)
- return -EINVAL;
+ if (args->obj) {
+ if (to_qda_gem_obj(args->obj)->iommu_dev != ctx->session->assigned_iommu_dev)
+ return -EACCES;
- err = get_gem_obj_from_handle(ctx, margs->handle, &ctx->map_obj);
- if (err)
- return err;
+ drm_gem_object_get(args->obj);
+ ctx->map_obj = args->obj;
+ } else {
+ if (!margs->handle)
+ return -EINVAL;
+
+ err = get_gem_obj_from_handle(ctx, margs->handle, &ctx->map_obj);
+ if (err)
+ return err;
+ }
qda_gem_obj = to_qda_gem_obj(ctx->map_obj);
if (margs->size > qda_gem_obj->size)
@@ -967,7 +981,8 @@ static int setup_mmap_pages(struct qda_fastrpc_invoke_ctx *ctx, struct drm_qda_m
*/
static int qda_fastrpc_prepare_args_map(struct qda_fastrpc_invoke_ctx *ctx, void *argp)
{
- struct drm_qda_mem_map *margs = argp;
+ struct qda_mem_map_args *map_args = argp;
+ struct drm_qda_mem_map *margs = &map_args->map;
struct qda_fastrpc_map_req_msg *req;
struct qda_gem_obj *kernel_gem;
u8 *gv;
@@ -996,7 +1011,7 @@ static int qda_fastrpc_prepare_args_map(struct qda_fastrpc_invoke_ctx *ctx, void
req->vaddr = margs->vaddrin;
req->num = sizeof(struct qda_phy_page);
- err = setup_mmap_pages(ctx, margs, (struct qda_phy_page *)(gv + off_pages));
+ err = setup_mmap_pages(ctx, map_args, (struct qda_phy_page *)(gv + off_pages));
if (err)
goto out_put;
@@ -1020,7 +1035,8 @@ static int qda_fastrpc_prepare_args_map(struct qda_fastrpc_invoke_ctx *ctx, void
*/
static int qda_fastrpc_prepare_args_mem_map(struct qda_fastrpc_invoke_ctx *ctx, void *argp)
{
- struct drm_qda_mem_map *margs = argp;
+ struct qda_mem_map_args *map_args = argp;
+ struct drm_qda_mem_map *margs = &map_args->map;
struct qda_fastrpc_mem_map_req_msg *req;
struct qda_gem_obj *kernel_gem;
u8 *gv;
@@ -1056,7 +1072,7 @@ static int qda_fastrpc_prepare_args_mem_map(struct qda_fastrpc_invoke_ctx *ctx,
req->num = sizeof(struct qda_phy_page);
req->data_len = 0;
- err = setup_mmap_pages(ctx, margs, (struct qda_phy_page *)(gv + off_pages));
+ err = setup_mmap_pages(ctx, map_args, (struct qda_phy_page *)(gv + off_pages));
if (err)
goto out_put;
diff --git a/drivers/accel/qda/qda_fastrpc.h b/drivers/accel/qda/qda_fastrpc.h
index 889b41dc20b0..10a99bbfa383 100644
--- a/drivers/accel/qda/qda_fastrpc.h
+++ b/drivers/accel/qda/qda_fastrpc.h
@@ -360,6 +360,23 @@ struct qda_init_create_args {
struct drm_gem_object *elf_obj;
};
+/**
+ * struct qda_mem_map_args - Kernel-side arguments for mapping a buffer into the DSP
+ *
+ * Wraps the UAPI arguments so that a caller with no handle table, such as the
+ * legacy shim, can pass an already imported buffer.
+ */
+struct qda_mem_map_args {
+ /** @map: Mapping parameters; @map.vaddrout is filled in on success */
+ struct drm_qda_mem_map map;
+ /**
+ * @obj: Buffer to map, in the session's context bank, or NULL if
+ * @map.handle names it. Borrowed: the caller keeps its reference for
+ * the length of the call.
+ */
+ struct drm_gem_object *obj;
+};
+
struct qda_fastrpc_invoke_ctx *qda_fastrpc_context_alloc(struct qda_dev *qdev);
void qda_fastrpc_context_free(struct kref *ref);
void qda_fastrpc_cleanup_handlelist(struct qda_fastrpc_invoke_ctx *ctx);
diff --git a/drivers/accel/qda/qda_fastrpc_shim.c b/drivers/accel/qda/qda_fastrpc_shim.c
index 4a2ba20ee01a..c46d2de4f581 100644
--- a/drivers/accel/qda/qda_fastrpc_shim.c
+++ b/drivers/accel/qda/qda_fastrpc_shim.c
@@ -8,7 +8,9 @@
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/limits.h>
+#include <linux/list.h>
#include <linux/miscdevice.h>
+#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/slab.h>
@@ -21,9 +23,29 @@
#include "qda_fastrpc.h"
#include "qda_legacy_ops.h"
+/*
+ * A buffer the DSP has mapped for an open file. A legacy session has no
+ * handle table, so this is what keeps the buffer alive for as long as the
+ * mapping lasts, the job a GEM handle does for the accel UAPI.
+ *
+ * Plain mappings are found by the address map returned, which is all
+ * MUNMAP carries. Attribute-based ones are found by the fd, which doubles
+ * as the identifier the DSP tracks the buffer by.
+ */
+struct qda_shim_mapping {
+ struct list_head node;
+ u64 key;
+ u64 vaddr;
+ u64 size;
+ struct drm_gem_object *obj;
+};
+
/* State of one open /dev/fastrpc-* file */
struct qda_shim_file {
struct qda_session *session;
+ struct mutex maps_lock;
+ struct list_head mmap_list;
+ struct list_head mem_map_list;
/* Opened through the /dev/fastrpc-<dsp>-secure node */
bool secure_node;
/* Properties of the qda_shim_dev this file was opened on */
@@ -79,6 +101,83 @@ static struct drm_gem_object *shim_import_fd(struct qda_session *session, s32 fd
return obj;
}
+/* Takes ownership of @obj on success; on failure the caller still owns it */
+static struct qda_shim_mapping *shim_mapping_add(struct qda_shim_file *sf,
+ struct list_head *list, u64 key, u64 vaddr,
+ u64 size, struct drm_gem_object *obj)
+{
+ struct qda_shim_mapping *m, *new;
+
+ new = kzalloc_obj(*new);
+ if (!new)
+ return ERR_PTR(-ENOMEM);
+
+ new->key = key;
+ new->vaddr = vaddr;
+ new->size = size;
+ new->obj = obj;
+
+ guard(mutex)(&sf->maps_lock);
+
+ list_for_each_entry(m, list, node) {
+ if (m->key == key) {
+ kfree(new);
+ return ERR_PTR(-EEXIST);
+ }
+ }
+ list_add_tail(&new->node, list);
+
+ return new;
+}
+
+static struct qda_shim_mapping *shim_mapping_detach(struct qda_shim_file *sf,
+ struct list_head *list, u64 key, u64 vaddr)
+{
+ struct qda_shim_mapping *m;
+
+ guard(mutex)(&sf->maps_lock);
+
+ list_for_each_entry(m, list, node) {
+ if (m->key == key && m->vaddr == vaddr) {
+ list_del(&m->node);
+ return m;
+ }
+ }
+
+ return NULL;
+}
+
+static void shim_mapping_attach(struct qda_shim_file *sf, struct list_head *list,
+ struct qda_shim_mapping *m)
+{
+ guard(mutex)(&sf->maps_lock);
+ list_add_tail(&m->node, list);
+}
+
+static void shim_mapping_free(struct qda_shim_mapping *m)
+{
+ drm_gem_object_put(m->obj);
+ kfree(m);
+}
+
+/* The DSP unmap comes first: the buffer must outlive the DSP's use of it */
+static void shim_mappings_release(struct qda_shim_file *sf)
+{
+ struct qda_shim_mapping *m, *tmp;
+
+ list_for_each_entry_safe(m, tmp, &sf->mmap_list, node) {
+ list_del(&m->node);
+ qda_legacy_ops_table.munmap(sf->session, m->vaddr, m->size);
+ shim_mapping_free(m);
+ }
+
+ list_for_each_entry_safe(m, tmp, &sf->mem_map_list, node) {
+ list_del(&m->node);
+ qda_legacy_ops_table.mem_unmap(sf->session, m->key, m->vaddr, m->size);
+ shim_mapping_free(m);
+ }
+}
+
static int qda_shim_open(struct inode *inode, struct file *file)
{
struct qda_shim_node *snode = container_of(file->private_data, struct qda_shim_node,
@@ -97,6 +196,9 @@ static int qda_shim_open(struct inode *inode, struct file *file)
return err;
}
+ mutex_init(&sf->maps_lock);
+ INIT_LIST_HEAD(&sf->mmap_list);
+ INIT_LIST_HEAD(&sf->mem_map_list);
sf->secure_node = snode->secure;
sf->secure_channel = snode->sdev->secure_channel;
sf->unsigned_support = snode->sdev->unsigned_support;
@@ -110,8 +212,10 @@ static int qda_shim_release(struct inode *inode, struct file *file)
{
struct qda_shim_file *sf = file->private_data;
+ shim_mappings_release(sf);
qda_legacy_ops_table.release(sf->session);
qda_legacy_ops_table.session_destroy(sf->session);
+ mutex_destroy(&sf->maps_lock);
kfree(sf);
return 0;
@@ -191,6 +295,156 @@ static long qda_shim_init_create(struct qda_shim_file *sf, void __user *argp)
return err;
}
+static long qda_shim_mmap(struct qda_shim_file *sf, void __user *argp)
+{
+ struct qda_shim_mapping *m;
+ struct fastrpc_req_mmap args;
+ struct drm_gem_object *obj;
+ int err;
+
+ if (copy_from_user(&args, argp, sizeof(args)))
+ return -EFAULT;
+
+ obj = shim_import_fd(sf->session, args.fd);
+ if (IS_ERR(obj))
+ return PTR_ERR(obj);
+ if (!obj)
+ return -EINVAL;
+
+ err = qda_legacy_ops_table.mmap(sf->session, obj, args.vaddrin, args.size, args.flags,
+ &args.vaddrout);
+ if (err) {
+ drm_gem_object_put(obj);
+ return err;
+ }
+
+ m = shim_mapping_add(sf, &sf->mmap_list, args.vaddrout, args.vaddrout, args.size, obj);
+ if (IS_ERR(m)) {
+ err = PTR_ERR(m);
+ goto err_unmap;
+ }
+
+ if (copy_to_user(argp, &args, sizeof(args))) {
+ m = shim_mapping_detach(sf, &sf->mmap_list, args.vaddrout, args.vaddrout);
+ if (m) {
+ qda_legacy_ops_table.munmap(sf->session, m->vaddr, m->size);
+ shim_mapping_free(m);
+ }
+ return -EFAULT;
+ }
+
+ return 0;
+
+err_unmap:
+ qda_legacy_ops_table.munmap(sf->session, args.vaddrout, args.size);
+ drm_gem_object_put(obj);
+
+ return err;
+}
+
+static long qda_shim_munmap(struct qda_shim_file *sf, void __user *argp)
+{
+ struct fastrpc_req_munmap args;
+ struct qda_shim_mapping *m;
+ int err;
+
+ if (copy_from_user(&args, argp, sizeof(args)))
+ return -EFAULT;
+
+ m = shim_mapping_detach(sf, &sf->mmap_list, args.vaddrout, args.vaddrout);
+ if (!m)
+ return -ENOENT;
+
+ if (m->size != args.size) {
+ shim_mapping_attach(sf, &sf->mmap_list, m);
+ return -EINVAL;
+ }
+
+ err = qda_legacy_ops_table.munmap(sf->session, m->vaddr, m->size);
+ if (err) {
+ shim_mapping_attach(sf, &sf->mmap_list, m);
+ return err;
+ }
+
+ shim_mapping_free(m);
+
+ return 0;
+}
+
+static long qda_shim_mem_map(struct qda_shim_file *sf, void __user *argp)
+{
+ struct qda_shim_mapping *m;
+ struct fastrpc_mem_map args;
+ struct drm_gem_object *obj;
+ int err;
+
+ if (copy_from_user(&args, argp, sizeof(args)))
+ return -EFAULT;
+
+ if (args.offset < 0)
+ return -EINVAL;
+
+ obj = shim_import_fd(sf->session, args.fd);
+ if (IS_ERR(obj))
+ return PTR_ERR(obj);
+ if (!obj)
+ return -EINVAL;
+
+ /* Reserved before the DSP is asked, so the same fd cannot be mapped twice */
+ m = shim_mapping_add(sf, &sf->mem_map_list, args.fd, 0, args.length, obj);
+ if (IS_ERR(m)) {
+ drm_gem_object_put(obj);
+ return PTR_ERR(m);
+ }
+
+ err = qda_legacy_ops_table.mem_map(sf->session, obj, args.flags, args.attrs, args.offset,
+ args.vaddrin, args.length, args.fd, &args.vaddrout);
+ if (err) {
+ m = shim_mapping_detach(sf, &sf->mem_map_list, args.fd, 0);
+ if (m)
+ shim_mapping_free(m);
+ return err;
+ }
+
+ scoped_guard(mutex, &sf->maps_lock)
+ m->vaddr = args.vaddrout;
+
+ if (copy_to_user(argp, &args, sizeof(args))) {
+ m = shim_mapping_detach(sf, &sf->mem_map_list, args.fd, args.vaddrout);
+ if (m) {
+ qda_legacy_ops_table.mem_unmap(sf->session, m->key, m->vaddr, m->size);
+ shim_mapping_free(m);
+ }
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static long qda_shim_mem_unmap(struct qda_shim_file *sf, void __user *argp)
+{
+ struct fastrpc_mem_unmap args;
+ struct qda_shim_mapping *m;
+ int err;
+
+ if (copy_from_user(&args, argp, sizeof(args)))
+ return -EFAULT;
+
+ m = shim_mapping_detach(sf, &sf->mem_map_list, args.fd, args.vaddr);
+ if (!m)
+ return -ENOENT;
+
+ err = qda_legacy_ops_table.mem_unmap(sf->session, m->key, m->vaddr, m->size);
+ if (err) {
+ shim_mapping_attach(sf, &sf->mem_map_list, m);
+ return err;
+ }
+
+ shim_mapping_free(m);
+
+ return 0;
+}
+
static long qda_shim_invoke(struct qda_shim_file *sf, void __user *argp)
{
struct qda_legacy_invoke_arg *largs;
@@ -262,6 +516,14 @@ static long qda_shim_dispatch(struct qda_shim_file *sf, unsigned int cmd, void _
return qda_shim_alloc_dma_buf(sf, argp);
case FASTRPC_IOCTL_INIT_CREATE:
return qda_shim_init_create(sf, argp);
+ case FASTRPC_IOCTL_MMAP:
+ return qda_shim_mmap(sf, argp);
+ case FASTRPC_IOCTL_MUNMAP:
+ return qda_shim_munmap(sf, argp);
+ case FASTRPC_IOCTL_MEM_MAP:
+ return qda_shim_mem_map(sf, argp);
+ case FASTRPC_IOCTL_MEM_UNMAP:
+ return qda_shim_mem_unmap(sf, argp);
case FASTRPC_IOCTL_INVOKE:
return qda_shim_invoke(sf, argp);
default:
diff --git a/drivers/accel/qda/qda_ioctl.c b/drivers/accel/qda/qda_ioctl.c
index 17d1b488b4a9..999afa9e70c2 100644
--- a/drivers/accel/qda/qda_ioctl.c
+++ b/drivers/accel/qda/qda_ioctl.c
@@ -185,42 +185,74 @@ int qda_release_dsp_process(struct qda_dev *qdev, struct qda_session *session)
int qda_ioctl_mmap(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
struct drm_qda_mem_map *map_req = data;
+ struct qda_mem_map_args args = {
+ .map = *map_req,
+ };
+ int err;
+
+ err = qda_session_mem_map(file_priv->driver_priv, &args);
+ if (err)
+ return err;
- switch (map_req->request) {
+ map_req->vaddrout = args.map.vaddrout;
+
+ return 0;
+}
+
+/**
+ * qda_session_mem_map() - Map a buffer into the DSP's address space
+ * @session: Session to map for
+ * @args: Mapping parameters; @args->map.vaddrout is filled in on success
+ *
+ * For sessions with no handle table to name the buffer by, such as those of
+ * the legacy shim, which supply @args->obj.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+int qda_session_mem_map(struct qda_session *session, struct qda_mem_map_args *args)
+{
+ switch (args->map.request) {
case QDA_REQUEST_MMAP:
- return qda_fastrpc_invoke(QDA_FASTRPC_RMID_INIT_MMAP, data, file_priv->driver_priv);
+ return qda_fastrpc_invoke(QDA_FASTRPC_RMID_INIT_MMAP, args, session);
case QDA_REQUEST_MEM_MAP:
- return qda_fastrpc_invoke(QDA_FASTRPC_RMID_INIT_MEM_MAP, data,
- file_priv->driver_priv);
+ return qda_fastrpc_invoke(QDA_FASTRPC_RMID_INIT_MEM_MAP, args, session);
default:
return -EINVAL;
}
}
/**
- * qda_ioctl_munmap() - Remove a buffer's mapping from the DSP's address space
- * @dev: DRM device structure
- * @data: User-space data (struct drm_qda_mem_unmap)
- * @file_priv: DRM file private data
+ * qda_session_mem_unmap() - Remove a buffer's mapping from the DSP's address space
+ * @session: Session the mapping belongs to
+ * @unmap: Which mapping to remove
*
* Return: 0 on success, negative error code on failure
*/
-int qda_ioctl_munmap(struct drm_device *dev, void *data, struct drm_file *file_priv)
+int qda_session_mem_unmap(struct qda_session *session, struct drm_qda_mem_unmap *unmap)
{
- struct drm_qda_mem_unmap *unmap_req = data;
-
- switch (unmap_req->request) {
+ switch (unmap->request) {
case QDA_REQUEST_MUNMAP:
- return qda_fastrpc_invoke(QDA_FASTRPC_RMID_INIT_MUNMAP, data,
- file_priv->driver_priv);
+ return qda_fastrpc_invoke(QDA_FASTRPC_RMID_INIT_MUNMAP, unmap, session);
case QDA_REQUEST_MEM_UNMAP:
- return qda_fastrpc_invoke(QDA_FASTRPC_RMID_INIT_MEM_UNMAP, data,
- file_priv->driver_priv);
+ return qda_fastrpc_invoke(QDA_FASTRPC_RMID_INIT_MEM_UNMAP, unmap, session);
default:
return -EINVAL;
}
}
+/**
+ * qda_ioctl_munmap() - Remove a buffer's mapping from the DSP's address space
+ * @dev: DRM device structure
+ * @data: User-space data (struct drm_qda_mem_unmap)
+ * @file_priv: DRM file private data
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+int qda_ioctl_munmap(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+ return qda_session_mem_unmap(file_priv->driver_priv, data);
+}
+
/**
* qda_ioctl_invoke() - Run a method on the DSP
* @dev: DRM device structure
diff --git a/drivers/accel/qda/qda_ioctl.h b/drivers/accel/qda/qda_ioctl.h
index 9c053349c3fa..9b868189df0a 100644
--- a/drivers/accel/qda/qda_ioctl.h
+++ b/drivers/accel/qda/qda_ioctl.h
@@ -8,7 +8,9 @@
#include "qda_drv.h"
+struct drm_qda_mem_unmap;
struct qda_init_create_args;
+struct qda_mem_map_args;
int qda_ioctl_query(struct drm_device *dev, void *data, struct drm_file *file_priv);
int qda_ioctl_gem_create(struct drm_device *dev, void *data, struct drm_file *file_priv);
@@ -18,5 +20,7 @@ int qda_ioctl_init_create(struct drm_device *dev, void *data, struct drm_file *f
int qda_ioctl_mmap(struct drm_device *dev, void *data, struct drm_file *file_priv);
int qda_ioctl_munmap(struct drm_device *dev, void *data, struct drm_file *file_priv);
int qda_session_init_create(struct qda_session *session, struct qda_init_create_args *create);
+int qda_session_mem_map(struct qda_session *session, struct qda_mem_map_args *args);
+int qda_session_mem_unmap(struct qda_session *session, struct drm_qda_mem_unmap *unmap);
#endif /* __QDA_IOCTL_H__ */
diff --git a/drivers/accel/qda/qda_legacy_ops.c b/drivers/accel/qda/qda_legacy_ops.c
index 2b3b3f4fb246..ea815ab0c52a 100644
--- a/drivers/accel/qda/qda_legacy_ops.c
+++ b/drivers/accel/qda/qda_legacy_ops.c
@@ -75,6 +75,79 @@ static int legacy_release(struct qda_session *session)
return qda_release_dsp_process(session->qda_dev, session);
}
+static int legacy_mmap(struct qda_session *session, struct drm_gem_object *obj,
+ u64 vaddrin, u64 size, u32 flags, u64 *vaddrout)
+{
+ struct qda_mem_map_args args = {
+ .map = {
+ .request = QDA_REQUEST_MMAP,
+ .flags = flags,
+ .vaddrin = vaddrin,
+ .size = size,
+ },
+ .obj = obj,
+ };
+ int err;
+
+ err = qda_session_mem_map(session, &args);
+ if (err)
+ return err;
+
+ *vaddrout = args.map.vaddrout;
+
+ return 0;
+}
+
+static int legacy_mem_map(struct qda_session *session, struct drm_gem_object *obj, u32 flags,
+ u32 attrs, u32 offset, u64 vaddrin, u64 size, s32 dsp_handle,
+ u64 *vaddrout)
+{
+ struct qda_mem_map_args args = {
+ .map = {
+ .request = QDA_REQUEST_MEM_MAP,
+ .flags = flags,
+ .attrs = attrs,
+ .offset = offset,
+ .dsp_handle = dsp_handle,
+ .vaddrin = vaddrin,
+ .size = size,
+ },
+ .obj = obj,
+ };
+ int err;
+
+ err = qda_session_mem_map(session, &args);
+ if (err)
+ return err;
+
+ *vaddrout = args.map.vaddrout;
+
+ return 0;
+}
+
+static int legacy_munmap(struct qda_session *session, u64 vaddrout, u64 size)
+{
+ struct drm_qda_mem_unmap unmap = {
+ .request = QDA_REQUEST_MUNMAP,
+ .vaddrout = vaddrout,
+ .size = size,
+ };
+
+ return qda_session_mem_unmap(session, &unmap);
+}
+
+static int legacy_mem_unmap(struct qda_session *session, s32 dsp_handle, u64 vaddr, u64 size)
+{
+ struct drm_qda_mem_unmap unmap = {
+ .request = QDA_REQUEST_MEM_UNMAP,
+ .dsp_handle = dsp_handle,
+ .vaddr = vaddr,
+ .size = size,
+ };
+
+ return qda_session_mem_unmap(session, &unmap);
+}
+
/*
* As the GEM_CREATE ioctl, but exporting a DMA-BUF rather than installing a
* handle: a session the shim created has no DRM file to hold handles, and the
@@ -120,6 +193,10 @@ const struct qda_legacy_ops qda_legacy_ops_table = {
.session_destroy = legacy_session_destroy,
.init_create = legacy_init_create,
.release = legacy_release,
+ .mmap = legacy_mmap,
+ .mem_map = legacy_mem_map,
+ .munmap = legacy_munmap,
+ .mem_unmap = legacy_mem_unmap,
.alloc_dmabuf = legacy_alloc_dmabuf,
.import_dmabuf = legacy_import_dmabuf,
.invoke = legacy_invoke,
diff --git a/drivers/accel/qda/qda_legacy_ops.h b/drivers/accel/qda/qda_legacy_ops.h
index 05bd1f806c9a..e3126ac10507 100644
--- a/drivers/accel/qda/qda_legacy_ops.h
+++ b/drivers/accel/qda/qda_legacy_ops.h
@@ -35,6 +35,17 @@ struct qda_legacy_ops {
u32 filelen, u32 attrs, u32 siglen);
/** @release: Release the session's DSP process, if it has one */
int (*release)(struct qda_session *session);
+ /** @mmap: Map a buffer into the DSP's address space */
+ int (*mmap)(struct qda_session *session, struct drm_gem_object *obj, u64 vaddrin,
+ u64 size, u32 flags, u64 *vaddrout);
+ /** @mem_map: Map a region of a buffer with explicit SMMU attributes */
+ int (*mem_map)(struct qda_session *session, struct drm_gem_object *obj, u32 flags,
+ u32 attrs, u32 offset, u64 vaddrin, u64 size, s32 dsp_handle,
+ u64 *vaddrout);
+ /** @munmap: Undo a mapping made with @mmap */
+ int (*munmap)(struct qda_session *session, u64 vaddrout, u64 size);
+ /** @mem_unmap: Undo a mapping made with @mem_map */
+ int (*mem_unmap)(struct qda_session *session, s32 dsp_handle, u64 vaddr, u64 size);
/** @alloc_dmabuf: Allocate a buffer and export it as a DMA-BUF */
struct dma_buf *(*alloc_dmabuf)(struct qda_session *session, u64 size);
/** @import_dmabuf: Map a DMA-BUF into a session's context bank */
--
2.34.1
next prev parent reply other threads:[~2026-11-01 22:24 UTC|newest]
Thread overview: 38+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-01 22:21 [PATCH v4 00/25] accel/qda: Qualcomm DSP Accelerator driver Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 01/25] accel/qda: Add QDA driver documentation Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 02/25] accel/qda: Add initial QDA DRM accelerator driver Ekansh Gupta
2026-11-02 8:42 ` Krzysztof Kozlowski
2026-11-01 22:21 ` [PATCH v4 03/25] accel/qda: Add compute context bank devices Ekansh Gupta
2026-11-02 8:43 ` Krzysztof Kozlowski
2026-11-01 22:21 ` [PATCH v4 04/25] accel/qda: Assign a context bank to each session Ekansh Gupta
2026-11-02 8:45 ` Krzysztof Kozlowski
2026-11-01 22:21 ` [PATCH v4 05/25] accel/qda: Add UAPI header and DSP query ioctl Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 06/25] accel/qda: Add buffer allocation for the DSP Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 07/25] accel/qda: Add DMA-BUF import Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 08/25] accel/qda: Add legacy ops base and auxiliary device Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 09/25] accel/qda: Add legacy FastRPC shim skeleton Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 10/25] accel/qda: Add FastRPC invocation contexts Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 11/25] accel/qda: Add RPMsg send and response dispatch Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 12/25] accel/qda: Add invocation argument validation and packing Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 13/25] accel/qda: Add the invocation ioctl and teardown on unplug Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 14/25] accel/qda: Add invocation through the legacy FastRPC shim Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 15/25] accel/qda: Add DSP process creation and release Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 16/25] accel/qda: Add DSP process creation and release to the legacy shim Ekansh Gupta
2026-11-02 8:47 ` Krzysztof Kozlowski
2026-11-01 22:21 ` [PATCH v4 17/25] accel/qda: Add remote memory mapping to the DSP address space Ekansh Gupta
2026-11-02 9:24 ` Konrad Dybcio
2026-11-01 22:21 ` [PATCH v4 18/25] accel/qda: Add remote memory unmapping from " Ekansh Gupta
2026-11-01 22:21 ` Ekansh Gupta [this message]
2026-11-01 22:21 ` [PATCH v4 20/25] accel/qda: Add remote attach to root and sensors protection domains Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 21/25] accel/qda: Add Audio protection domain attach and its remote heap Ekansh Gupta
2026-11-02 8:43 ` Arnd Bergmann
2026-11-02 8:50 ` Krzysztof Kozlowski
2026-11-01 22:21 ` [PATCH v4 22/25] accel/qda: Add remote session attach to the legacy shim Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 23/25] accel/qda: Add DSP capability query Ekansh Gupta
2026-11-02 8:46 ` Arnd Bergmann
2026-11-01 22:21 ` [PATCH v4 24/25] accel/qda: Add legacy shim support for " Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 25/25] accel/qda: Add poll mode for invocation completion Ekansh Gupta
2026-11-02 8:53 ` [PATCH v4 00/25] accel/qda: Qualcomm DSP Accelerator driver Krzysztof Kozlowski
2026-11-02 10:08 ` Ekansh Gupta
2026-11-02 10:12 ` Krzysztof Kozlowski
2026-11-02 10:52 ` Ekansh Gupta
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261102-v4-v4-19-88f2f24a5f0b@qti.qualcomm.com \
--to=ekansh.gupta@oss.qualcomm.com \
--cc=airlied@gmail.com \
--cc=andersson@kernel.org \
--cc=arnd@arndb.de \
--cc=bkumar@qti.qualcomm.com \
--cc=cacar@qti.qualcomm.com \
--cc=chennak@qti.qualcomm.com \
--cc=christian.koenig@amd.com \
--cc=corbet@lwn.net \
--cc=dmitry.baryshkov@oss.qualcomm.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=ekangupt@qti.qualcomm.com \
--cc=gregkh@linuxfoundation.org \
--cc=jgg@ziepe.ca \
--cc=krzk@kernel.org \
--cc=linaro-mm-sig@lists.linaro.org \
--cc=lingtong@qti.qualcomm.com \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=maarten.lankhorst@linux.intel.com \
--cc=mripard@kernel.org \
--cc=ogabbay@kernel.org \
--cc=phasta@kernel.org \
--cc=quic_bkumar@quicinc.com \
--cc=quic_chennak@quicinc.com \
--cc=rdunlap@infradead.org \
--cc=rob.clark@oss.qualcomm.com \
--cc=sandheep@qti.qualcomm.com \
--cc=simona@ffwll.ch \
--cc=skhan@linuxfoundation.org \
--cc=srini@kernel.org \
--cc=sumit.semwal@linaro.org \
--cc=tzimmermann@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®