[PATCH RFC 17/18] accel/qda: Add FastRPC-based DSP memory unmapping support
From: Ekansh Gupta
Date: Mon Feb 23 2026 - 14:19:18 EST
Add a DRM_QDA_MUNMAP ioctl and corresponding FastRPC plumbing to
unmap previously mapped buffers from the DSP virtual address space.
The new qda_mem_unmap UAPI structure supports both legacy unmap
semantics, where a DSP virtual address is provided directly, and
handle-based MEM_UNMAP semantics using a buffer handle, virtual
address and size.
On the FastRPC side new method identifiers FASTRPC_RMID_INIT_MUNMAP
and FASTRPC_RMID_INIT_MEM_UNMAP are introduced along with request
message structures for legacy and attribute-based unmap operations.
The fastrpc_prepare_args() path gains handlers that copy the
qda_mem_unmap parameters from user space, build the appropriate
unmap request payload and encode a single input buffer in the
scalars so that the existing invoke infrastructure can be reused.
The qda_ioctl_munmap() handler selects the appropriate FastRPC method
based on the qda_mem_unmap request type and forwards the unmap
operation through fastrpc_invoke(), allowing RPMsg to deliver the
request to the DSP. This completes the basic memory management flow
for QDA FastRPC clients by providing explicit unmap operations to
release DSP mappings established via DRM_QDA_MAP.
Signed-off-by: Ekansh Gupta <ekansh.gupta@xxxxxxxxxxxxxxxx>
---
drivers/accel/qda/qda_drv.c | 1 +
drivers/accel/qda/qda_fastrpc.c | 80 +++++++++++++++++++++++++++++++++++++++++
drivers/accel/qda/qda_fastrpc.h | 34 ++++++++++++++++++
drivers/accel/qda/qda_ioctl.c | 22 ++++++++++++
drivers/accel/qda/qda_ioctl.h | 13 +++++++
include/uapi/drm/qda_accel.h | 34 +++++++++++++++++-
6 files changed, 183 insertions(+), 1 deletion(-)
diff --git a/drivers/accel/qda/qda_drv.c b/drivers/accel/qda/qda_drv.c
index 5f43c97ebc25..072a788b0980 100644
--- a/drivers/accel/qda/qda_drv.c
+++ b/drivers/accel/qda/qda_drv.c
@@ -164,6 +164,7 @@ static const struct drm_ioctl_desc qda_ioctls[] = {
DRM_IOCTL_DEF_DRV(QDA_INIT_ATTACH, qda_ioctl_attach, 0),
DRM_IOCTL_DEF_DRV(QDA_INIT_CREATE, qda_ioctl_create, 0),
DRM_IOCTL_DEF_DRV(QDA_MAP, qda_ioctl_mmap, 0),
+ DRM_IOCTL_DEF_DRV(QDA_MUNMAP, qda_ioctl_munmap, 0),
DRM_IOCTL_DEF_DRV(QDA_INVOKE, qda_ioctl_invoke, 0),
};
diff --git a/drivers/accel/qda/qda_fastrpc.c b/drivers/accel/qda/qda_fastrpc.c
index 25b5d53ba2d6..53d505b76aad 100644
--- a/drivers/accel/qda/qda_fastrpc.c
+++ b/drivers/accel/qda/qda_fastrpc.c
@@ -869,6 +869,80 @@ static int fastrpc_prepare_args_mem_map_attr(struct fastrpc_invoke_context *ctx,
return 0;
}
+static int fastrpc_prepare_args_munmap(struct fastrpc_invoke_context *ctx, char __user *argp)
+{
+ struct fastrpc_invoke_args *args;
+ struct fastrpc_munmap_req_msg *req_msg;
+ struct qda_mem_unmap uargs;
+ void *req;
+ int err;
+
+ err = copy_from_user_or_kernel(&uargs, argp, sizeof(uargs));
+ if (err)
+ return err;
+
+ args = kzalloc_obj(*args, GFP_KERNEL);
+ if (!args)
+ return -ENOMEM;
+
+ req = kzalloc_obj(*req_msg, GFP_KERNEL);
+ if (!req) {
+ kfree(args);
+ return -ENOMEM;
+ }
+ req_msg = (struct fastrpc_munmap_req_msg *)req;
+
+ req_msg->client_id = ctx->client_id;
+ req_msg->size = uargs.size;
+ req_msg->vaddr = uargs.vaddrout;
+
+ setup_single_arg(args, req_msg, sizeof(*req_msg));
+ ctx->sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MUNMAP, 1, 0);
+ ctx->args = args;
+ ctx->req = req;
+ ctx->handle = FASTRPC_INIT_HANDLE;
+
+ return 0;
+}
+
+static int fastrpc_prepare_args_mem_unmap_attr(struct fastrpc_invoke_context *ctx,
+ char __user *argp)
+{
+ struct fastrpc_invoke_args *args;
+ struct fastrpc_mem_unmap_req_msg *req_msg;
+ struct qda_mem_unmap uargs;
+ void *req;
+ int err;
+
+ err = copy_from_user_or_kernel(&uargs, argp, sizeof(uargs));
+ if (err)
+ return err;
+
+ args = kzalloc_obj(*args, GFP_KERNEL);
+ if (!args)
+ return -ENOMEM;
+
+ req = kzalloc_obj(*req_msg, GFP_KERNEL);
+ if (!req) {
+ kfree(args);
+ return -ENOMEM;
+ }
+ req_msg = (struct fastrpc_mem_unmap_req_msg *)req;
+
+ req_msg->client_id = ctx->client_id;
+ req_msg->fd = uargs.fd;
+ req_msg->vaddrin = uargs.vaddr;
+ req_msg->len = uargs.size;
+
+ setup_single_arg(args, req_msg, sizeof(*req_msg));
+ ctx->sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MEM_UNMAP, 1, 0);
+ ctx->args = args;
+ ctx->req = req;
+ ctx->handle = FASTRPC_INIT_HANDLE;
+
+ return 0;
+}
+
int fastrpc_prepare_args(struct fastrpc_invoke_context *ctx, char __user *argp)
{
int err;
@@ -895,6 +969,12 @@ int fastrpc_prepare_args(struct fastrpc_invoke_context *ctx, char __user *argp)
case FASTRPC_RMID_INIT_MEM_MAP:
err = fastrpc_prepare_args_mem_map_attr(ctx, argp);
break;
+ case FASTRPC_RMID_INIT_MUNMAP:
+ err = fastrpc_prepare_args_munmap(ctx, argp);
+ break;
+ case FASTRPC_RMID_INIT_MEM_UNMAP:
+ err = fastrpc_prepare_args_mem_unmap_attr(ctx, argp);
+ break;
default:
return -EINVAL;
}
diff --git a/drivers/accel/qda/qda_fastrpc.h b/drivers/accel/qda/qda_fastrpc.h
index b45ccc77d9d1..aa396fdc8e7f 100644
--- a/drivers/accel/qda/qda_fastrpc.h
+++ b/drivers/accel/qda/qda_fastrpc.h
@@ -261,9 +261,11 @@ struct fastrpc_invoke_context {
#define FASTRPC_RMID_INIT_ATTACH 0 /* Attach to DSP session */
#define FASTRPC_RMID_INIT_RELEASE 1 /* Release DSP session */
#define FASTRPC_RMID_INIT_MMAP 4 /* Map memory region to DSP */
+#define FASTRPC_RMID_INIT_MUNMAP 5 /* Unmap DSP memory region */
#define FASTRPC_RMID_INIT_CREATE 6 /* Create DSP process */
#define FASTRPC_RMID_INIT_CREATE_ATTR 7 /* Create DSP process with attributes */
#define FASTRPC_RMID_INIT_MEM_MAP 10 /* Map DMA buffer with attributes to DSP */
+#define FASTRPC_RMID_INIT_MEM_UNMAP 11 /* Unmap DMA buffer from DSP */
#define FASTRPC_RMID_INVOKE_DYNAMIC 0xFFFFFFFF /* Dynamic method invocation */
/* Common handle for initialization operations */
@@ -280,6 +282,38 @@ struct fastrpc_invoke_context {
/* Message structures for internal FastRPC calls */
+/**
+ * struct fastrpc_mem_unmap_req_msg - Memory unmap request message with attributes
+ *
+ * This message structure is sent to the DSP to request unmapping
+ * of a previously mapped memory region (ATTR request).
+ */
+struct fastrpc_mem_unmap_req_msg {
+ /* Client identifier for the session */
+ s32 client_id;
+ /* Handle of the buffer */
+ s32 fd;
+ /* Virtual address to unmap from DSP */
+ u64 vaddrin;
+ /* Size of the region to unmap in bytes */
+ u64 len;
+};
+
+/**
+ * struct fastrpc_munmap_req_msg - Legacy memory unmap request message
+ *
+ * This message structure is sent to the DSP to request unmapping
+ * of a previously mapped memory region.
+ */
+struct fastrpc_munmap_req_msg {
+ /* Client identifier for the session */
+ int client_id;
+ /* Virtual address to unmap from DSP */
+ u64 vaddr;
+ /* Size of the region to unmap in bytes */
+ u64 size;
+};
+
/**
* struct fastrpc_mem_map_req_msg - Memory map request message with attributes
*
diff --git a/drivers/accel/qda/qda_ioctl.c b/drivers/accel/qda/qda_ioctl.c
index 4eb932e2c9ae..a7a8ff283498 100644
--- a/drivers/accel/qda/qda_ioctl.c
+++ b/drivers/accel/qda/qda_ioctl.c
@@ -247,3 +247,25 @@ int qda_ioctl_mmap(struct drm_device *dev, void *data, struct drm_file *file_pri
return -EINVAL;
}
}
+
+int qda_ioctl_munmap(struct drm_device *dev, void *data, struct drm_file *file_priv)
+{
+ struct qda_mem_unmap *unmap_req;
+
+ if (!data)
+ return -EINVAL;
+
+ unmap_req = (struct qda_mem_unmap *)data;
+
+ switch (unmap_req->request) {
+ case QDA_MUNMAP_REQUEST_LEGACY:
+ return fastrpc_invoke(FASTRPC_RMID_INIT_MUNMAP, dev, data, file_priv);
+
+ case QDA_MUNMAP_REQUEST_ATTR:
+ return fastrpc_invoke(FASTRPC_RMID_INIT_MEM_UNMAP, dev, data, file_priv);
+
+ default:
+ qda_err(NULL, "Invalid munmap request type: %u\n", unmap_req->request);
+ return -EINVAL;
+ }
+}
diff --git a/drivers/accel/qda/qda_ioctl.h b/drivers/accel/qda/qda_ioctl.h
index d402d6715b41..759ba3b98394 100644
--- a/drivers/accel/qda/qda_ioctl.h
+++ b/drivers/accel/qda/qda_ioctl.h
@@ -102,4 +102,17 @@ int qda_ioctl_create(struct drm_device *dev, void *data, struct drm_file *file_p
*/
int qda_ioctl_mmap(struct drm_device *dev, void *data, struct drm_file *file_priv);
+/**
+ * qda_ioctl_munmap - Unmap memory from DSP address space
+ * @dev: DRM device structure
+ * @data: User-space data containing memory unmapping parameters
+ * @file_priv: DRM file private data
+ *
+ * This IOCTL handler unmaps a previously mapped buffer from the DSP's
+ * virtual address space, releasing the associated resources.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+int qda_ioctl_munmap(struct drm_device *dev, void *data, struct drm_file *file_priv);
+
#endif /* _QDA_IOCTL_H */
diff --git a/include/uapi/drm/qda_accel.h b/include/uapi/drm/qda_accel.h
index 9151ba7adfaf..53f4a9955a87 100644
--- a/include/uapi/drm/qda_accel.h
+++ b/include/uapi/drm/qda_accel.h
@@ -24,7 +24,7 @@ extern "C" {
#define DRM_QDA_INIT_ATTACH 0x03
#define DRM_QDA_INIT_CREATE 0x04
#define DRM_QDA_MAP 0x05
-/* 0x06 is reserved for other request */
+#define DRM_QDA_MUNMAP 0x06
#define DRM_QDA_INVOKE 0x07
/*
@@ -43,6 +43,8 @@ extern "C" {
#define DRM_IOCTL_QDA_INIT_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_QDA_INIT_CREATE, \
struct qda_init_create)
#define DRM_IOCTL_QDA_MAP DRM_IOWR(DRM_COMMAND_BASE + DRM_QDA_MAP, struct qda_mem_map)
+#define DRM_IOCTL_QDA_MUNMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_QDA_MUNMAP, \
+ struct qda_mem_unmap)
#define DRM_IOCTL_QDA_INVOKE DRM_IOWR(DRM_COMMAND_BASE + DRM_QDA_INVOKE, \
struct qda_invoke_args)
@@ -50,6 +52,9 @@ extern "C" {
#define QDA_MAP_REQUEST_LEGACY 1 /* Legacy MMAP operation */
#define QDA_MAP_REQUEST_ATTR 2 /* Handle-based MEM_MAP operation with attributes */
+/* Request type definitions for qda_mem_unmap */
+#define QDA_MUNMAP_REQUEST_LEGACY 1 /* Legacy MUNMAP operation */
+#define QDA_MUNMAP_REQUEST_ATTR 2 /* Handle-based MEM_UNMAP operation */
/**
* struct drm_qda_query - Device information query structure
* @dsp_name: Name of DSP (e.g., "adsp", "cdsp", "cdsp1", "gdsp0", "gdsp1")
@@ -185,6 +190,33 @@ struct qda_mem_map {
__u64 vaddrout;
};
+/**
+ * struct qda_mem_unmap - Memory unmapping request structure
+ * @request: Request type (QDA_MUNMAP_REQUEST_LEGACY or QDA_MUNMAP_REQUEST_ATTR)
+ * @fd: Handle (used for ATTR request)
+ * @vaddr: Virtual address (used for ATTR request)
+ * @vaddrout: DSP virtual address (used for LEGACY request)
+ * @size: Size of the memory region to unmap in bytes
+ *
+ * This structure is used to request unmapping of a previously mapped
+ * memory region from the DSP's virtual address space.
+ *
+ * For QDA_MUNMAP_REQUEST_LEGACY (value 1):
+ * - Uses fields: vaddrout, size
+ * - Legacy MUNMAP operation for backward compatibility
+ *
+ * For QDA_MUNMAP_REQUEST_ATTR (value 2):
+ * - Uses fields: fd, vaddr, size
+ * - Handle-based MEM_UNMAP operation
+ */
+struct qda_mem_unmap {
+ __u32 request;
+ __s32 fd;
+ __u64 vaddr;
+ __u64 vaddrout;
+ __u64 size;
+};
+
#if defined(__cplusplus)
}
#endif
--
2.34.1