Linux Documentation
 help / color / mirror / Atom feed
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
>>
> 


  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