On Tue, May 19, 2026 at 11:46:03AM +0530, Ekansh Gupta via B4 Relay wrote:
From: Ekansh Gupta ekansh.gupta@oss.qualcomm.com
Implement the REMOTE_SESSION_CREATE and INIT_RELEASE FastRPC operations, which establish and tear down a user process on the DSP.
DRM_IOCTL_QDA_REMOTE_SESSION_CREATE (drm_qda_init_create) Creates a new process on the DSP by sending an INIT_CREATE message via the FastRPC INIT_HANDLE. The caller provides an ELF file (via DMA-BUF fd or direct pointer) and optional process attributes. A 4 MB GEM buffer is allocated per session to hold the DSP process image; this buffer is stored in qda_file_priv and reused for the lifetime of the session.
If attrs is non-zero, INIT_CREATE_ATTR is used instead of INIT_CREATE to pass the extended attribute and signature fields.
What is the difference?
INIT_RELEASE Sends a release message to the DSP when the DRM file is closed (qda_postclose via qda_release_dsp_process), freeing the remote process and its resources. The release is skipped if the device has already been unplugged.
qda_fastrpc.c fastrpc_prepare_args_init_create() marshals the six-argument create-process payload: the inbuf descriptor, process name, ELF file, physical pages, attrs, and siglen. fastrpc_prepare_args_release_process() marshals the single- argument release payload (remote_session_id).
qda_drv.c qda_postclose() is extended to call qda_release_dsp_process() under drm_dev_enter() so the release message is only sent while the device is still accessible.
Assisted-by: Claude:claude-4-6-sonnet Signed-off-by: Ekansh Gupta ekansh.gupta@oss.qualcomm.com
drivers/accel/qda/qda_drv.c | 8 +++ drivers/accel/qda/qda_drv.h | 5 ++ drivers/accel/qda/qda_fastrpc.c | 140 ++++++++++++++++++++++++++++++++++++++++ drivers/accel/qda/qda_fastrpc.h | 39 +++++++++-- drivers/accel/qda/qda_ioctl.c | 52 +++++++++++++++ drivers/accel/qda/qda_ioctl.h | 1 + include/uapi/drm/qda_accel.h | 32 ++++++++- 7 files changed, 270 insertions(+), 7 deletions(-)
diff --git a/drivers/accel/qda/qda_drv.c b/drivers/accel/qda/qda_drv.c index 704c7d3127d2..4eaba9b050c0 100644 --- a/drivers/accel/qda/qda_drv.c +++ b/drivers/accel/qda/qda_drv.c @@ -36,6 +36,13 @@ static int qda_open(struct drm_device *dev, struct drm_file *file) static void qda_postclose(struct drm_device *dev, struct drm_file *file) { struct qda_file_priv *qda_file_priv = file->driver_priv;
- int idx;
- /* Only send the DSP release message while the device is accessible */
- if (drm_dev_enter(dev, &idx)) {
qda_release_dsp_process(qda_file_priv->qda_dev, file);drm_dev_exit(idx);- }
if (qda_file_priv->assigned_iommu_dev) { struct qda_iommu_device *iommu_dev = qda_file_priv->assigned_iommu_dev; @@ -59,6 +66,7 @@ static const struct drm_ioctl_desc qda_ioctls[] = { DRM_IOCTL_DEF_DRV(QDA_QUERY, qda_ioctl_query, 0), DRM_IOCTL_DEF_DRV(QDA_GEM_CREATE, qda_ioctl_gem_create, 0), DRM_IOCTL_DEF_DRV(QDA_GEM_MMAP_OFFSET, qda_ioctl_gem_mmap_offset, 0),
- DRM_IOCTL_DEF_DRV(QDA_REMOTE_SESSION_CREATE, qda_ioctl_init_create, 0),
Why is it being added in the middle?
DRM_IOCTL_DEF_DRV(QDA_REMOTE_INVOKE, qda_ioctl_invoke, 0), }; diff --git a/drivers/accel/qda/qda_drv.h b/drivers/accel/qda/qda_drv.h index 420cccff42bf..4b4639961d95 100644 --- a/drivers/accel/qda/qda_drv.h +++ b/drivers/accel/qda/qda_drv.h @@ -28,6 +28,8 @@ struct qda_file_priv { struct qda_dev *qda_dev; /** @assigned_iommu_dev: IOMMU device assigned to this process */ struct qda_iommu_device *assigned_iommu_dev;
- /** @init_mem_gem_obj: GEM object for PD initialization memory */
- struct qda_gem_obj *init_mem_gem_obj; /** @pid: Process ID for tracking */ pid_t pid; /** @remote_session_id: Unique session identifier */
@@ -83,4 +85,7 @@ void qda_deinit_device(struct qda_dev *qdev); int qda_register_device(struct qda_dev *qdev); void qda_unregister_device(struct qda_dev *qdev); +/* DSP process / protection domain management */ +int qda_release_dsp_process(struct qda_dev *qdev, struct drm_file *file_priv);
#endif /* __QDA_DRV_H__ */ diff --git a/drivers/accel/qda/qda_fastrpc.c b/drivers/accel/qda/qda_fastrpc.c index 0ec37175a098..305915022b91 100644 --- a/drivers/accel/qda/qda_fastrpc.c +++ b/drivers/accel/qda/qda_fastrpc.c @@ -524,6 +524,138 @@ int qda_fastrpc_invoke_unpack(struct fastrpc_invoke_context *ctx, return err; } +static void setup_create_process_args(struct drm_qda_fastrpc_invoke_args *args,
struct fastrpc_create_process_inbuf *inbuf,struct drm_qda_init_create *init,struct fastrpc_phy_page *pages)+{
- args[0].ptr = (u64)(uintptr_t)inbuf;
- args[0].length = sizeof(*inbuf);
- args[0].fd = -1;
- args[1].ptr = (u64)(uintptr_t)current->comm;
- args[1].length = inbuf->namelen;
- args[1].fd = -1;
- args[2].ptr = (u64)init->file;
- args[2].length = inbuf->filelen;
- args[2].fd = init->filefd; /* DMA-BUF fd forwarded to DSP */
- args[3].ptr = (u64)(uintptr_t)pages;
- args[3].length = 1 * sizeof(*pages);
- args[3].fd = -1;
- args[4].ptr = (u64)(uintptr_t)&inbuf->attrs;
- args[4].length = sizeof(inbuf->attrs);
- args[4].fd = -1;
- args[5].ptr = (u64)(uintptr_t)&inbuf->siglen;
- args[5].length = sizeof(inbuf->siglen);
- args[5].fd = -1;
+}
+static void setup_single_arg(struct drm_qda_fastrpc_invoke_args *args, const void *ptr, size_t size) +{
- args[0].ptr = (u64)(uintptr_t)ptr;
- args[0].length = size;
- args[0].fd = -1;
+}
+static int fastrpc_prepare_args_release_process(struct fastrpc_invoke_context *ctx) +{
- struct drm_qda_fastrpc_invoke_args *args;
- args = kzalloc_obj(*args);
- if (!args)
return -ENOMEM;- setup_single_arg(args, &ctx->remote_session_id, sizeof(ctx->remote_session_id));
- ctx->sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_RELEASE, 1, 0);
- ctx->args = args;
- ctx->handle = FASTRPC_INIT_HANDLE;
- return 0;
+}
+static int fastrpc_prepare_args_init_create(struct fastrpc_invoke_context *ctx,
char __user *argp)+{
- struct drm_qda_init_create init;
- struct drm_qda_fastrpc_invoke_args *args;
- struct fastrpc_create_process_inbuf *inbuf;
- int err;
- u32 sc;
- args = kcalloc(FASTRPC_CREATE_PROCESS_NARGS, sizeof(*args), GFP_KERNEL);
- if (!args)
return -ENOMEM;- ctx->input_pages = kcalloc(1, sizeof(*ctx->input_pages), GFP_KERNEL);
- if (!ctx->input_pages) {
err = -ENOMEM;goto err_free_args;- }
- ctx->inbuf = kcalloc(1, sizeof(*inbuf), GFP_KERNEL);
- if (!ctx->inbuf) {
err = -ENOMEM;goto err_free_input_pages;- }
- inbuf = ctx->inbuf;
- memcpy(&init, argp, sizeof(init));
- if (init.filelen > FASTRPC_INIT_FILELEN_MAX) {
err = -EINVAL;goto err_free_inbuf;- }
- /*
* Validate that the DMA-BUF fd is importable. The fd itself is kept* in init.filefd and forwarded to the DSP via setup_create_process_args().*/- if (init.filelen && init.filefd > 0) {
struct drm_gem_object *file_gem_obj;err = get_gem_obj_from_dmabuf_fd(ctx, init.filefd, &file_gem_obj);if (err) {err = -EINVAL;goto err_free_inbuf;}drm_gem_object_put(file_gem_obj);- }
- inbuf->remote_session_id = ctx->remote_session_id;
- inbuf->namelen = strlen(current->comm) + 1;
- inbuf->filelen = init.filelen;
- inbuf->pageslen = 1;
- inbuf->attrs = init.attrs;
- inbuf->siglen = init.siglen;
- setup_pages_from_gem_obj(ctx->init_mem_gem_obj, &ctx->input_pages[0]);
- setup_create_process_args(args, inbuf, &init, ctx->input_pages);
- sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE, 4, 0);
- if (init.attrs)
sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_CREATE_ATTR, 4, 0);- ctx->sc = sc;
- ctx->args = args;
- ctx->handle = FASTRPC_INIT_HANDLE;
- return 0;
+err_free_inbuf:
- kfree(ctx->inbuf);
- ctx->inbuf = NULL;
+err_free_input_pages:
- kfree(ctx->input_pages);
- ctx->input_pages = NULL;
+err_free_args:
- kfree(args);
- return err;
+}
static int fastrpc_prepare_args_invoke(struct fastrpc_invoke_context *ctx, char __user *argp) { struct drm_qda_invoke_args invoke_args; @@ -568,6 +700,14 @@ int qda_fastrpc_prepare_args(struct fastrpc_invoke_context *ctx, char __user *ar int err; switch (ctx->type) {
- case FASTRPC_RMID_INIT_RELEASE:
err = fastrpc_prepare_args_release_process(ctx);break;- case FASTRPC_RMID_INIT_CREATE:
- case FASTRPC_RMID_INIT_CREATE_ATTR:
ctx->pd = QDA_USER_PD;err = fastrpc_prepare_args_init_create(ctx, argp); case FASTRPC_RMID_INVOKE_DYNAMIC: err = fastrpc_prepare_args_invoke(ctx, argp); break;break;diff --git a/drivers/accel/qda/qda_fastrpc.h b/drivers/accel/qda/qda_fastrpc.h index ce77baeccfba..1c1236f9525e 100644 --- a/drivers/accel/qda/qda_fastrpc.h +++ b/drivers/accel/qda/qda_fastrpc.h @@ -127,6 +127,27 @@ struct fastrpc_invoke_buf { u32 pgidx; }; +/**
- struct fastrpc_create_process_inbuf - Input buffer for process creation
- This structure defines the input buffer format for creating a new
- process on the remote DSP.
- */
+struct fastrpc_create_process_inbuf {
- /** @remote_session_id: Client identifier for the session */
- int remote_session_id;
- /** @namelen: Length of the process name string including NUL terminator */
- u32 namelen;
- /** @filelen: Length of the ELF shell file in bytes */
- u32 filelen;
- /** @pageslen: Number of physical page descriptors */
- u32 pageslen;
- /** @attrs: Process attribute flags */
- u32 attrs;
- /** @siglen: Length of the signature data in bytes */
- u32 siglen;
+};
/**
- struct fastrpc_msg - FastRPC wire message for remote invocations
@@ -153,10 +174,6 @@ struct fastrpc_msg { /**
- struct qda_msg - FastRPC message with kernel-internal bookkeeping
- The wire-format portion is kept in the embedded @fastrpc member (must
- be first) so that &qda_msg->fastrpc can be passed directly to
*/
- rpmsg_send() without a copy.
struct qda_msg { /** @@ -245,7 +262,7 @@ struct fastrpc_invoke_context { struct qda_gem_obj *msg_gem_obj; /** @file_priv: DRM file private data */ struct drm_file *file_priv;
- /** @init_mem_gem_obj: GEM object for protection domain init memory */
- /** @init_mem_gem_obj: GEM object for PD initialization memory */ struct qda_gem_obj *init_mem_gem_obj; /** @req: Pointer to kernel-internal request buffer */ void *req;
@@ -256,11 +273,23 @@ struct fastrpc_invoke_context { }; /* Remote Method ID table - identifies initialization and control operations */ +#define FASTRPC_RMID_INIT_RELEASE 1 /* Release DSP process */ +#define FASTRPC_RMID_INIT_CREATE 6 /* Create DSP process */ +#define FASTRPC_RMID_INIT_CREATE_ATTR 7 /* Create DSP process with attributes */ #define FASTRPC_RMID_INVOKE_DYNAMIC 0xFFFFFFFF /* Dynamic method invocation */ /* Common handle for initialization operations */ #define FASTRPC_INIT_HANDLE 0x1 +/* Protection Domain (PD) identifiers */ +#define QDA_ROOT_PD (0) +#define QDA_USER_PD (1)
+/* Number of arguments for process creation */ +#define FASTRPC_CREATE_PROCESS_NARGS 6 +/* Maximum initialization file size (4 MB) */ +#define FASTRPC_INIT_FILELEN_MAX (4 * 1024 * 1024)
void qda_fastrpc_context_free(struct kref *ref); struct fastrpc_invoke_context *qda_fastrpc_context_alloc(void); int qda_fastrpc_prepare_args(struct fastrpc_invoke_context *ctx, char __user *argp); diff --git a/drivers/accel/qda/qda_ioctl.c b/drivers/accel/qda/qda_ioctl.c index c81268c20b04..33f0a798ad13 100644 --- a/drivers/accel/qda/qda_ioctl.c +++ b/drivers/accel/qda/qda_ioctl.c @@ -109,6 +109,7 @@ static int fastrpc_invoke(int type, struct drm_device *dev, void *data, struct drm_gem_object *gem_obj; int err; size_t hdr_size;
- size_t initmem_size = FASTRPC_INIT_FILELEN_MAX;
ctx = qda_fastrpc_context_alloc(); if (IS_ERR(ctx)) @@ -124,6 +125,27 @@ static int fastrpc_invoke(int type, struct drm_device *dev, void *data, ctx->file_priv = file_priv; ctx->remote_session_id = qda_file_priv->remote_session_id;
- if (type == FASTRPC_RMID_INIT_CREATE) {
struct drm_gem_object *initmem_gem_obj;if (qda_file_priv->init_mem_gem_obj) {
Why is it non-NULL here?
drm_gem_object_put(&qda_file_priv->init_mem_gem_obj->base);qda_file_priv->init_mem_gem_obj = NULL;}initmem_gem_obj = qda_gem_create_object(dev, qdev->iommu_mgr,initmem_size, file_priv);if (IS_ERR(initmem_gem_obj)) {err = PTR_ERR(initmem_gem_obj);goto err_context_free;}ctx->init_mem_gem_obj = to_qda_gem_obj(initmem_gem_obj);qda_file_priv->init_mem_gem_obj = ctx->init_mem_gem_obj;- } else if (type == FASTRPC_RMID_INIT_RELEASE) {
ctx->init_mem_gem_obj = qda_file_priv->init_mem_gem_obj;- }
- err = qda_fastrpc_prepare_args(ctx, (char __user *)data); if (err) goto err_context_free;
@@ -161,11 +183,41 @@ static int fastrpc_invoke(int type, struct drm_device *dev, void *data, return 0; err_context_free:
- if (type == FASTRPC_RMID_INIT_RELEASE && !err && qda_file_priv->init_mem_gem_obj) {
drm_gem_object_put(&qda_file_priv->init_mem_gem_obj->base);qda_file_priv->init_mem_gem_obj = NULL;- }
- fastrpc_context_put_id(ctx, qdev); kref_put(&ctx->refcount, qda_fastrpc_context_free); return err;
} +/**
- qda_ioctl_init_create() - Create a DSP process
- @dev: DRM device structure
- @data: User-space data (struct drm_qda_init_create)
- @file_priv: DRM file private data
- Return: 0 on success, negative error code on failure
- */
+int qda_ioctl_init_create(struct drm_device *dev, void *data, struct drm_file *file_priv) +{
- return fastrpc_invoke(FASTRPC_RMID_INIT_CREATE, dev, data, file_priv);
Where is INIT_CREATE_ATTR, which you described earlier?
+}
+/**
- qda_release_dsp_process() - Release DSP process resources for a file
- @qdev: QDA device structure
- @file_priv: DRM file private data
- Return: 0 on success, negative error code on failure
- */
+int qda_release_dsp_process(struct qda_dev *qdev, struct drm_file *file_priv) +{
- return fastrpc_invoke(FASTRPC_RMID_INIT_RELEASE, &qdev->drm_dev, NULL, file_priv);
+}
/**
- qda_ioctl_invoke() - Perform a dynamic FastRPC method invocation
- @dev: DRM device structure
diff --git a/drivers/accel/qda/qda_ioctl.h b/drivers/accel/qda/qda_ioctl.h index 3bb9cfd98370..192565434363 100644 --- a/drivers/accel/qda/qda_ioctl.h +++ b/drivers/accel/qda/qda_ioctl.h @@ -9,6 +9,7 @@ #include "qda_drv.h" int qda_ioctl_query(struct drm_device *dev, void *data, struct drm_file *file_priv); +int qda_ioctl_init_create(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); int qda_ioctl_gem_mmap_offset(struct drm_device *dev, void *data, struct drm_file *file_priv); int qda_ioctl_invoke(struct drm_device *dev, void *data, struct drm_file *file_priv); diff --git a/include/uapi/drm/qda_accel.h b/include/uapi/drm/qda_accel.h index 72512213741f..711e2523a570 100644 --- a/include/uapi/drm/qda_accel.h +++ b/include/uapi/drm/qda_accel.h @@ -21,8 +21,9 @@ extern "C" { #define DRM_QDA_QUERY 0x00 #define DRM_QDA_GEM_CREATE 0x01 #define DRM_QDA_GEM_MMAP_OFFSET 0x02 -/* Command numbers 0x03-0x06 reserved for INIT_ATTACH, INIT_CREATE, MAP, MUNMAP */ -#define DRM_QDA_REMOTE_INVOKE 0x07 +/* Command number 0x03 reserved for INIT_ATTACH; 0x05-0x06 reserved for MAP, MUNMAP */ +#define DRM_QDA_REMOTE_SESSION_CREATE 0x04 +#define DRM_QDA_REMOTE_INVOKE 0x07 /*
- QDA IOCTL definitions
@@ -37,6 +38,9 @@ extern "C" { struct drm_qda_gem_create) #define DRM_IOCTL_QDA_GEM_MMAP_OFFSET DRM_IOWR(DRM_COMMAND_BASE + DRM_QDA_GEM_MMAP_OFFSET, \ struct drm_qda_gem_mmap_offset) +#define DRM_IOCTL_QDA_REMOTE_SESSION_CREATE \
- DRM_IOWR(DRM_COMMAND_BASE + DRM_QDA_REMOTE_SESSION_CREATE, \
struct drm_qda_init_create)#define DRM_IOCTL_QDA_REMOTE_INVOKE DRM_IOWR(DRM_COMMAND_BASE + DRM_QDA_REMOTE_INVOKE, \ struct drm_qda_invoke_args) @@ -99,6 +103,30 @@ struct drm_qda_fastrpc_invoke_args { __u32 attr; }; +/**
- struct drm_qda_init_create - Accelerator process initialization parameters
- @filelen: Length of the ELF file in bytes
- @filefd: DMA-BUF file descriptor containing the ELF file
- @attrs: Process attributes flags
- @siglen: Length of signature data in bytes
- @file: Pointer to ELF file data if not using filefd
- This structure is used with DRM_IOCTL_QDA_INIT_CREATE to initialize
- a new process on the accelerator. The process code is provided either
- via a file descriptor (filefd, typically a GEM object) or a direct
- pointer (file). Set file to 0 if using filefd.
- The attrs field contains bit flags for debug mode, privileged execution,
- and other process attributes.
- */
+struct drm_qda_init_create {
- __u32 filelen;
- __s32 filefd;
- __u32 attrs;
- __u32 siglen;
- __u64 file;
+};
/**
- struct drm_qda_invoke_args - Dynamic FastRPC invocation parameters
- @handle: Remote handle to invoke on the DSP
-- 2.34.1