From: Ekansh Gupta <ekansh.gupta@oss.qualcomm.com>
To: "Oded Gabbay" <ogabbay@kernel.org>,
"Jonathan Corbet" <corbet@lwn.net>,
"Shuah Khan" <skhan@linuxfoundation.org>,
"Randy Dunlap" <rdunlap@infradead.org>,
"Ekansh Gupta" <ekansh.gupta@oss.qualcomm.com>,
"Srinivas Kandagatla" <srini@kernel.org>,
"Arnd Bergmann" <arnd@arndb.de>,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
"David Airlie" <airlied@gmail.com>,
"Simona Vetter" <simona@ffwll.ch>,
"Maarten Lankhorst" <maarten.lankhorst@linux.intel.com>,
"Maxime Ripard" <mripard@kernel.org>,
"Thomas Zimmermann" <tzimmermann@suse.de>,
"Sumit Semwal" <sumit.semwal@linaro.org>,
"Christian König" <christian.koenig@amd.com>,
"Philipp Stanner" <phasta@kernel.org>,
dmitry.baryshkov@oss.qualcomm.com, andersson@kernel.org,
krzk@kernel.org, rob.clark@oss.qualcomm.com, jgg@ziepe.ca
Cc: lingtong@qti.qualcomm.com, cacar@qti.qualcomm.com,
sandheep@qti.qualcomm.com,
Bharath Kumar <bkumar@qti.qualcomm.com>,
Chenna Kesava Raju <chennak@qti.qualcomm.com>,
dri-devel@lists.freedesktop.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org,
Bharath Kumar <quic_bkumar@quicinc.com>,
Chenna Kesava Raju <quic_chennak@quicinc.com>,
Ekansh Gupta <ekangupt@qti.qualcomm.com>
Subject: [PATCH v4 15/25] accel/qda: Add DSP process creation and release
Date: Mon, 02 Nov 2026 03:51:28 +0530 [thread overview]
Message-ID: <20261102-v4-v4-15-88f2f24a5f0b@qti.qualcomm.com> (raw)
In-Reply-To: <20261102-v4-v4-0-88f2f24a5f0b@qti.qualcomm.com>
An application needs a process on the DSP to run its own code, and
that process has to be torn down when the application goes away. Add
the requests that create and release one, and the ioctl that creates
it.
Creating a process hands the DSP an ELF image, which the caller names
by buffer handle, together with a block of memory the DSP loads the
image into. That memory is allocated per session and kept until the
process is released, since the DSP uses it for as long as the process
runs. A process created again on the same session replaces the first,
so the memory held for the previous one is dropped first.
A signed process runs with the DSP's trust in the signature, so
creating one requires CAP_SYS_ADMIN; only an unsigned process may be
created without it.
Releasing is sent when a session closes, if the device is still there
to receive it. Once the DSP has torn the process down, the memory held
for it is freed.
Every request after a successful create is directed at the new
protection domain, so the session remembers which one it is in and the
message built for a request carries it. Requests addressed to the
initialisation handle carry session ID 0, since the session has no
process yet to identify.
Signed-off-by: Ekansh Gupta <ekansh.gupta@oss.qualcomm.com>
---
drivers/accel/qda/qda_drv.c | 16 +++-
drivers/accel/qda/qda_drv.h | 11 +++
drivers/accel/qda/qda_fastrpc.c | 202 ++++++++++++++++++++++++++++++++++++++--
drivers/accel/qda/qda_fastrpc.h | 48 +++++++++-
drivers/accel/qda/qda_ioctl.c | 59 +++++++++++-
drivers/accel/qda/qda_ioctl.h | 1 +
include/uapi/drm/qda_accel.h | 28 ++++++
7 files changed, 354 insertions(+), 11 deletions(-)
diff --git a/drivers/accel/qda/qda_drv.c b/drivers/accel/qda/qda_drv.c
index 7d44342d3f67..983c6a3dcfb4 100644
--- a/drivers/accel/qda/qda_drv.c
+++ b/drivers/accel/qda/qda_drv.c
@@ -13,6 +13,7 @@
#include "qda_drv.h"
#include "qda_fastrpc.h"
+#include "qda_gem.h"
#include "qda_ioctl.h"
#include "qda_prime.h"
@@ -72,6 +73,9 @@ static void qda_session_release(struct kref *ref)
qda_session_msg_buf_pool_destroy(session);
+ if (session->init_mem_gem_obj)
+ drm_gem_object_put(&session->init_mem_gem_obj->base);
+
if (session->assigned_iommu_dev)
qda_memory_manager_release_device(session->assigned_iommu_dev);
@@ -101,7 +105,16 @@ EXPORT_SYMBOL_FOR_MODULES(qda_session_put, "qda_fastrpc_shim");
static void qda_postclose(struct drm_device *dev, struct drm_file *file)
{
- qda_session_put(file->driver_priv);
+ struct qda_session *session = file->driver_priv;
+ int idx;
+
+ /* Only a session that created a process has one to release */
+ if (READ_ONCE(session->init_mem_gem_obj) && drm_dev_enter(dev, &idx)) {
+ qda_release_dsp_process(session->qda_dev, session);
+ drm_dev_exit(idx);
+ }
+
+ qda_session_put(session);
}
DEFINE_DRM_ACCEL_FOPS(qda_accel_fops);
@@ -111,6 +124,7 @@ static const struct drm_ioctl_desc qda_ioctls[] = {
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_INVOKE, qda_ioctl_invoke, 0),
+ DRM_IOCTL_DEF_DRV(QDA_REMOTE_SESSION_CREATE, qda_ioctl_init_create, 0),
};
static const struct drm_driver qda_drm_driver = {
diff --git a/drivers/accel/qda/qda_drv.h b/drivers/accel/qda/qda_drv.h
index 80a8569b311a..2f98fd83fdda 100644
--- a/drivers/accel/qda/qda_drv.h
+++ b/drivers/accel/qda/qda_drv.h
@@ -56,6 +56,14 @@ struct qda_session {
struct qda_iommu_device *assigned_iommu_dev;
/** @remote_session_id: Identifies this session to the DSP */
int remote_session_id;
+ /** @pd: Protection domain this session's requests are directed at */
+ int pd;
+ /**
+ * @init_mem_gem_obj: Memory the DSP loaded this session's process
+ * into, held for as long as the process runs. Swapped with xchg(), as
+ * ioctls on one file can run concurrently.
+ */
+ struct qda_gem_obj *init_mem_gem_obj;
/**
* @msg_buf_pool: Invoke header buffers this session is done with,
* kept for its later invocations to reuse.
@@ -137,4 +145,7 @@ struct qda_session *qda_session_alloc(struct qda_dev *qdev);
void qda_session_get(struct qda_session *session);
void qda_session_put(struct qda_session *session);
+/* DSP process management */
+int qda_release_dsp_process(struct qda_dev *qdev, struct qda_session *session);
+
#endif /* __QDA_DRV_H__ */
diff --git a/drivers/accel/qda/qda_fastrpc.c b/drivers/accel/qda/qda_fastrpc.c
index 693dd6f035d2..4672405ea4b7 100644
--- a/drivers/accel/qda/qda_fastrpc.c
+++ b/drivers/accel/qda/qda_fastrpc.c
@@ -1,9 +1,12 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
#include <linux/bitfield.h>
+#include <linux/capability.h>
#include <linux/dma-mapping.h>
#include <linux/mm.h>
+#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/string.h>
#include <linux/uaccess.h>
#include <drm/drm_gem.h>
#include <drm/drm_print.h>
@@ -245,6 +248,9 @@ void qda_fastrpc_context_free(struct kref *ref)
if (ctx->msg_gem_obj)
qda_session_msg_buf_put(ctx->session, &ctx->msg_gem_obj->base);
+ if (ctx->init_mem_gem_obj)
+ drm_gem_object_put(&ctx->init_mem_gem_obj->base);
+
if (ctx->session)
qda_session_put(ctx->session);
@@ -301,10 +307,54 @@ struct qda_fastrpc_invoke_ctx *qda_fastrpc_context_alloc(struct qda_dev *qdev)
return ctx;
}
+/*
+ * Allocate one DMA-coherent object to hold every buffer the driver builds for
+ * one of its own requests, so they cost a single page rather than one each.
+ * The memory is cleared, so output slots start out clean.
+ */
+static struct qda_gem_obj *alloc_kernel_gem(struct qda_fastrpc_invoke_ctx *ctx, size_t size)
+{
+ struct qda_dev *qdev = ctx->qdev;
+ struct drm_gem_object *gem_obj;
+
+ gem_obj = qda_gem_create_object(&qdev->drm_dev, qdev->iommu_mgr, size, ctx->session);
+ if (IS_ERR(gem_obj))
+ return ERR_CAST(gem_obj);
+
+ memset(to_qda_gem_obj(gem_obj)->virt, 0, to_qda_gem_obj(gem_obj)->size);
+
+ return to_qda_gem_obj(gem_obj);
+}
+
+/* The context releases whatever has been allocated here if a later step fails */
+static int alloc_kernel_args(struct qda_fastrpc_invoke_ctx *ctx, u32 nargs)
+{
+ ctx->args = kzalloc_objs(*ctx->args, nargs);
+ if (!ctx->args)
+ return -ENOMEM;
+
+ ctx->gem_objs = kzalloc_objs(*ctx->gem_objs, nargs);
+ if (!ctx->gem_objs)
+ return -ENOMEM;
+
+ return 0;
+}
+
+/* Describe the region at @ptr in @kernel_gem as argument @idx, taking a reference on it */
+static void assign_kernel_gem_arg(struct qda_fastrpc_invoke_ctx *ctx, int idx,
+ struct qda_gem_obj *kernel_gem, void *ptr, size_t len)
+{
+ ctx->args[idx].offset = (u8 *)ptr - (u8 *)kernel_gem->virt;
+ ctx->args[idx].length = len;
+ drm_gem_object_get(&kernel_gem->base);
+ ctx->gem_objs[idx] = &kernel_gem->base;
+}
+
/*
* Resolve the address of an in/out buffer argument. The buffer is either a
- * GEM object the legacy shim already resolved into ctx->gem_objs[i], or a GEM
- * handle looked up in the calling session's own handle table. For a handle,
+ * GEM object already resolved into ctx->gem_objs[i], by the legacy shim or by
+ * the driver for its own requests, or a GEM handle looked up in the calling
+ * session's own handle table. For a handle,
* the offset and length come from user space and are checked against the
* buffer's real size: a region described as larger than its buffer would let
* the DSP read and write past the end of it, into whatever else is mapped in
@@ -321,7 +371,7 @@ static int process_msg_buffer(struct qda_fastrpc_invoke_ctx *ctx, int i,
u64 vma_offset = 0;
int err;
- if (ctx->gem_objs[i]) {
+ if (ctx->gem_objs[i] && ctx->legacy) {
/*
* The legacy ABI predates GEM handles, so the offset field
* holds an address in the caller's own mapping of the buffer,
@@ -341,6 +391,17 @@ static int process_msg_buffer(struct qda_fastrpc_invoke_ctx *ctx, int i,
return 0;
}
+ if (ctx->gem_objs[i]) {
+ /* Built by the driver, so the offset is a byte offset into the buffer */
+ qda_gem_obj = to_qda_gem_obj(ctx->gem_objs[i]);
+ unaligned_addr = qda_gem_obj->dma_addr + ctx->args[i].offset;
+ rpra[i].buf.addr = unaligned_addr;
+ pages[i].addr = unaligned_addr & PAGE_MASK;
+ pages[i].size = calculate_page_aligned_size(unaligned_addr, len);
+
+ return 0;
+ }
+
if (!ctx->args[i].handle)
return -EINVAL;
@@ -511,9 +572,14 @@ int qda_fastrpc_invoke_pack(struct qda_fastrpc_invoke_ctx *ctx, struct qda_msg *
/* Ensure the payload is visible to the DSP before the doorbell */
dma_wmb();
- msg->fastrpc.remote_session_id = ctx->session->remote_session_id;
+ /* The session has no process yet to identify while one is being created */
+ if (ctx->handle == QDA_FASTRPC_INIT_HANDLE)
+ msg->fastrpc.remote_session_id = 0;
+ else
+ msg->fastrpc.remote_session_id = ctx->session->remote_session_id;
+
msg->fastrpc.tid = current->pid;
- msg->fastrpc.ctx = ctx->ctxid | QDA_USER_PD;
+ msg->fastrpc.ctx = ctx->ctxid | ctx->pd;
msg->fastrpc.handle = ctx->handle;
msg->fastrpc.sc = ctx->sc;
msg->fastrpc.addr = msg->phys;
@@ -639,6 +705,9 @@ int qda_fastrpc_invoke_legacy(struct qda_dev *qdev, struct qda_session *session,
/* Dropped by qda_fastrpc_context_free(), as for the accel UAPI path */
qda_session_get(session);
ctx->session = session;
+ ctx->type = QDA_FASTRPC_RMID_INVOKE_DYNAMIC;
+ ctx->legacy = true;
+ ctx->pd = READ_ONCE(session->pd);
ctx->handle = handle;
ctx->sc = sc;
@@ -688,6 +757,110 @@ int qda_fastrpc_invoke_legacy(struct qda_dev *qdev, struct qda_session *session,
return err;
}
+/*
+ * INIT_RELEASE packed layout:
+ * [0] remote_session_id sizeof(int) IN
+ */
+static int qda_fastrpc_prepare_args_release_process(struct qda_fastrpc_invoke_ctx *ctx)
+{
+ struct qda_gem_obj *kernel_gem;
+ int err;
+
+ ctx->sc = QDA_FASTRPC_SCALARS(QDA_FASTRPC_RMID_INIT_RELEASE, 1, 0);
+ ctx->handle = QDA_FASTRPC_INIT_HANDLE;
+
+ err = alloc_kernel_args(ctx, 1);
+ if (err)
+ return err;
+
+ kernel_gem = alloc_kernel_gem(ctx, sizeof(int));
+ if (IS_ERR(kernel_gem))
+ return PTR_ERR(kernel_gem);
+
+ *(int *)kernel_gem->virt = ctx->session->remote_session_id;
+ assign_kernel_gem_arg(ctx, 0, kernel_gem, kernel_gem->virt, sizeof(int));
+ drm_gem_object_put(&kernel_gem->base);
+
+ return 0;
+}
+
+/*
+ * INIT_CREATE / INIT_CREATE_ATTR packed layout:
+ * [0] inbuf sizeof(qda_fastrpc_create_process_inbuf) IN
+ * [1] comm TASK_COMM_LEN IN
+ * [2] ELF buffer named by the caller's handle, not packed IN
+ * [3] pages sizeof(qda_phy_page), the process image memory IN
+ *
+ * The attributes and signature length travel in @inbuf. The _ATTR method is
+ * used when any attribute is set, as in drivers/misc/fastrpc.c.
+ */
+static int qda_fastrpc_prepare_args_init_create(struct qda_fastrpc_invoke_ctx *ctx, void *argp)
+{
+ struct drm_qda_init_create *init = argp;
+ struct qda_fastrpc_create_process_inbuf *inbuf;
+ struct qda_dev *qdev = ctx->qdev;
+ struct drm_gem_object *gem_obj;
+ struct qda_gem_obj *kernel_gem;
+ u8 *gv;
+ int err;
+
+ const size_t off_inbuf = 0;
+ const size_t off_comm = off_inbuf + sizeof(*inbuf);
+ const size_t off_pages = off_comm + TASK_COMM_LEN;
+ const size_t total_size = off_pages + sizeof(struct qda_phy_page);
+
+ if (init->file || init->filelen > QDA_FASTRPC_INIT_FILELEN_MAX)
+ return -EINVAL;
+
+ /* A signed process runs with the DSP's trust in the signature */
+ if (!(init->attrs & QDA_INIT_ATTR_UNSIGNED_MODULE) && !capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ /* The DSP loads the image into this memory and keeps using it while the process runs */
+ gem_obj = qda_gem_create_object(&qdev->drm_dev, qdev->iommu_mgr,
+ QDA_FASTRPC_INIT_FILELEN_MAX, ctx->session);
+ if (IS_ERR(gem_obj))
+ return PTR_ERR(gem_obj);
+
+ ctx->init_mem_gem_obj = to_qda_gem_obj(gem_obj);
+
+ ctx->sc = init->attrs ? QDA_FASTRPC_SCALARS(QDA_FASTRPC_RMID_INIT_CREATE_ATTR, 4, 0)
+ : QDA_FASTRPC_SCALARS(QDA_FASTRPC_RMID_INIT_CREATE, 4, 0);
+ ctx->handle = QDA_FASTRPC_INIT_HANDLE;
+
+ err = alloc_kernel_args(ctx, 4);
+ if (err)
+ return err;
+
+ kernel_gem = alloc_kernel_gem(ctx, total_size);
+ if (IS_ERR(kernel_gem))
+ return PTR_ERR(kernel_gem);
+ gv = kernel_gem->virt;
+
+ inbuf = (struct qda_fastrpc_create_process_inbuf *)(gv + off_inbuf);
+ inbuf->remote_session_id = ctx->session->remote_session_id;
+ inbuf->filelen = init->filelen;
+ inbuf->pageslen = 1;
+ inbuf->attrs = init->attrs;
+ inbuf->siglen = init->siglen;
+
+ strscpy(gv + off_comm, current->comm, TASK_COMM_LEN);
+ inbuf->namelen = strlen(gv + off_comm) + 1;
+
+ setup_pages_from_gem_obj(ctx->init_mem_gem_obj, (struct qda_phy_page *)(gv + off_pages));
+
+ assign_kernel_gem_arg(ctx, 0, kernel_gem, inbuf, sizeof(*inbuf));
+ assign_kernel_gem_arg(ctx, 1, kernel_gem, gv + off_comm, inbuf->namelen);
+ /* The image starts at the beginning of the buffer the caller named */
+ ctx->args[2].length = init->filelen;
+ ctx->args[2].handle = init->filehandle;
+ assign_kernel_gem_arg(ctx, 3, kernel_gem, gv + off_pages, sizeof(struct qda_phy_page));
+
+ drm_gem_object_put(&kernel_gem->base);
+
+ return 0;
+}
+
/*
* INVOKE_DYNAMIC: the argument descriptors are supplied by user space, which
* is also responsible for having imported every buffer to a GEM handle.
@@ -740,8 +913,23 @@ int qda_fastrpc_prepare_args(struct qda_fastrpc_invoke_ctx *ctx,
*/
qda_session_get(session);
ctx->session = session;
-
- err = qda_fastrpc_prepare_args_invoke(ctx, argp);
+ ctx->pd = READ_ONCE(session->pd);
+
+ switch (ctx->type) {
+ case QDA_FASTRPC_RMID_INIT_RELEASE:
+ err = qda_fastrpc_prepare_args_release_process(ctx);
+ break;
+ case QDA_FASTRPC_RMID_INIT_CREATE:
+ /* The new process is in the user PD, and so is the request creating it */
+ ctx->pd = QDA_USER_PD;
+ err = qda_fastrpc_prepare_args_init_create(ctx, argp);
+ break;
+ case QDA_FASTRPC_RMID_INVOKE_DYNAMIC:
+ err = qda_fastrpc_prepare_args_invoke(ctx, argp);
+ break;
+ default:
+ return -EINVAL;
+ }
if (err)
return err;
diff --git a/drivers/accel/qda/qda_fastrpc.h b/drivers/accel/qda/qda_fastrpc.h
index 3243bd1065c6..eaebc4e99676 100644
--- a/drivers/accel/qda/qda_fastrpc.h
+++ b/drivers/accel/qda/qda_fastrpc.h
@@ -33,14 +33,32 @@ struct qda_session;
QDA_REMOTE_SCALARS_INHANDLES(sc) + \
QDA_REMOTE_SCALARS_OUTHANDLES(sc))
+/* Encodes a method ID and the in/out buffer counts; handle counts are zero */
+#define QDA_FASTRPC_SCALARS(method, in, out) ((((method) & 0x1f) << 24) | \
+ (((in) & 0xff) << 16) | \
+ (((out) & 0xff) << 8))
+
/* FastRPC configuration constants */
#define QDA_FASTRPC_ALIGN 128 /* Alignment the DSP expects of the payload */
#define QDA_FASTRPC_MAX_HANDLELIST 16 /* Handles the DSP can ask to release */
#define QDA_FASTRPC_MAX_CRCLIST 64 /* CRC list entries */
-/* Protection domain a session's invocations run in */
+/* Methods of the initialisation handle */
+#define QDA_FASTRPC_RMID_INIT_RELEASE 1
+#define QDA_FASTRPC_RMID_INIT_CREATE 6
+#define QDA_FASTRPC_RMID_INIT_CREATE_ATTR 7
+#define QDA_FASTRPC_RMID_INVOKE_DYNAMIC 0xFFFFFFFFU
+
+/* Handle the initialisation methods are addressed to */
+#define QDA_FASTRPC_INIT_HANDLE 0x1
+
+/* Protection domains a request can be directed at */
+#define QDA_ROOT_PD 0
#define QDA_USER_PD 1
+/* Largest ELF image a process may be created from */
+#define QDA_FASTRPC_INIT_FILELEN_MAX (4 * 1024 * 1024)
+
/* Idle invoke header buffers a session keeps for reuse */
#define QDA_MSG_BUF_POOL_MAX 8
@@ -111,6 +129,26 @@ struct qda_invoke_buf {
u32 pgidx;
};
+/**
+ * struct qda_fastrpc_create_process_inbuf - Input buffer for process creation
+ *
+ * Layout the DSP expects; do not reorder.
+ */
+struct qda_fastrpc_create_process_inbuf {
+ /** @remote_session_id: Session the process belongs to */
+ int remote_session_id;
+ /** @namelen: Length of the process name including the NUL */
+ u32 namelen;
+ /** @filelen: Length of the ELF image 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 qda_fastrpc_msg - FastRPC wire message for remote invocations
*
@@ -164,6 +202,12 @@ struct qda_fastrpc_invoke_ctx {
u64 ctxid;
/** @retval: Status the DSP reported, or an error if it never answered */
int retval;
+ /** @pd: Protection domain, OR'ed into the low bits of @ctxid when packed */
+ int pd;
+ /** @type: Method being invoked (QDA_FASTRPC_RMID_*) */
+ u32 type;
+ /** @legacy: Arguments came from the legacy shim, where offsets are user VAs */
+ bool legacy;
/** @nscalars: Total number of scalar arguments */
int nscalars;
/** @nbufs: Number of buffer arguments; the rest are handle arguments */
@@ -180,6 +224,8 @@ struct qda_fastrpc_invoke_ctx {
struct drm_gem_object **gem_objs;
/** @msg_gem_obj: GEM object backing the message payload buffer */
struct qda_gem_obj *msg_gem_obj;
+ /** @init_mem_gem_obj: Memory the DSP loads a new process into */
+ struct qda_gem_obj *init_mem_gem_obj;
/** @pages: Array of physical page descriptors inside the payload */
struct qda_phy_page *pages;
/** @work: Completed once the DSP has answered */
diff --git a/drivers/accel/qda/qda_ioctl.c b/drivers/accel/qda/qda_ioctl.c
index e9f4151e344a..f51ad0bc9e9c 100644
--- a/drivers/accel/qda/qda_ioctl.c
+++ b/drivers/accel/qda/qda_ioctl.c
@@ -75,7 +75,22 @@ int qda_ioctl_gem_mmap_offset(struct drm_device *dev, void *data, struct drm_fil
return drm_gem_dumb_map_offset(file_priv, dev, args->handle, &args->offset);
}
-static int qda_fastrpc_invoke(void *data, struct qda_session *session)
+/*
+ * A process created again replaces the first, so the memory held for the
+ * previous one is dropped. Swapped atomically, as ioctls on one file can run
+ * concurrently.
+ */
+static void qda_session_set_init_mem(struct qda_session *session, struct qda_gem_obj *mem)
+{
+ struct qda_gem_obj *old;
+
+ drm_gem_object_get(&mem->base);
+ old = xchg(&session->init_mem_gem_obj, mem);
+ if (old)
+ drm_gem_object_put(&old->base);
+}
+
+static int qda_fastrpc_invoke(u32 type, void *data, struct qda_session *session)
{
struct qda_dev *qdev = session->qda_dev;
struct qda_fastrpc_invoke_ctx *ctx;
@@ -85,11 +100,26 @@ static int qda_fastrpc_invoke(void *data, struct qda_session *session)
if (IS_ERR(ctx))
return PTR_ERR(ctx);
+ ctx->type = type;
+
err = qda_fastrpc_prepare_args(ctx, session, data);
if (err)
goto out_put;
err = qda_fastrpc_invoke_common(qdev, ctx);
+ if (err)
+ goto out_put;
+
+ /*
+ * The session only changes once the DSP has accepted the request, so a
+ * failed create leaves the previous process, if any, as it was. The
+ * memory is freed with the session, which the invocation keeps alive
+ * until it is done, so a release needs no reference of its own.
+ */
+ if (type == QDA_FASTRPC_RMID_INIT_CREATE) {
+ qda_session_set_init_mem(session, ctx->init_mem_gem_obj);
+ WRITE_ONCE(session->pd, QDA_USER_PD);
+ }
out_put:
kref_put(&ctx->refcount, qda_fastrpc_context_free);
@@ -97,6 +127,31 @@ static int qda_fastrpc_invoke(void *data, struct qda_session *session)
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 qda_fastrpc_invoke(QDA_FASTRPC_RMID_INIT_CREATE, data, file_priv->driver_priv);
+}
+
+/**
+ * qda_release_dsp_process() - Tear down a session's DSP process
+ * @qdev: QDA device structure
+ * @session: Session whose process is released
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+int qda_release_dsp_process(struct qda_dev *qdev, struct qda_session *session)
+{
+ return qda_fastrpc_invoke(QDA_FASTRPC_RMID_INIT_RELEASE, NULL, session);
+}
+
/**
* qda_ioctl_invoke() - Run a method on the DSP
* @dev: DRM device structure
@@ -107,5 +162,5 @@ static int qda_fastrpc_invoke(void *data, struct qda_session *session)
*/
int qda_ioctl_invoke(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- return qda_fastrpc_invoke(data, file_priv->driver_priv);
+ return qda_fastrpc_invoke(QDA_FASTRPC_RMID_INVOKE_DYNAMIC, data, file_priv->driver_priv);
}
diff --git a/drivers/accel/qda/qda_ioctl.h b/drivers/accel/qda/qda_ioctl.h
index 3bb9cfd98370..da67f863c03c 100644
--- a/drivers/accel/qda/qda_ioctl.h
+++ b/drivers/accel/qda/qda_ioctl.h
@@ -12,5 +12,6 @@ int qda_ioctl_query(struct drm_device *dev, void *data, struct drm_file *file_pr
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);
+int qda_ioctl_init_create(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 c21bc5b2446c..75e67c5f5923 100644
--- a/include/uapi/drm/qda_accel.h
+++ b/include/uapi/drm/qda_accel.h
@@ -16,6 +16,7 @@ extern "C" {
#define DRM_QDA_GEM_CREATE 0x01
#define DRM_QDA_GEM_MMAP_OFFSET 0x02
#define DRM_QDA_REMOTE_INVOKE 0x03
+#define DRM_QDA_REMOTE_SESSION_CREATE 0x04
#define DRM_IOCTL_QDA_QUERY DRM_IOWR(DRM_COMMAND_BASE + DRM_QDA_QUERY, \
struct drm_qda_query)
@@ -25,6 +26,9 @@ extern "C" {
struct drm_qda_gem_mmap_offset)
#define DRM_IOCTL_QDA_REMOTE_INVOKE DRM_IOWR(DRM_COMMAND_BASE + DRM_QDA_REMOTE_INVOKE, \
struct drm_qda_invoke_args)
+#define DRM_IOCTL_QDA_REMOTE_SESSION_CREATE \
+ DRM_IOWR(DRM_COMMAND_BASE + DRM_QDA_REMOTE_SESSION_CREATE, \
+ struct drm_qda_init_create)
/* Query type definitions for drm_qda_query */
#define QDA_QUERY_DSP_NAME 1
@@ -109,6 +113,30 @@ struct drm_qda_invoke_args {
__u64 args;
};
+/* Process attribute flags for drm_qda_init_create.attrs */
+#define QDA_INIT_ATTR_UNSIGNED_MODULE (1U << 3)
+
+/**
+ * struct drm_qda_init_create - DSP process creation parameters
+ * @filelen: Length of the ELF image in bytes
+ * @filehandle: Handle of the buffer holding the ELF image
+ * @attrs: Process attribute flags
+ * @siglen: Length of the signature data in bytes
+ * @file: Reserved, must be zero
+ *
+ * Creates a process on the DSP for this file to run in. Without
+ * QDA_INIT_ATTR_UNSIGNED_MODULE in @attrs the process is created signed, which
+ * requires CAP_SYS_ADMIN. Creating a process again on the same file replaces
+ * the first.
+ */
+struct drm_qda_init_create {
+ __u32 filelen;
+ __u32 filehandle;
+ __u32 attrs;
+ __u32 siglen;
+ __u64 file;
+};
+
#if defined(__cplusplus)
}
#endif
--
2.34.1
next prev parent reply other threads:[~2026-11-01 22:24 UTC|newest]
Thread overview: 38+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-01 22:21 [PATCH v4 00/25] accel/qda: Qualcomm DSP Accelerator driver Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 01/25] accel/qda: Add QDA driver documentation Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 02/25] accel/qda: Add initial QDA DRM accelerator driver Ekansh Gupta
2026-11-02 8:42 ` Krzysztof Kozlowski
2026-11-01 22:21 ` [PATCH v4 03/25] accel/qda: Add compute context bank devices Ekansh Gupta
2026-11-02 8:43 ` Krzysztof Kozlowski
2026-11-01 22:21 ` [PATCH v4 04/25] accel/qda: Assign a context bank to each session Ekansh Gupta
2026-11-02 8:45 ` Krzysztof Kozlowski
2026-11-01 22:21 ` [PATCH v4 05/25] accel/qda: Add UAPI header and DSP query ioctl Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 06/25] accel/qda: Add buffer allocation for the DSP Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 07/25] accel/qda: Add DMA-BUF import Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 08/25] accel/qda: Add legacy ops base and auxiliary device Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 09/25] accel/qda: Add legacy FastRPC shim skeleton Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 10/25] accel/qda: Add FastRPC invocation contexts Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 11/25] accel/qda: Add RPMsg send and response dispatch Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 12/25] accel/qda: Add invocation argument validation and packing Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 13/25] accel/qda: Add the invocation ioctl and teardown on unplug Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 14/25] accel/qda: Add invocation through the legacy FastRPC shim Ekansh Gupta
2026-11-01 22:21 ` Ekansh Gupta [this message]
2026-11-01 22:21 ` [PATCH v4 16/25] accel/qda: Add DSP process creation and release to the legacy shim Ekansh Gupta
2026-11-02 8:47 ` Krzysztof Kozlowski
2026-11-01 22:21 ` [PATCH v4 17/25] accel/qda: Add remote memory mapping to the DSP address space Ekansh Gupta
2026-11-02 9:24 ` Konrad Dybcio
2026-11-01 22:21 ` [PATCH v4 18/25] accel/qda: Add remote memory unmapping from " Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 19/25] accel/qda: Add remote memory map and unmap to the legacy shim Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 20/25] accel/qda: Add remote attach to root and sensors protection domains Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 21/25] accel/qda: Add Audio protection domain attach and its remote heap Ekansh Gupta
2026-11-02 8:43 ` Arnd Bergmann
2026-11-02 8:50 ` Krzysztof Kozlowski
2026-11-01 22:21 ` [PATCH v4 22/25] accel/qda: Add remote session attach to the legacy shim Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 23/25] accel/qda: Add DSP capability query Ekansh Gupta
2026-11-02 8:46 ` Arnd Bergmann
2026-11-01 22:21 ` [PATCH v4 24/25] accel/qda: Add legacy shim support for " Ekansh Gupta
2026-11-01 22:21 ` [PATCH v4 25/25] accel/qda: Add poll mode for invocation completion Ekansh Gupta
2026-11-02 8:53 ` [PATCH v4 00/25] accel/qda: Qualcomm DSP Accelerator driver Krzysztof Kozlowski
2026-11-02 10:08 ` Ekansh Gupta
2026-11-02 10:12 ` Krzysztof Kozlowski
2026-11-02 10:52 ` Ekansh Gupta
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261102-v4-v4-15-88f2f24a5f0b@qti.qualcomm.com \
--to=ekansh.gupta@oss.qualcomm.com \
--cc=airlied@gmail.com \
--cc=andersson@kernel.org \
--cc=arnd@arndb.de \
--cc=bkumar@qti.qualcomm.com \
--cc=cacar@qti.qualcomm.com \
--cc=chennak@qti.qualcomm.com \
--cc=christian.koenig@amd.com \
--cc=corbet@lwn.net \
--cc=dmitry.baryshkov@oss.qualcomm.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=ekangupt@qti.qualcomm.com \
--cc=gregkh@linuxfoundation.org \
--cc=jgg@ziepe.ca \
--cc=krzk@kernel.org \
--cc=linaro-mm-sig@lists.linaro.org \
--cc=lingtong@qti.qualcomm.com \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=maarten.lankhorst@linux.intel.com \
--cc=mripard@kernel.org \
--cc=ogabbay@kernel.org \
--cc=phasta@kernel.org \
--cc=quic_bkumar@quicinc.com \
--cc=quic_chennak@quicinc.com \
--cc=rdunlap@infradead.org \
--cc=rob.clark@oss.qualcomm.com \
--cc=sandheep@qti.qualcomm.com \
--cc=simona@ffwll.ch \
--cc=skhan@linuxfoundation.org \
--cc=srini@kernel.org \
--cc=sumit.semwal@linaro.org \
--cc=tzimmermann@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®