From: Ekansh Gupta <ekansh.gupta@oss.qualcomm.com>
To: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Cc: "Oded Gabbay" <ogabbay@kernel.org>,
"Jonathan Corbet" <corbet@lwn.net>,
"Shuah Khan" <skhan@linuxfoundation.org>,
"Randy Dunlap" <rdunlap@infradead.org>,
"Nathan Chancellor" <nathan@kernel.org>,
"Nick Desaulniers" <ndesaulniers@google.com>,
"Bill Wendling" <morbo@google.com>,
"Justin Stitt" <justinstitt@google.com>,
"Joerg Roedel (AMD)" <joro@8bytes.org>,
"Will Deacon" <will@kernel.org>,
"Robin Murphy" <robin.murphy@arm.com>,
"Maarten Lankhorst" <maarten.lankhorst@linux.intel.com>,
"Maxime Ripard" <mripard@kernel.org>,
"Thomas Zimmermann" <tzimmermann@suse.de>,
"David Airlie" <airlied@gmail.com>,
"Simona Vetter" <simona@ffwll.ch>,
"Sumit Semwal" <sumit.semwal@linaro.org>,
"Christian König" <christian.koenig@amd.com>,
"Bharath Kumar" <quic_bkumar@quicinc.com>,
"Chenna Kesava Raju" <quic_chennak@quicinc.com>,
srinivas.kandagatla@oss.qualcomm.com,
linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org,
linux-doc@vger.kernel.org, linux-arm-msm@vger.kernel.org,
llvm@lists.linux.dev, iommu@lists.linux.dev,
linux-media@vger.kernel.org, linaro-mm-sig@lists.linaro.org
Subject: Re: [PATCH v2 12/15] accel/qda: Add FastRPC invocation support
Date: Thu, 20 Aug 2026 14:05:01 +0530 [thread overview]
Message-ID: <3f644c83-ffd6-452d-aa81-1c13aaa397ac@oss.qualcomm.com> (raw)
In-Reply-To: <hbrtbfpmcodd3nkaytihzki56232bws7ubbcth7ewwckwi5y6t@ft4ej4fr7duz>
On 18-08-2026 09:49, Dmitry Baryshkov wrote:
> On Mon, Aug 17, 2026 at 10:17:47AM +0530, Ekansh Gupta wrote:
>> Implement the FastRPC remote procedure call path, allowing user-space to
>> invoke methods on the DSP via DRM_IOCTL_QDA_REMOTE_INVOKE.
>>
>> qda_fastrpc.c / qda_fastrpc.h
>> Implements the FastRPC protocol layer: argument marshalling
>> (qda_fastrpc_invoke_pack), response unmarshalling
>> (qda_fastrpc_invoke_unpack), and invocation context lifecycle
>> management. Each invocation allocates a qda_fastrpc_invoke_ctx which
>> tracks buffer descriptors, GEM objects, and the completion used to
>> synchronise with the DSP response.
>>
>> Buffer arguments are identified by GEM handles. Userspace imports any
>> DMA-BUF fd to a GEM handle with DRM_IOCTL_PRIME_FD_TO_HANDLE before
>> invoking; the driver never accepts DMA-BUF fds directly. Each argument
>> is described by its GEM handle, the user virtual address of the data
>> and its length, from which the driver derives the offset within the
>> buffer and the page-aligned range to describe to the DSP. Packing
>> several arguments into one buffer, and any overlap handling, is left
>> to user space.
>>
>> qda_rpmsg.c
>> Implements qda_rpmsg_send_msg() which sends the wire-format
>> fastrpc_msg (embedded as the first member of qda_msg) directly via
>> rpmsg_send(), and qda_rpmsg_wait_for_rsp() which blocks on the context
>> completion. The RPMsg callback dispatches responses to waiting
>> contexts via the ctx_xa XArray.
>>
>> qda_ioctl.c
>> qda_ioctl_invoke() drives the full invocation lifecycle: it builds the
>> invocation context from the user-supplied arguments, packs the
>> arguments into the message buffer, sends the message to the DSP, waits
>> for the response, unpacks the output arguments back to user space and
>> releases the context.
>>
>> include/uapi/drm/qda_accel.h
>> Adds DRM_IOCTL_QDA_REMOTE_INVOKE with struct drm_qda_invoke_args and
>> the per-argument descriptor struct drm_qda_fastrpc_invoke_args.
>>
>> Assisted-by: Claude:claude-sonnet-5
>> Signed-off-by: Ekansh Gupta <ekansh.gupta@oss.qualcomm.com>
>> ---
>> Changes in v2:
>> - Drop the DMA-BUF fd argument path. Buffer arguments are now identified
>> by GEM handles only; user space is responsible for importing fds to
>> GEM handles before invoking (Dmitry Baryshkov)
>> - Leave argument packing and overlap handling to user space rather than
>> supporting several buffer-passing formats in the driver
>> (Dmitry Baryshkov)
>> ---
>> drivers/accel/qda/Makefile | 1 +
>> drivers/accel/qda/qda_drv.c | 8 +
>> drivers/accel/qda/qda_drv.h | 8 +
>> drivers/accel/qda/qda_fastrpc.c | 434 ++++++++++++++++++++++++++++++++++++++++
>> drivers/accel/qda/qda_fastrpc.h | 242 ++++++++++++++++++++++
>> drivers/accel/qda/qda_ioctl.c | 83 ++++++++
>> drivers/accel/qda/qda_ioctl.h | 1 +
>> drivers/accel/qda/qda_rpmsg.c | 91 ++++++++-
>> drivers/accel/qda/qda_rpmsg.h | 26 +++
>> include/uapi/drm/qda_accel.h | 42 ++++
>> 10 files changed, 934 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/accel/qda/Makefile b/drivers/accel/qda/Makefile
>> index fb092e56d7f3..2d10420cd1ec 100644
>> --- a/drivers/accel/qda/Makefile
>> +++ b/drivers/accel/qda/Makefile
>> @@ -8,6 +8,7 @@ obj-$(CONFIG_DRM_ACCEL_QDA) := qda.o
>> qda-y := \
>> qda_cb.o \
>> qda_drv.o \
>> + qda_fastrpc.o \
>> qda_gem.o \
>> qda_ioctl.o \
>> qda_memory_dma.o \
>> diff --git a/drivers/accel/qda/qda_drv.c b/drivers/accel/qda/qda_drv.c
>> index a68a07d0ae56..f925bbcfa6e9 100644
>> --- a/drivers/accel/qda/qda_drv.c
>> +++ b/drivers/accel/qda/qda_drv.c
>> @@ -25,6 +25,8 @@ static int qda_open(struct drm_device *dev, struct drm_file *file)
>>
>> qda_file_priv->pid = current->pid;
>> qda_file_priv->qda_dev = qda_dev_from_drm(dev);
>> + qda_file_priv->remote_session_id =
>> + atomic_inc_return(&qda_file_priv->qda_dev->remote_session_id_counter);
>
> What happens on the wraparound? What if some of those sessions are still
> alive?
collision would require 2^31 opens without close, is this reachable?
Should I add a comment here? Or some how address this?>
>> file->driver_priv = qda_file_priv;
>>
>> return 0;
>
> [...]
>
>> +
>> +/*
>> + * The driver only accepts GEM handles from user space; userspace imports
>> + * DMA-BUF fds with DRM_IOCTL_PRIME_FD_TO_HANDLE before issuing any ioctl that
>> + * carries a buffer reference.
>
> What else can it accept?
will remove the obvious statement here>
>> + *
>> + * The caller owns the returned reference and must drop it with
>> + * drm_gem_object_put().
>> + */
>> +static int get_gem_obj_from_handle(struct qda_fastrpc_invoke_ctx *ctx, u32 handle,
>> + struct drm_gem_object **gem_obj)
>> +{
>> + *gem_obj = drm_gem_object_lookup(ctx->file_priv, handle);
>> + if (!*gem_obj)
>> + return -ENOENT;
>> +
>> + return 0;
>> +}
>> +
>> +static void setup_pages_from_gem_obj(struct qda_gem_obj *qda_gem_obj,
>> + struct fastrpc_phy_page *pages)
>> +{
>> + pages->addr = qda_gem_obj->dma_addr;
>> + pages->size = qda_gem_obj->size;
>> +}
>> +
>> +static u64 calculate_vma_offset(u64 user_ptr)
>> +{
>> + struct vm_area_struct *vma;
>> + u64 vma_offset = 0;
>> +
>> + mmap_read_lock(current->mm);
>> + vma = find_vma(current->mm, user_ptr);
>> + if (vma)
>> + vma_offset = (user_ptr & PAGE_MASK) - vma->vm_start;
>> + mmap_read_unlock(current->mm);
>> +
>> + return vma_offset;
>> +}
>> +
>> +static u64 calculate_page_aligned_size(u64 ptr, u64 len)
>> +{
>> + u64 pg_start = (ptr & PAGE_MASK) >> PAGE_SHIFT;
>> + u64 pg_end = ((ptr + len - 1) & PAGE_MASK) >> PAGE_SHIFT;
>> +
>> + return (pg_end - pg_start + 1) * PAGE_SIZE;
>> +}
>> +
>> +static struct fastrpc_invoke_buf *fastrpc_invoke_buf_start(union fastrpc_remote_arg *pra, int len)
>> +{
>> + return (struct fastrpc_invoke_buf *)(&pra[len]);
>
> Ugh. Is it not start + len * sizeof(union fastrpc_remote_arg)? Can't you
> just write it at the caller site?
ack>
>> +}
>> +
>> +static struct fastrpc_phy_page *fastrpc_phy_page_start(struct fastrpc_invoke_buf *buf, int len)
>> +{
>> + return (struct fastrpc_phy_page *)(&buf[len]);
>> +}
>> +
>> +static size_t fastrpc_get_meta_size(struct qda_fastrpc_invoke_ctx *ctx)
>> +{
>> + return (sizeof(struct fastrpc_remote_buf) +
>
> Just one buffer?
I'll add a comment explaining this formulation like it was in fastrpc[1].
[1]
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/drivers/misc/fastrpc.c#n982>
>> + sizeof(struct fastrpc_invoke_buf) +
>> + sizeof(struct fastrpc_phy_page)) * ctx->nscalars +
>> + sizeof(u64) * FASTRPC_MAX_HANDLELIST +
>> + sizeof(u32) * FASTRPC_MAX_CRCLIST;
>> +}
>> +
>> +/**
>> + * qda_fastrpc_cleanup_handlelist() - Release DMA handles the DSP no longer needs
>> + * @ctx: Invocation context whose response buffer contains the handle list
>> + *
>> + * The DSP signals handle release by writing GEM handles into the handle list
>> + * region of the response buffer. Walk the list and close each handle, which
>> + * drops the GEM reference and tears down the IOMMU mapping. This must be called
>> + * after dma_rmb() has made the DSP's writes visible.
>> + */
>> +void qda_fastrpc_cleanup_handlelist(struct qda_fastrpc_invoke_ctx *ctx)
>> +{
>> + u64 *handlelist;
>> + int i;
>> +
>> + handlelist = (u64 *)(ctx->pages + ctx->nscalars);
>> + for (i = 0; i < FASTRPC_MAX_HANDLELIST; i++) {
>> + if (!handlelist[i])
>> + break;
>> + drm_gem_handle_delete(ctx->file_priv, (u32)handlelist[i]);
>> + }
>> +}
>> +
>> +/**
>> + * qda_fastrpc_context_free() - Release an invocation context
>> + * @ref: Reference counter embedded in the context
>> + *
>> + * Called when the last reference is dropped, which may be either the caller
>> + * that issued the invocation or the response callback. The context is removed
>> + * from the lookup table here so that a late response can never find a context
>> + * that is already being destroyed.
>> + *
>> + * ctx->req, ctx->rsp, ctx->inbuf and ctx->input_pages point into kernel-owned
>> + * GEM mappings and are released along with ctx->gem_objs[].
>> + */
>> +void qda_fastrpc_context_free(struct kref *ref)
>> +{
>> + struct qda_fastrpc_invoke_ctx *ctx;
>> + int i;
>> +
>> + ctx = container_of(ref, struct qda_fastrpc_invoke_ctx, refcount);
>> +
>> + xa_erase(&ctx->qdev->ctx_xa, ctx->ctxid >> 4);
>> +
>> + if (ctx->gem_objs) {
>> + for (i = 0; i < ctx->nscalars; ++i) {
>> + if (ctx->gem_objs[i])
>> + drm_gem_object_put(ctx->gem_objs[i]);
>> + }
>> + kfree(ctx->gem_objs);
>> + }
>> +
>> + if (ctx->msg_gem_obj)
>> + drm_gem_object_put(&ctx->msg_gem_obj->base);
>> +
>> + kfree(ctx->args);
>> + kfree(ctx);
>> +}
>> +
>> +/**
>> + * qda_fastrpc_flush_pending() - Fail every outstanding invocation
>> + * @qdev: Device whose contexts should be flushed
>> + *
>> + * Called when the remote processor goes away. The DSP will never answer the
>> + * in-flight invocations, so this stands in for the response callback: it wakes
>> + * each waiter with an error and drops the reference the send path took for that
>> + * callback. The waiter then tears the context down, releasing the GEM objects
>> + * it pinned.
>> + *
>> + * Must run after drm_dev_unplug() has drained qda_rpmsg_cb(), so the real
>> + * callback can no longer run and this is the only path completing a context.
>> + */
>> +void qda_fastrpc_flush_pending(struct qda_dev *qdev)
>> +{
>> + struct qda_fastrpc_invoke_ctx *ctx;
>> + unsigned long idx;
>> +
>> + xa_for_each(&qdev->ctx_xa, idx, ctx) {
>> + ctx->retval = -EPIPE;
>> + complete(&ctx->work);
>> + kref_put(&ctx->refcount, qda_fastrpc_context_free);
>> + }
>> +}
>> +
>> +/**
>> + * qda_fastrpc_context_alloc() - Allocate a FastRPC invocation context
>> + * @qdev: Device whose lookup table the context is registered in
>> + *
>> + * Return: Pointer to the new context, or ERR_PTR on failure
>> + */
>> +struct qda_fastrpc_invoke_ctx *qda_fastrpc_context_alloc(struct qda_dev *qdev)
>> +{
>> + struct qda_fastrpc_invoke_ctx *ctx;
>> + int ret;
>> + u32 id;
>> +
>> + ctx = kzalloc_obj(*ctx);
>> + if (!ctx)
>> + return ERR_PTR(-ENOMEM);
>> +
>> + INIT_LIST_HEAD(&ctx->node);
>> + init_completion(&ctx->work);
>> + kref_init(&ctx->refcount);
>> + ctx->qdev = qdev;
>> + ctx->retval = -1;
>> + ctx->pid = current->pid;
>> +
>> + ret = xa_alloc(&qdev->ctx_xa, &id, ctx, xa_limit_32b, GFP_KERNEL);
>> + if (ret) {
>> + kfree(ctx);
>> + return ERR_PTR(ret);
>> + }
>> + ctx->ctxid = id << 4;
>> +
>> + return ctx;
>> +}
>> +
>> +/*
>> + * Resolve the physical address of an in/out buffer argument. The buffer is
>> + * backed either by a kernel-owned GEM object already recorded in
>> + * ctx->gem_objs[i], or by a user-supplied GEM handle in ctx->args[i].handle.
>> + */
>> +static int process_msg_buffer(struct qda_fastrpc_invoke_ctx *ctx, int i,
>> + union fastrpc_remote_arg *rpra,
>> + struct fastrpc_phy_page *pages)
>> +{
>> + u64 len = ctx->args[i].length;
>> + struct qda_gem_obj *qda_gem_obj;
>> +
>> + rpra[i].buf.pv = ctx->args[i].ptr;
>> +
>> + if (ctx->gem_objs[i]) {
>> + u64 unaligned_addr, offset;
>> +
>> + qda_gem_obj = to_qda_gem_obj(ctx->gem_objs[i]);
>> + offset = ctx->args[i].ptr - (u64)(uintptr_t)qda_gem_obj->virt;
>> +
>> + unaligned_addr = qda_gem_obj->dma_addr + offset;
>> + pages[i].addr = unaligned_addr & PAGE_MASK;
>> + pages[i].size = calculate_page_aligned_size(unaligned_addr, len);
>> + } else if (ctx->args[i].handle) {
>> + struct drm_gem_object *gem_obj;
>> + int err;
>> +
>> + err = get_gem_obj_from_handle(ctx, ctx->args[i].handle, &gem_obj);
>> + if (err)
>> + return err;
>> +
>> + ctx->gem_objs[i] = gem_obj;
>> + qda_gem_obj = to_qda_gem_obj(gem_obj);
>> +
>> + pages[i].addr = qda_gem_obj->dma_addr +
>> + calculate_vma_offset(ctx->args[i].ptr);
>> + pages[i].size = calculate_page_aligned_size(ctx->args[i].ptr, len);
>> + } else {
>> + return -EINVAL;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +/*
>> + * Resolve a DMA-handle argument. The kernel needs the physical page
>> + * descriptor, while the DSP identifies the buffer by its GEM handle.
>> + */
>> +static int process_dma_handle(struct qda_fastrpc_invoke_ctx *ctx, int i,
>> + union fastrpc_remote_arg *rpra,
>> + struct fastrpc_phy_page *pages)
>> +{
>> + struct drm_gem_object *gem_obj;
>> + int err;
>> +
>> + if (!ctx->args[i].handle) {
>> + rpra[i].buf.pv = ctx->args[i].ptr;
>> + rpra[i].buf.len = ctx->args[i].length;
>> + return 0;
>> + }
>> +
>> + err = get_gem_obj_from_handle(ctx, ctx->args[i].handle, &gem_obj);
>> + if (err)
>> + return err;
>> +
>> + ctx->gem_objs[i] = gem_obj;
>> + setup_pages_from_gem_obj(to_qda_gem_obj(gem_obj), &pages[i]);
>> +
>> + /* The DSP-facing offset and length fields are 32-bit by wire format */
>> + rpra[i].dma.handle = ctx->args[i].handle;
>> + rpra[i].dma.len = (u32)ctx->args[i].length;
>> + rpra[i].dma.offset = (u32)ctx->args[i].ptr;
>> +
>> + return 0;
>> +}
>> +
>> +/**
>> + * qda_fastrpc_get_header_size() - Compute the FastRPC message header size
>> + * @ctx: FastRPC invocation context
>> + *
>> + * Also caches the intermediate metadata and packet sizes in @ctx for the
>> + * subsequent pack step.
>> + *
>> + * Return: Page-aligned size of the message payload buffer in bytes
>> + */
>> +size_t qda_fastrpc_get_header_size(struct qda_fastrpc_invoke_ctx *ctx)
>> +{
>> + ctx->inbufs = REMOTE_SCALARS_INBUFS(ctx->sc);
>> + ctx->metalen = fastrpc_get_meta_size(ctx);
>> + ctx->pkt_size = ALIGN(ctx->metalen, FASTRPC_ALIGN);
>> + ctx->aligned_pkt_size = PAGE_ALIGN(ctx->pkt_size);
>> +
>> + return ctx->aligned_pkt_size;
>> +}
>> +
>> +static int qda_fastrpc_get_args(struct qda_fastrpc_invoke_ctx *ctx)
>> +{
>> + struct fastrpc_invoke_buf *list;
>> + struct fastrpc_phy_page *pages;
>> + union fastrpc_remote_arg *rpra;
>> + int i, err;
>> +
>> + ctx->msg->buf = ctx->msg_gem_obj->virt;
>> + ctx->msg->phys = ctx->msg_gem_obj->dma_addr;
>> + memset(ctx->msg->buf, 0, ctx->aligned_pkt_size);
>> +
>> + rpra = ctx->msg->buf;
>> + list = fastrpc_invoke_buf_start(rpra, ctx->nscalars);
>> + pages = fastrpc_phy_page_start(list, ctx->nscalars);
>> + ctx->rpra = rpra;
>> + ctx->list = list;
>> + ctx->pages = pages;
>> +
>> + for (i = 0; i < ctx->nbufs; ++i) {
>> + rpra[i].buf.pv = 0;
>> + rpra[i].buf.len = ctx->args[i].length;
>> + list[i].num = ctx->args[i].length ? 1 : 0;
>> + list[i].pgidx = i;
>> +
>> + if (!ctx->args[i].length)
>> + continue;
>> +
>> + err = process_msg_buffer(ctx, i, rpra, pages);
>> + if (err)
>> + return err;
>> + }
>> +
>> + for (i = ctx->nbufs; i < ctx->nscalars; ++i) {
>> + list[i].num = ctx->args[i].length ? 1 : 0;
>> + list[i].pgidx = i;
>> +
>> + err = process_dma_handle(ctx, i, rpra, pages);
>> + if (err)
>> + return err;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +/**
>> + * qda_fastrpc_invoke_pack() - Pack an invocation context into a QDA message
>> + * @ctx: FastRPC invocation context
>> + * @msg: QDA message to fill in
>> + *
>> + * Return: 0 on success, negative error code on failure
>> + */
>> +int qda_fastrpc_invoke_pack(struct qda_fastrpc_invoke_ctx *ctx, struct qda_msg *msg)
>> +{
>> + int err;
>> +
>> + ctx->msg = msg;
>> +
>> + err = qda_fastrpc_get_args(ctx);
>> + if (err)
>> + return err;
>> +
>> + /* Ensure the payload is visible to the DSP before the doorbell */
>> + dma_wmb();
>> +
>> + if (ctx->handle == FASTRPC_INIT_HANDLE)
>> + msg->fastrpc.remote_session_id = 0;
>> + else
>> + msg->fastrpc.remote_session_id = ctx->remote_session_id;
>> +
>> + msg->fastrpc.tid = ctx->pid;
>> + msg->fastrpc.ctx = ctx->ctxid | ctx->pd;
>> + msg->fastrpc.handle = ctx->handle;
>> + msg->fastrpc.sc = ctx->sc;
>> + msg->fastrpc.addr = msg->phys;
>> + msg->fastrpc.size = roundup(ctx->pkt_size, PAGE_SIZE);
>> + msg->fastrpc_ctx = ctx;
>> + msg->file_priv = ctx->file_priv;
>> +
>> + 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.
>> + */
>> +static int qda_fastrpc_prepare_args_invoke(struct qda_fastrpc_invoke_ctx *ctx, void *argp)
>> +{
>> + struct drm_qda_invoke_args *invoke_args = argp;
>> + struct drm_qda_fastrpc_invoke_args *args;
>> + u32 nscalars;
>> +
>> + ctx->handle = invoke_args->handle;
>> + ctx->sc = invoke_args->sc;
>> +
>> + nscalars = REMOTE_SCALARS_LENGTH(ctx->sc);
>> + if (!nscalars)
>> + return 0;
>> +
>> + args = kzalloc_objs(*args, nscalars);
>> + if (!args)
>> + return -ENOMEM;
>> +
>> + if (copy_from_user(args, u64_to_user_ptr(invoke_args->args),
>> + nscalars * sizeof(*args))) {
>> + kfree(args);
>> + return -EFAULT;
>> + }
>> +
>> + ctx->args = args;
>> +
>> + return 0;
>> +}
>> +
>> +/**
>> + * qda_fastrpc_prepare_args() - Prepare arguments for a FastRPC invocation
>> + * @ctx: FastRPC invocation context
>> + * @argp: Kernel-side ioctl argument buffer owned by the DRM core
>> + *
>> + * Return: 0 on success, negative error code on failure
>> + */
>> +int qda_fastrpc_prepare_args(struct qda_fastrpc_invoke_ctx *ctx, void *argp)
>> +{
>> + int err;
>> +
>> + switch (ctx->type) {
>> + case FASTRPC_RMID_INVOKE_DYNAMIC:
>> + err = qda_fastrpc_prepare_args_invoke(ctx, argp);
>> + break;
>> + default:
>> + return -EINVAL;
>> + }
>> + if (err)
>> + return err;
>> +
>> + ctx->nscalars = REMOTE_SCALARS_LENGTH(ctx->sc);
>> + ctx->nbufs = REMOTE_SCALARS_INBUFS(ctx->sc) + REMOTE_SCALARS_OUTBUFS(ctx->sc);
>> +
>> + if (ctx->nscalars && !ctx->gem_objs) {
>> + ctx->gem_objs = kzalloc_objs(*ctx->gem_objs, ctx->nscalars);
>> + if (!ctx->gem_objs)
>> + return -ENOMEM;
>> + }
>> +
>> + return 0;
>> +}
>> diff --git a/drivers/accel/qda/qda_fastrpc.h b/drivers/accel/qda/qda_fastrpc.h
>> new file mode 100644
>> index 000000000000..a25818923a6e
>> --- /dev/null
>> +++ b/drivers/accel/qda/qda_fastrpc.h
>> @@ -0,0 +1,242 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/*
>> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
>> + */
>> +
>> +#ifndef __QDA_FASTRPC_H__
>> +#define __QDA_FASTRPC_H__
>> +
>> +#include <linux/completion.h>
>> +#include <linux/kref.h>
>> +#include <linux/list.h>
>> +#include <linux/types.h>
>> +#include <drm/drm_drv.h>
>> +#include <drm/drm_file.h>
>> +#include <drm/qda_accel.h>
>> +
>> +struct qda_dev;
>> +struct qda_gem_obj;
>> +struct qda_msg;
>> +
>> +/*
>> + * FastRPC scalar extraction macros
>> + *
>> + * These macros extract different fields from the scalar value that describes
>> + * the arguments passed in a FastRPC invocation.
>> + */
>> +#define REMOTE_SCALARS_INBUFS(sc) (((sc) >> 16) & 0x0ff)
>> +#define REMOTE_SCALARS_OUTBUFS(sc) (((sc) >> 8) & 0x0ff)
>> +#define REMOTE_SCALARS_INHANDLES(sc) (((sc) >> 4) & 0x0f)
>> +#define REMOTE_SCALARS_OUTHANDLES(sc) ((sc) & 0x0f)
>> +#define REMOTE_SCALARS_LENGTH(sc) (REMOTE_SCALARS_INBUFS(sc) + \
>> + REMOTE_SCALARS_OUTBUFS(sc) + \
>> + REMOTE_SCALARS_INHANDLES(sc) + \
>> + REMOTE_SCALARS_OUTHANDLES(sc))
>> +
>> +/* FastRPC configuration constants */
>> +#define FASTRPC_ALIGN 128 /* Alignment requirement */
>> +#define FASTRPC_MAX_HANDLELIST 16 /* Maximum handles the DSP can release */
>> +#define FASTRPC_MAX_CRCLIST 64 /* Maximum CRC list entries */
>> +
>> +/*
>> + * FastRPC scalar construction macros
>> + *
>> + * These macros build the scalar value that describes the arguments
>> + * for a FastRPC invocation.
>> + */
>> +#define FASTRPC_BUILD_SCALARS(attr, method, in, out, oin, oout) \
>> + (((attr & 0x07) << 29) | \
>> + ((method & 0x1f) << 24) | \
>> + ((in & 0xff) << 16) | \
>> + ((out & 0xff) << 8) | \
>> + ((oin & 0x0f) << 4) | \
>> + (oout & 0x0f))
>> +
>> +#define FASTRPC_SCALARS(method, in, out) \
>> + FASTRPC_BUILD_SCALARS(0, method, in, out, 0, 0)
>> +
>> +/**
>> + * struct fastrpc_remote_dmahandle - Remote DMA handle descriptor
>> + */
>> +struct fastrpc_remote_dmahandle {
>> + /** @handle: Handle of the buffer */
>> + s32 handle;
>> + /** @offset: Byte offset within the buffer object */
>> + u32 offset;
>> + /** @len: Length of the region in bytes */
>> + u32 len;
>> +};
>> +
>> +/**
>> + * struct fastrpc_remote_buf - Remote buffer descriptor
>> + */
>> +struct fastrpc_remote_buf {
>> + /** @pv: Buffer pointer (user virtual address) */
>> + u64 pv;
>
> pv would mean physical something. Also, where do you validate the user's
> address? Where do we check that it's ok to access the buffer, that it's
> not a garbage?
this is inherited from fastrpc(same is also used on DSP firmware) but I
can rename it to something more meaningful like addr/va. This `pv` is
used for offset calculation which eventually gives address of the page
carrying the buffer. I can add checks when this calculation is done to
ensure the pv is in proper range of the buffer passed by user.>
>> + /** @len: Length of the buffer in bytes */
>> + u64 len;
>> +};
>> +
>> +/**
>> + * union fastrpc_remote_arg - Remote argument (buffer or DMA handle)
>> + */
>> +union fastrpc_remote_arg {
>> + /** @buf: Inline buffer descriptor */
>> + struct fastrpc_remote_buf buf;
>> + /** @dma: DMA-BUF handle descriptor */
>> + struct fastrpc_remote_dmahandle dma;
>> +};
>> +
>> +/**
>> + * struct fastrpc_phy_page - Physical page descriptor
>> + */
>> +struct fastrpc_phy_page {
>> + /** @addr: Physical (IOMMU) address of the page */
>> + u64 addr;
>> + /** @size: Size of the contiguous region in bytes */
>> + u64 size;
>> +};
>> +
>> +/**
>> + * struct fastrpc_invoke_buf - Invoke buffer descriptor
>> + */
>> +struct fastrpc_invoke_buf {
>> + /** @num: Number of contiguous physical regions */
>> + u32 num;
>> + /** @pgidx: Index into the physical page array */
>> + u32 pgidx;
>> +};
>> +
>> +/**
>> + * struct fastrpc_msg - FastRPC wire message for remote invocations
>> + *
>> + * Sent to the remote processor via RPMsg. This is the exact layout
>> + * the DSP expects; do not reorder or add fields without DSP firmware
>> + * coordination.
>
> __packed?
I'll check more on this.>
>> + */
>> +struct fastrpc_msg {
>> + /** @remote_session_id: Session identifier on the remote processor */
>> + int remote_session_id;
>
> Is it int or u32?
This is again from fastrpc where it's a mix of int and s32. I'll keep it
the to actual s32 here in QDA.>
>> + /** @tid: Thread ID of the invoking thread */
>> + int tid;
>> + /** @ctx: Context identifier for matching request/response */
>> + u64 ctx;
>> + /** @handle: Handle of the remote method to invoke */
>> + u32 handle;
>> + /** @sc: Scalars value encoding in/out buffer counts */
>> + u32 sc;
>> + /** @addr: Physical address of the message payload buffer */
>> + u64 addr;
>> + /** @size: Size of the message payload in bytes */
>> + u64 size;
>> +};
>> +
>> +/**
>> + * struct qda_fastrpc_invoke_ctx - Remote procedure call invocation context
>> + *
>> + * Maintains all state for a single remote procedure call, including buffer
>> + * management, synchronisation, and result handling.
>> + */
>> +struct qda_fastrpc_invoke_ctx {
>> + /** @node: List node for linking contexts in a queue */
>> + struct list_head node;
>> + /** @qdev: Device owning the XArray this context is registered in */
>> + struct qda_dev *qdev;
>> + /** @ctxid: Unique context identifier (XArray key shifted left by 4) */
>
> Why is it shifted by 4? Why not by 3?
I'll add the PD encoding comment here.>
>> + u64 ctxid;
>> + /** @inbufs: Number of input buffers */
>> + int inbufs;
>> + /** @nscalars: Total number of scalar arguments */
>> + int nscalars;
>> + /** @nbufs: Total number of buffer arguments (inbufs + outbufs) */
>> + int nbufs;
>> + /** @pid: Process ID of the calling process */
>> + int pid;
>> + /** @retval: Status code reported by the DSP for this invocation */
>> + int retval;
>> + /** @remote_session_id: Session identifier on the remote processor */
>> + int remote_session_id;
>
> is pid linked to remote_session_id?
not really, remote_session_id is more of session specific, so in case of
multi-session(same PID having multiple sessions) should have different
remote_session_id.>
>> + /** @pd: Protection domain identifier encoded into the context ID */
>
> If it's already encoded, why do you need it here?c
it's stores so the packing step can use it, I'll document more on this.
Or if I can have both msg->fastrpc.ctx and ctxid same, I'll check that
also>
>> + int pd;
>> + /** @type: Invocation type (e.g. FASTRPC_RMID_INVOKE_DYNAMIC) */
>> + u32 type;
>
> What other types can exist?
I'll add all the types in document or just add FASTRPC_RMID_* and point
to qda_fastrpc.h for more details.>
>> + /** @sc: Scalars value encoding in/out buffer counts */
>> + u32 sc;
>
> Remove it and calculate from in/outbufs above?
The source of sc is the auto-generated stub file which passes this to
remote_handle_invoke() based on the method requested by the user. This
as is as it is passed to DSP where this is used in auto-generated skel.
I think the other way around(in/outbufs from sc) would make more sense.>
>> + /** @handle: Handle of the remote method being invoked */
>> + u32 handle;
>> + /** @metalen: Length of the FastRPC metadata header in bytes */
>> + size_t metalen;
>> + /** @pkt_size: Total payload size in bytes */
>> + u64 pkt_size;
>> + /** @aligned_pkt_size: Page-aligned payload size for GEM allocation */
>
> ???
I'll check and remove this.>
>> + u64 aligned_pkt_size;
>> + /** @list: Array of invoke buffer descriptors */
>> + struct fastrpc_invoke_buf *list;
>> + /** @pages: Array of physical page descriptors for all arguments */
>> + struct fastrpc_phy_page *pages;
>> + /** @input_pages: Array of physical page descriptors for input buffers */
>> + struct fastrpc_phy_page *input_pages;
>> + /** @work: Completion used to synchronise with the DSP response */
>> + struct completion work;
>> + /** @msg: Pointer to the QDA message structure for this invocation */
>> + struct qda_msg *msg;
>> + /** @rpra: Array of remote procedure arguments */
>> + union fastrpc_remote_arg *rpra;
>> + /** @gem_objs: Array of GEM objects imported for argument buffers */
>> + struct drm_gem_object **gem_objs;
>> + /** @args: Invoke argument descriptors */
>> + struct drm_qda_fastrpc_invoke_args *args;
>> + /** @refcount: Reference counter for context lifetime management */
>
> What for?
just to ensure that the context is not freed in case the
wait_for_completion() is interrupted.>
>> + struct kref refcount;
>> + /** @msg_gem_obj: GEM object backing the message payload buffer */
>> + struct qda_gem_obj *msg_gem_obj;
>> + /** @file_priv: DRM file private data */
>> + struct drm_file *file_priv;
>> + /**
>> + * @req: Request buffer for the internal init/map/unmap calls. Points
>> + * into a kernel-owned GEM mapping tracked by @gem_objs, so it must
>> + * never be freed directly.
>> + */
>> + void *req;
>
> Why do you need separate pointers here? Can't you be getting them from
> msm_gem_obj?
These are typed pointers into different offsets of the kernel GEM
mapping. I could compute them each time from `msg_gem_obj->virt +
offset`, but caching them avoids repetitive casting. Let me see if
removing this looks cleaner.>
>> + /** @rsp: Response buffer, same lifetime rules as @req */
>> + void *rsp;
>> + /** @inbuf: Process-create input buffer, same lifetime rules as @req */
>> + void *inbuf;
>> +};
>> +
>> +/**
>> + * struct qda_msg - FastRPC message with kernel-internal bookkeeping
>> + */
>> +struct qda_msg {
>> + /**
>> + * @fastrpc: Wire-format message sent to the DSP via RPMsg.
>> + * Must be the first member.
>> + */
>> + struct fastrpc_msg fastrpc;
>> + /** @buf: Kernel virtual address of the payload buffer */
>> + void *buf;
>> + /** @phys: Physical/DMA address of the payload buffer */
>> + u64 phys;
>> + /** @ret: Return value from the remote processor */
>> + int ret;
>> + /** @fastrpc_ctx: Back-pointer to the owning invocation context */
>> + struct qda_fastrpc_invoke_ctx *fastrpc_ctx;
>> + /** @file_priv: DRM file private data for GEM object lookup */
>> + struct drm_file *file_priv;
>> +};
>> +
>> +/* Remote Method ID table - identifies initialization and control operations */
>> +#define FASTRPC_RMID_INVOKE_DYNAMIC 0xFFFFFFFFU /* Dynamic method invocation */
>> +
>> +/* Common handle for initialization operations */
>> +#define FASTRPC_INIT_HANDLE 0x1
>> +
>> +void qda_fastrpc_context_free(struct kref *ref);
>> +void qda_fastrpc_cleanup_handlelist(struct qda_fastrpc_invoke_ctx *ctx);
>> +void qda_fastrpc_flush_pending(struct qda_dev *qdev);
>> +struct qda_fastrpc_invoke_ctx *qda_fastrpc_context_alloc(struct qda_dev *qdev);
>> +int qda_fastrpc_prepare_args(struct qda_fastrpc_invoke_ctx *ctx, void *argp);
>> +size_t qda_fastrpc_get_header_size(struct qda_fastrpc_invoke_ctx *ctx);
>> +int qda_fastrpc_invoke_pack(struct qda_fastrpc_invoke_ctx *ctx, struct qda_msg *msg);
>> +
>> +#endif /* __QDA_FASTRPC_H__ */
>> diff --git a/drivers/accel/qda/qda_ioctl.c b/drivers/accel/qda/qda_ioctl.c
>> index f65325c80a12..b7ee4899ba74 100644
>> --- a/drivers/accel/qda/qda_ioctl.c
>> +++ b/drivers/accel/qda/qda_ioctl.c
>> @@ -1,10 +1,13 @@
>> // SPDX-License-Identifier: GPL-2.0-only
>> // Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
>> #include <drm/drm_ioctl.h>
>> +#include <drm/drm_print.h>
>> #include <drm/qda_accel.h>
>> #include "qda_drv.h"
>> +#include "qda_fastrpc.h"
>> #include "qda_gem.h"
>> #include "qda_ioctl.h"
>> +#include "qda_rpmsg.h"
>>
>> /**
>> * qda_ioctl_query() - Query DSP device information
>> @@ -83,3 +86,83 @@ 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(u32 type, struct drm_device *dev, void *data,
>> + struct drm_file *file_priv)
>> +{
>> + struct qda_file_priv *qda_file_priv = file_priv->driver_priv;
>> + struct qda_dev *qdev = qda_file_priv->qda_dev;
>> + struct qda_fastrpc_invoke_ctx *ctx;
>> + struct drm_gem_object *gem_obj;
>> + struct qda_msg msg;
>> + size_t hdr_size;
>> + int err;
>> +
>> + ctx = qda_fastrpc_context_alloc(qdev);
>> + if (IS_ERR(ctx))
>> + return PTR_ERR(ctx);
>> +
>> + ctx->type = type;
>> + ctx->file_priv = file_priv;
>> + ctx->remote_session_id = qda_file_priv->remote_session_id;
>> +
>> + err = qda_fastrpc_prepare_args(ctx, data);
>> + if (err)
>> + goto err_context_free;
>> +
>> + hdr_size = qda_fastrpc_get_header_size(ctx);
>> +
>> + gem_obj = qda_gem_create_object(dev, qdev->iommu_mgr, hdr_size, file_priv);
>> + if (IS_ERR(gem_obj)) {
>> + err = PTR_ERR(gem_obj);
>> + goto err_context_free;
>> + }
>> +
>> + ctx->msg_gem_obj = to_qda_gem_obj(gem_obj);
>> +
>> + err = qda_fastrpc_invoke_pack(ctx, &msg);
>> + if (err)
>> + goto err_context_free;
>> +
>> + err = qda_rpmsg_send_msg(qdev, &msg);
>> + if (err)
>> + goto err_context_free;
>> +
>> + err = qda_rpmsg_wait_for_rsp(ctx);
>> + if (err)
>> + goto err_context_free;
>> +
>> + /* Ensure the results written by the DSP are visible before reading */
>> + dma_rmb();
>> +
>> + err = ctx->retval;
>> + if (err) {
>> + drm_dbg_driver(dev, "DSP returned status 0x%x for type %u\n",
>> + ctx->retval, type);
>> + goto err_context_free;
>> + }
>> +
>> + qda_fastrpc_cleanup_handlelist(ctx);
>> +
>> + kref_put(&ctx->refcount, qda_fastrpc_context_free);
>> +
>> + return 0;
>> +
>> +err_context_free:
>> + kref_put(&ctx->refcount, qda_fastrpc_context_free);
>> +
>> + return err;
>> +}
>> +
>> +/**
>> + * qda_ioctl_invoke() - Perform a dynamic FastRPC method invocation
>> + * @dev: DRM device structure
>> + * @data: User-space data (struct qda_invoke_args)
>> + * @file_priv: DRM file private data
>> + *
>> + * Return: 0 on success, negative error code on failure
>> + */
>> +int qda_ioctl_invoke(struct drm_device *dev, void *data, struct drm_file *file_priv)
>> +{
>> + return qda_fastrpc_invoke(FASTRPC_RMID_INVOKE_DYNAMIC, dev, data, file_priv);
>> +}
>> diff --git a/drivers/accel/qda/qda_ioctl.h b/drivers/accel/qda/qda_ioctl.h
>> index d1cbbfb6d965..3bb9cfd98370 100644
>> --- a/drivers/accel/qda/qda_ioctl.h
>> +++ b/drivers/accel/qda/qda_ioctl.h
>> @@ -11,5 +11,6 @@
>> int qda_ioctl_query(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);
>>
>> #endif /* __QDA_IOCTL_H__ */
>> diff --git a/drivers/accel/qda/qda_rpmsg.c b/drivers/accel/qda/qda_rpmsg.c
>> index 64bf503106d9..7a5e0d3e20ca 100644
>> --- a/drivers/accel/qda/qda_rpmsg.c
>> +++ b/drivers/accel/qda/qda_rpmsg.c
>> @@ -1,12 +1,17 @@
>> // SPDX-License-Identifier: GPL-2.0-only
>> // Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
>> +#include <linux/completion.h>
>> #include <linux/module.h>
>> #include <linux/of.h>
>> #include <linux/rpmsg.h>
>> +#include <linux/sched.h>
>> +#include <linux/wait.h>
>> #include <drm/drm_print.h>
>>
>> #include "qda_cb.h"
>> #include "qda_drv.h"
>> +#include "qda_fastrpc.h"
>> +#include "qda_rpmsg.h"
>>
>> static struct qda_dev *qda_rpmsg_alloc_and_init_qdev(struct rpmsg_device *rpdev)
>> {
>> @@ -23,11 +28,92 @@ static struct qda_dev *qda_rpmsg_alloc_and_init_qdev(struct rpmsg_device *rpdev)
>> return qdev;
>> }
>>
>> +/**
>> + * qda_rpmsg_send_msg() - Send a packed invocation to the remote processor
>> + * @qdev: QDA device structure
>> + * @msg: Packed message to send
>> + *
>> + * Takes a reference on the invocation context on behalf of the response
>> + * callback, which keeps the context alive until the DSP has replied.
>> + *
>> + * Return: 0 on success, negative error code on failure
>> + */
>> +int qda_rpmsg_send_msg(struct qda_dev *qdev, struct qda_msg *msg)
>> +{
>> + struct qda_fastrpc_invoke_ctx *ctx = msg->fastrpc_ctx;
>> + int ret, idx;
>> +
>> + if (!drm_dev_enter(&qdev->drm_dev, &idx))
>> + return -ENODEV;
>> +
>> + if (!qdev->rpdev) {
>> + ret = -ENODEV;
>> + goto out_exit;
>> + }
>> +
>> + kref_get(&ctx->refcount);
>> +
>> + ret = rpmsg_send(qdev->rpdev->ept, &msg->fastrpc, sizeof(msg->fastrpc));
>> + if (ret) {
>> + drm_err_ratelimited(&qdev->drm_dev, "Failed to send rpmsg: %d\n", ret);
>> + kref_put(&ctx->refcount, qda_fastrpc_context_free);
>> + }
>> +
>> +out_exit:
>> + drm_dev_exit(idx);
>> +
>> + return ret;
>> +}
>> +
>> +/**
>> + * qda_rpmsg_wait_for_rsp() - Wait for the DSP to answer an invocation
>> + * @ctx: FastRPC invocation context
>> + *
>> + * Return: 0 once the response arrived, or -ERESTARTSYS if a signal
>> + * interrupted the wait
>> + */
>> +int qda_rpmsg_wait_for_rsp(struct qda_fastrpc_invoke_ctx *ctx)
>> +{
>> + return wait_for_completion_interruptible(&ctx->work);
>> +}
>> +
>> static int qda_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len,
>> void *priv, u32 src)
>> {
>> - /* Placeholder: responses will be dispatched here */
>> - return 0;
>> + struct qda_dev *qdev = dev_get_drvdata(&rpdev->dev);
>> + struct qda_invoke_rsp *resp_msg = data;
>> + struct qda_fastrpc_invoke_ctx *ctx;
>> + int ret = 0, idx;
>> +
>> + if (!qdev)
>> + return -ENODEV;
>> +
>> + if (!drm_dev_enter(&qdev->drm_dev, &idx))
>> + return -ENODEV;
>> +
>> + if (len < sizeof(*resp_msg)) {
>> + ret = -EINVAL;
>> + goto out_exit;
>> + }
>> +
>> + ctx = xa_load(&qdev->ctx_xa, resp_msg->ctx >> 4);
>> + if (!ctx) {
>> + drm_dbg_driver(&qdev->drm_dev, "No context matches response 0x%llx\n",
>> + resp_msg->ctx);
>> + ret = -ENOENT;
>> + goto out_exit;
>> + }
>> +
>> + ctx->retval = resp_msg->retval;
>> + complete(&ctx->work);
>> +
>> + /* Release the reference taken by qda_rpmsg_send_msg() */
>> + kref_put(&ctx->refcount, qda_fastrpc_context_free);
>> +
>> +out_exit:
>> + drm_dev_exit(idx);
>> +
>> + return ret;
>> }
>>
>> static void qda_rpmsg_remove(struct rpmsg_device *rpdev)
>> @@ -41,6 +127,7 @@ static void qda_rpmsg_remove(struct rpmsg_device *rpdev)
>> */
>> drm_dev_unplug(&qdev->drm_dev);
>> qdev->rpdev = NULL;
>> + qda_fastrpc_flush_pending(qdev);
>> qda_cb_unpopulate(qdev);
>> qda_deinit_device(qdev);
>> }
>> diff --git a/drivers/accel/qda/qda_rpmsg.h b/drivers/accel/qda/qda_rpmsg.h
>> new file mode 100644
>> index 000000000000..a70f4a80808d
>> --- /dev/null
>> +++ b/drivers/accel/qda/qda_rpmsg.h
>> @@ -0,0 +1,26 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/*
>> + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
>> + */
>> +
>> +#ifndef __QDA_RPMSG_H__
>> +#define __QDA_RPMSG_H__
>> +
>> +#include "qda_drv.h"
>> +#include "qda_fastrpc.h"
>> +
>> +/**
>> + * struct qda_invoke_rsp - Response structure for FastRPC invocations
>> + */
>> +struct qda_invoke_rsp {
>> + /** @ctx: Invoke caller context for matching request/response */
>> + u64 ctx;
>> + /** @retval: Return value from the remote invocation */
>> + int retval;
>> +};
>> +
>> +/* RPMsg transport layer functions */
>> +int qda_rpmsg_send_msg(struct qda_dev *qdev, struct qda_msg *msg);
>> +int qda_rpmsg_wait_for_rsp(struct qda_fastrpc_invoke_ctx *ctx);
>> +
>> +#endif /* __QDA_RPMSG_H__ */
>> diff --git a/include/uapi/drm/qda_accel.h b/include/uapi/drm/qda_accel.h
>> index 1d699f00e7be..5cf0fec1d91c 100644
>> --- a/include/uapi/drm/qda_accel.h
>> +++ b/include/uapi/drm/qda_accel.h
>> @@ -21,6 +21,8 @@ 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 */
>
> WHY?
I'll move away from this reserved idea in the next version and update it
in order of IOCTLs that are getting enabled.>
>> +#define DRM_QDA_REMOTE_INVOKE 0x07
>>
>> /*
>> * QDA IOCTL definitions
>> @@ -35,6 +37,8 @@ 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_INVOKE DRM_IOWR(DRM_COMMAND_BASE + DRM_QDA_REMOTE_INVOKE, \
>> + struct drm_qda_invoke_args)
>>
>> /* Query type definitions for drm_qda_query */
>> #define QDA_QUERY_DSP_NAME 1
>> @@ -84,6 +88,44 @@ struct drm_qda_gem_mmap_offset {
>> __u32 pad;
>> };
>>
>> +/**
>> + * struct drm_qda_fastrpc_invoke_args - FastRPC invocation argument descriptor
>> + * @ptr: Pointer to argument data (user virtual address)
>
> Why do you need it? Is handle + length not enough? If you want, specify
> offset inside the GEM BO.
The user VA (`ptr`) is needed because userspace mmaps the GEM BO and
then passes pointers into it to the DSP. The kernel derives the offset
within the BO from the VMA (via `calculate_vma_offset()`).
I can check if just passing handle + offset + length works here but that
might require some userspace change.
>
>> + * @length: Length of the argument data in bytes
>> + * @handle: GEM handle for buffer arguments; 0 for scalar arguments
>> + * @attr: Argument attributes and flags
>> + *
>> + * This structure describes a single argument passed to a FastRPC invocation.
>> + * Arguments can be either scalar values or buffer references (via GEM handle).
>> + * Userspace must import any DMA-BUF fd to a GEM handle before populating
>> + * this field; the driver never accepts DMA-BUF fds directly.
>> + */
>> +struct drm_qda_fastrpc_invoke_args {
>> + __u64 ptr;
>> + __u64 length;
>> + __u32 handle;
>> + __u32 attr;
>> +};
>> +
>> +/**
>> + * struct drm_qda_invoke_args - Dynamic FastRPC invocation parameters
>> + * @handle: Remote handle to invoke on the DSP
>> + * @sc: FastRPC scalars value encoding the number of in/out buffers
>> + * @args: User-space pointer to array of drm_qda_fastrpc_invoke_args descriptors;
>> + * the handle field in each entry must be a GEM handle (or 0 for
>> + * inline scalar buffers). Userspace must import DMA-BUF fds to GEM
>
> What is inline scalar buffer? I think, we agreed that everything is a
> GEM BO.
I missed updating this comment, The inline buffer logic is now removed.
I'll fix this.>
>> + * handles before passing them here.
>
> I'd say this is useless. It adds no information. If the driver only
> accepts GEM handles, why do you need to speak about DMA BUFs here?
ack, will update the details properly.>
>> + *
>> + * This structure is used with DRM_IOCTL_QDA_REMOTE_INVOKE to perform a
>> + * dynamic remote procedure call on the DSP. The args pointer must reference
>> + * an array of REMOTE_SCALARS_LENGTH(sc) drm_qda_fastrpc_invoke_args entries.
>
> And how does the user know, what is REMOTE_SCALARS_LENGTH? Define it
> here, please (and start with QDA).
ack.>
>> + */
>> +struct drm_qda_invoke_args {
>> + __u32 handle;
>> + __u32 sc;
>
> Can we place sc with __u8 inargs, __u8 outargs? Then there is no need to
> play with the bytes and talk about REMOTE_SCALARS_LENGTH.
Explained the source of `sc` above, I can correct the comments here.>
>> + __u64 args;
>
> __u64 inargs, __u64 outargs?
>
>> +};
>> +
>> #if defined(__cplusplus)
>> }
>> #endif
>>
>> --
>> 2.34.1
>>
>
next prev parent reply other threads:[~2026-08-20 8:35 UTC|newest]
Thread overview: 65+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-17 4:47 [PATCH v2 00/15] accel/qda: Qualcomm DSP Accelerator driver Ekansh Gupta
2026-08-17 4:47 ` [PATCH v2 01/15] MAINTAINERS: Add entry for Qualcomm DSP Accelerator (QDA) driver Ekansh Gupta
2026-08-18 19:22 ` Krzysztof Kozlowski
2026-08-19 13:05 ` Ekansh Gupta
2026-08-19 14:16 ` Krzysztof Kozlowski
2026-08-20 4:12 ` Ekansh Gupta
2026-08-17 4:47 ` [PATCH v2 02/15] accel/qda: Add QDA driver documentation Ekansh Gupta
2026-08-17 4:47 ` [PATCH v2 03/15] accel/qda: Add initial QDA DRM accelerator driver Ekansh Gupta
2026-08-18 19:10 ` Krzysztof Kozlowski
2026-08-19 13:17 ` Ekansh Gupta
2026-08-19 14:18 ` Krzysztof Kozlowski
2026-08-20 8:52 ` Dmitry Baryshkov
2026-08-20 9:07 ` Krzysztof Kozlowski
2026-08-20 10:07 ` Dmitry Baryshkov
2026-08-20 13:31 ` Krzysztof Kozlowski
2026-08-17 4:47 ` [PATCH v2 04/15] accel/qda: Add compute bus for QDA context banks Ekansh Gupta
2026-08-17 4:47 ` [PATCH v2 05/15] iommu: Add QDA compute context bank bus to iommu_buses Ekansh Gupta
2026-08-17 7:01 ` Joerg Roedel (AMD)
2026-08-17 13:44 ` Jason Gunthorpe
2026-08-18 5:10 ` Ekansh Gupta
2026-08-18 13:07 ` Jason Gunthorpe
2026-08-20 13:17 ` Ekansh Gupta
2026-08-17 4:47 ` [PATCH v2 06/15] accel/qda: Create compute context bank devices on QDA compute bus Ekansh Gupta
2026-08-17 4:47 ` [PATCH v2 07/15] accel/qda: Add memory manager for CB devices Ekansh Gupta
2026-08-17 6:52 ` Dmitry Baryshkov
2026-08-18 4:33 ` Ekansh Gupta
2026-08-18 4:44 ` Dmitry Baryshkov
2026-08-17 4:47 ` [PATCH v2 08/15] accel/qda: Add QUERY IOCTL and QDA UAPI header Ekansh Gupta
2026-08-17 6:58 ` Dmitry Baryshkov
2026-08-18 4:40 ` Ekansh Gupta
2026-08-18 4:45 ` Dmitry Baryshkov
2026-08-17 4:47 ` [PATCH v2 09/15] accel/qda: Add DMA-backed GEM objects and memory manager integration Ekansh Gupta
2026-08-18 3:42 ` Dmitry Baryshkov
2026-08-18 5:51 ` Ekansh Gupta
2026-08-18 3:48 ` Dmitry Baryshkov
2026-08-18 5:52 ` Ekansh Gupta
2026-08-17 4:47 ` [PATCH v2 10/15] accel/qda: Add GEM_CREATE and GEM_MMAP_OFFSET IOCTLs Ekansh Gupta
2026-08-18 3:49 ` Dmitry Baryshkov
2026-08-18 5:54 ` Ekansh Gupta
2026-08-17 4:47 ` [PATCH v2 11/15] accel/qda: Add PRIME DMA-BUF import support Ekansh Gupta
2026-08-18 3:55 ` Dmitry Baryshkov
2026-08-18 6:25 ` Ekansh Gupta
2026-08-17 4:47 ` [PATCH v2 12/15] accel/qda: Add FastRPC invocation support Ekansh Gupta
2026-08-18 4:19 ` Dmitry Baryshkov
2026-08-20 8:35 ` Ekansh Gupta [this message]
2026-08-17 4:47 ` [PATCH v2 13/15] accel/qda: Add DSP process creation and release Ekansh Gupta
2026-08-17 4:47 ` [PATCH v2 14/15] accel/qda: Add remote memory mapping to DSP address space Ekansh Gupta
2026-08-18 19:13 ` [PATCH v2 00/15] accel/qda: Qualcomm DSP Accelerator driver Krzysztof Kozlowski
2026-08-18 19:21 ` Krzysztof Kozlowski
2026-08-19 13:32 ` Ekansh Gupta
2026-08-19 14:19 ` Krzysztof Kozlowski
2026-08-19 13:26 ` Ekansh Gupta
2026-08-19 14:21 ` Krzysztof Kozlowski
2026-08-19 14:38 ` Rob Clark
2026-08-19 14:40 ` Konrad Dybcio
2026-08-19 14:43 ` Krzysztof Kozlowski
2026-08-19 14:49 ` Rob Clark
2026-08-19 14:53 ` Krzysztof Kozlowski
2026-08-19 15:23 ` Rob Clark
2026-08-19 15:27 ` Krzysztof Kozlowski
2026-08-19 15:48 ` Rob Clark
2026-08-20 6:15 ` Krzysztof Kozlowski
2026-08-20 14:47 ` Rob Clark
2026-08-18 19:18 ` Krzysztof Kozlowski
2026-08-19 13:23 ` 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=3f644c83-ffd6-452d-aa81-1c13aaa397ac@oss.qualcomm.com \
--to=ekansh.gupta@oss.qualcomm.com \
--cc=airlied@gmail.com \
--cc=christian.koenig@amd.com \
--cc=corbet@lwn.net \
--cc=dmitry.baryshkov@oss.qualcomm.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=iommu@lists.linux.dev \
--cc=joro@8bytes.org \
--cc=justinstitt@google.com \
--cc=linaro-mm-sig@lists.linaro.org \
--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=llvm@lists.linux.dev \
--cc=maarten.lankhorst@linux.intel.com \
--cc=morbo@google.com \
--cc=mripard@kernel.org \
--cc=nathan@kernel.org \
--cc=ndesaulniers@google.com \
--cc=ogabbay@kernel.org \
--cc=quic_bkumar@quicinc.com \
--cc=quic_chennak@quicinc.com \
--cc=rdunlap@infradead.org \
--cc=robin.murphy@arm.com \
--cc=simona@ffwll.ch \
--cc=skhan@linuxfoundation.org \
--cc=srinivas.kandagatla@oss.qualcomm.com \
--cc=sumit.semwal@linaro.org \
--cc=tzimmermann@suse.de \
--cc=will@kernel.org \
/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