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? > > 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? > 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? > + > 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 > > -- With best wishes Dmitry
