On 20-05-2026 19:30, Dmitry Baryshkov wrote:
> On Tue, May 19, 2026 at 11:46:03AM +0530, Ekansh Gupta via B4 Relay wrote:
>> From: Ekansh Gupta <[email protected]>
>>
>> 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?
This attaches attributes with the PD that is being created, I'll add
more details>
>>
>> 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 <[email protected]>
>> ---
>> 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?
no specific reason, I'll correct this.>
>> 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);
>> + break;
>> case FASTRPC_RMID_INVOKE_DYNAMIC:
>> err = fastrpc_prepare_args_invoke(ctx, argp);
>> 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?
I had added this check in case the init failed earlier and there is a
retry for the same, but now I see it's not correct and should be handled
in the error path. I'll fix this.>
>> +
>> 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?
INIT_CREATE_ATTR is used while `sc` creation so the DSP considers the
request is coming with some attributes, the ioctl functions are going to
be the same in both the cases, so keeping it unchanged and the decision
is taken while `sc` is getting created.>
>> +}
>> +
>> +/**
>> + * 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
>>
>>
>