Re: [PATCH v8 4/4] misc: fastrpc: Add polling mode support for fastRPC driver
From: Ekansh Gupta
Date: Thu Apr 16 2026 - 10:03:50 EST
On 16-04-2026 13:47, Luben Tuikov wrote:
> Hi Ekansh,
>
> Good work. A couple of notes below:
>
> On 2026-04-15 07:25, Ekansh Gupta wrote:
>> For any remote call to DSP, after sending an invocation message,
>> fastRPC driver waits for glink response and during this time the
>> CPU can go into low power modes. This adds latency to overall fastrpc
>> call as CPU wakeup and scheduling latencies are included. Add polling
>> mode support with which fastRPC driver will poll continuously on a
>> memory after sending a message to remote subsystem which will eliminate
>> CPU wakeup and scheduling latencies and reduce fastRPC overhead. In case
>> poll timeout happens, the call will fallback to normal RPC mode. Poll
>> mode can be enabled by user by using FASTRPC_IOCTL_SET_OPTION ioctl
>> request with FASTRPC_POLL_MODE request id.
>>
>> Signed-off-by: Ekansh Gupta <ekansh.gupta@xxxxxxxxxxxxxxxx>
>> ---
>> drivers/misc/fastrpc.c | 137 ++++++++++++++++++++++++++++++++++--
>> include/uapi/misc/fastrpc.h | 25 +++++++
>> 2 files changed, 155 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c
>> index c4a3547a5c7f..5311a4ba4bb7 100644
>> --- a/drivers/misc/fastrpc.c
>> +++ b/drivers/misc/fastrpc.c
>> @@ -24,6 +24,8 @@
>> #include <linux/of_reserved_mem.h>
>> #include <linux/bits.h>
>> #include <linux/bitops.h>
>> +#include <linux/compiler.h>
>> +#include <linux/iopoll.h>
>>
>> #define ADSP_DOMAIN_ID (0)
>> #define MDSP_DOMAIN_ID (1)
>> @@ -38,6 +40,12 @@
>> #define FASTRPC_CTX_MAX (256)
>> #define FASTRPC_INIT_HANDLE 1
>> #define FASTRPC_DSP_UTILITIES_HANDLE 2
>> +/*
>> + * Maximum handle value for static handles.
>> + * Static handles are pre-defined, fixed numeric values statically assigned
>> + * in the IDL file or FastRPC framework.
>> + */
>> +#define FASTRPC_MAX_STATIC_HANDLE (20)
>> #define FASTRPC_CTXID_MASK GENMASK(15, 8)
>> #define INIT_FILELEN_MAX (2 * 1024 * 1024)
>> #define INIT_FILE_NAMELEN_MAX (128)
>> @@ -106,6 +114,12 @@
>>
>> #define miscdev_to_fdevice(d) container_of(d, struct fastrpc_device, miscdev)
>>
>> +/* Poll response number from remote processor for call completion */
>> +#define FASTRPC_POLL_RESPONSE (0xdecaf)
>> +
>> +/* Polling mode timeout limit */
>> +#define FASTRPC_POLL_MAX_TIMEOUT_US (10000)
>> +
>> struct fastrpc_phy_page {
>> dma_addr_t addr; /* dma address */
>> u64 size; /* size of contiguous region */
>> @@ -236,8 +250,14 @@ struct fastrpc_invoke_ctx {
>> u32 sc;
>> u64 *fdlist;
>> u32 *crc;
>> + /* Poll memory that DSP updates */
>> + u32 *poll;
>
> Perhaps "poll_addr"? "poll" seems just too generic.
ack
>
>> u64 ctxid;
>> u64 msg_sz;
>> + /* work done status flag */
>> + bool is_work_done;
>> + /* process updates poll memory instead of glink response */
>> + bool is_polled;
>> struct kref refcount;
>> struct list_head node; /* list of ctxs */
>> struct completion work;
>> @@ -308,6 +328,8 @@ struct fastrpc_user {
>> int client_id;
>> int pd;
>> bool is_secure_dev;
>> + /* Flags poll mode state */
>> + bool poll_mode;
>> /* Lock for lists */
>> spinlock_t lock;
>> /* lock for allocations */
>> @@ -923,7 +945,8 @@ static int fastrpc_get_meta_size(struct fastrpc_invoke_ctx *ctx)
>> sizeof(struct fastrpc_invoke_buf) +
>> sizeof(struct fastrpc_phy_page)) * ctx->nscalars +
>> sizeof(u64) * FASTRPC_MAX_FDLIST +
>> - sizeof(u32) * FASTRPC_MAX_CRCLIST;
>> + sizeof(u32) * FASTRPC_MAX_CRCLIST +
>> + sizeof(u32);
>>
>> return size;
>> }
>> @@ -1019,6 +1042,9 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
>> list = fastrpc_invoke_buf_start(rpra, ctx->nscalars);
>> pages = fastrpc_phy_page_start(list, ctx->nscalars);
>> ctx->fdlist = (u64 *)(pages + ctx->nscalars);
>> + ctx->poll = (u32 *)((uintptr_t)ctx->fdlist + sizeof(u64) * FASTRPC_MAX_FDLIST +
>> + sizeof(u32) * FASTRPC_MAX_CRCLIST);
>> +
>> args = (uintptr_t)ctx->buf->virt + metalen;
>> rlen = pkt_size - metalen;
>> ctx->rpra = rpra;
>> @@ -1188,6 +1214,74 @@ static int fastrpc_invoke_send(struct fastrpc_session_ctx *sctx,
>>
>> }
>>
>> +static inline u32 fastrpc_poll_op(void *p)
>> +{
>> + struct fastrpc_invoke_ctx *ctx = p;
>> +
>> + dma_rmb();
>> + return READ_ONCE(*ctx->poll);
>
> I think you're better off using readl() here, but see my comment below, which obviates this function.
>
>> +}
>> +
>> +static int poll_for_remote_response(struct fastrpc_invoke_ctx *ctx)
>> +{
>> + u32 val;
>> + int ret;
>> +
>> + /*
>> + * Poll until DSP writes FASTRPC_POLL_RESPONSE into *ctx->poll
>> + * or until another path marks the work done.
>> + */
>> + ret = read_poll_timeout_atomic(fastrpc_poll_op, val,
>> + (val == FASTRPC_POLL_RESPONSE) || ctx->is_work_done, 1,
>> + FASTRPC_POLL_MAX_TIMEOUT_US, false, ctx);
>
> Is there any reason you're not using readl_poll_timeout_atomic() as documented in linux/iopoll.h?
> Does readl() not satisfy the read operation in fastrpc_poll_op()?
I didn't check this, I'll try this out.
>
> How can ctx->is_work_done be updated here? Perhaps you just want to use "val == FASTRPC_POLL_RESPONSE" as a condition here...
That is to handle the possibility that normal response comes while the
polling is ongoing. In that case, the call will get completed by
fastrpc_rpmsg_callback.
>
>> +
>> + if (!ret && val == FASTRPC_POLL_RESPONSE) {
>> + ctx->is_work_done = true;
>> + ctx->retval = 0;
>> + }
>> +
>> + if (ret == -ETIMEDOUT)
>> + ret = -EIO;
>> +
>> + return ret;
>> +}
>> +
>> +static inline int fastrpc_wait_for_response(struct fastrpc_invoke_ctx *ctx,
>> + u32 kernel)
>
> What is "kernel" and why is it a u32 when it is used as a "bool"? Perhaps a better name can be had?
This reflects kernel message. As of now, just propagated the same that
is used across the driver, maybe can address this as a separate patch.
>
>> +{
>> + int err = 0;
>> +
>> + if (kernel) {
>> + if (!wait_for_completion_timeout(&ctx->work, 10 * HZ))
>> + err = -ETIMEDOUT;
>> + } else {
>> + err = wait_for_completion_interruptible(&ctx->work);
>> + }
>> +
>> + return err;
>> +}
>> +
>> +static int fastrpc_wait_for_completion(struct fastrpc_invoke_ctx *ctx,
>> + u32 kernel)
>> +{
>> + int err;
>> +
>> + do {
>> + if (ctx->is_polled) {
>> + err = poll_for_remote_response(ctx);
>> + /* If polling timed out, move to normal response mode */
>> + if (err)
>> + ctx->is_polled = false;
>> + } else {
>> + err = fastrpc_wait_for_response(ctx, kernel);
>> + if (err)
>> + return err;
>> + }
>> + } while (!ctx->is_work_done);
>
> Perhaps you want to also check "err" here to make the exit condition more explicit. (The invariant in do-while loops is generally directly determined by something within the loop and generally not implicit.)
The reason to not keep "err" check is because the call should fallback
to normal response(fastrpc_wait_for_response()) in case
poll_for_remote_response() fails.
>
> Is it possible that in poll_for_remote_response() you get 0 as a poll result and val is not equal to FASTRCPC_POLL_RESPONSE? In such a case, this may hang. (Is a hang desired here?)
That's actually a good point, let me try making it more robust, this
condition might get encountered in case normal response is sent instead
of poll memory update.
>
> Is it possible that if polling is enabled, then you want to poll only once, and if unsuccessful, or successful but "!work_done", then transition to fastrpc_wait_for_response() and return, without looping? (since polling is looping after all...)
This is correct, the intention is the poll until it returns, continue if
successful and fallback to normal response if unsuccessful.
>
>> +
>> + return 0;
>
> "err" is always initialized so you can return "err" here if you exit with "err" as part of the exit condition. (And if you add "!err &&" in the loop invariant, then you don't need (if (err) return err;) after "fastrpc_wait_for_response()").
I'll be keeping this unchanged if I don't end up adding "!err &&" check
here, as err is always going to be zero here as suggested in earlier
version[1].
Thanks, Luben, for taking the time to review this change and for
providing insightful comments.
[1]
https://lore.kernel.org/all/wipphezpxtuuxtwhpwamsmvhwgwuesexmy5ev5pcqb65vov5kz@vuzzyyqnu7ci/
>