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

Reply via email to