From 66e91c428f74002cf0a7b420064fcfdf44c4b7c2 Mon Sep 17 00:00:00 2001 From: Jianping Li Date: Tue, 19 May 2026 16:12:00 +0800 Subject: [PATCH] FROMLIST: misc: fastrpc: Enable poll mode for specific devices Some devices, such as Talos, do not support poll mode, and it is not appropriate to force all devices to start in poll mode in the fastrpc driver. 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. Link: https://lore.kernel.org/all/20260424095903.1622565-5-ekansh.gupta@oss.qualcomm.com/ Signed-off-by: Jianping Li --- drivers/misc/fastrpc.c | 91 +++++++++++++++++++++++++++---------- include/uapi/misc/fastrpc.h | 25 ++++++++++ 2 files changed, 93 insertions(+), 23 deletions(-) diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 92966dd3bb998..afe9b35336103 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -260,6 +260,8 @@ struct fastrpc_invoke_ctx { bool is_work_done; /* response flags from remote processor */ enum fastrpc_response_flags rsp_flags; + /* process updates poll memory instead of glink response */ + bool is_polled; struct kref refcount; struct list_head node; /* list of ctxs */ struct completion work; @@ -304,6 +306,7 @@ struct fastrpc_channel_ctx { bool secure; bool unsigned_support; u64 dma_mask; + bool poll_mode_supported; }; struct fastrpc_device { @@ -325,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 */ @@ -1268,28 +1273,15 @@ static int fastrpc_wait_for_completion(struct fastrpc_invoke_ctx *ctx, { int err; - do { - switch (ctx->rsp_flags) { - case NORMAL_RESPONSE: - err = fastrpc_wait_for_response(ctx, kernel); - if (err || ctx->is_work_done) - return err; - break; - case POLL_MODE: - err = poll_for_remote_response(ctx); - /* If polling timed out, move to normal response mode */ - if (err) - ctx->rsp_flags = NORMAL_RESPONSE; - break; - default: - err = -EBADR; - dev_dbg(ctx->fl->sctx->dev, - "unsupported response type:0x%x\n", ctx->rsp_flags); - break; - } - } while (!ctx->is_work_done); + if (ctx->is_polled) { + err = poll_for_remote_response(ctx); + if (!err) + return 0; + /* If polling timed out or failed, move to normal response mode */ + ctx->is_polled = false; + } - return err; + return fastrpc_wait_for_response(ctx, kernel); } static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel, @@ -1327,8 +1319,13 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel, if (err) goto bail; - if (handle > FASTRPC_MAX_STATIC_HANDLE && fl->pd == USER_PD) - ctx->rsp_flags = POLL_MODE; + /* + * Set message context as polled if the call is for a user PD + * dynamic module and user has enabled poll mode. + */ + if (handle > FASTRPC_MAX_STATIC_HANDLE && fl->pd == USER_PD && + fl->poll_mode) + ctx->is_polled = true; err = fastrpc_wait_for_completion(ctx, kernel); if (err) @@ -1891,6 +1888,33 @@ static int fastrpc_get_info_from_kernel(struct fastrpc_ioctl_capability *cap, return 0; } +static int fastrpc_set_option(struct fastrpc_user *fl, char __user *argp) +{ + struct fastrpc_ioctl_set_option opt = { 0 }; + int i; + + if (copy_from_user(&opt, argp, sizeof(opt))) + return -EFAULT; + + for (i = 0; i < ARRAY_SIZE(opt.reserved); i++) { + if (opt.reserved[i] != 0) + return -EINVAL; + } + + if (opt.request_id != FASTRPC_POLL_MODE) + return -EINVAL; + + if (opt.value) { + if (!fl->cctx->poll_mode_supported) + return -EOPNOTSUPP; + fl->poll_mode = true; + } else { + fl->poll_mode = false; + } + + return 0; +} + static int fastrpc_get_dsp_info(struct fastrpc_user *fl, char __user *argp) { struct fastrpc_ioctl_capability cap = {0}; @@ -2254,6 +2278,9 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int cmd, case FASTRPC_IOCTL_MEM_UNMAP: err = fastrpc_req_mem_unmap(fl, argp); break; + case FASTRPC_IOCTL_SET_OPTION: + err = fastrpc_set_option(fl, argp); + break; case FASTRPC_IOCTL_GET_DSP_INFO: err = fastrpc_get_dsp_info(fl, argp); break; @@ -2400,6 +2427,21 @@ static int fastrpc_get_domain_id(const char *domain) return -EINVAL; } +/* + * Exception list for legacy platforms whose DSP firmware supports + * FastRPC polling mode. + * + * NOTE: This list is intentionally closed. + * Do NOT add new platforms here. New SoCs must advertise polling mode + * support via their soc_data. + */ + +static const char *const fastrpc_poll_supported_machines[] = { + "qcom,milos", "qcom,qcs8300", "qcom,sa8775p", "qcom,sar2130p", + "qcom,sm8450", "qcom,sm8550", "qcom,sm8650", "qcom,sm8750", + "qcom,x1e80100", "qcom,x1p42100", NULL, +}; + static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) { struct device *rdev = &rpdev->dev; @@ -2471,6 +2513,9 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) secure_dsp = !(of_property_read_bool(rdev->of_node, "qcom,non-secure-domain")); data->secure = secure_dsp; + data->poll_mode_supported = + of_machine_compatible_match(fastrpc_poll_supported_machines); + switch (domain_id) { case ADSP_DOMAIN_ID: case MDSP_DOMAIN_ID: diff --git a/include/uapi/misc/fastrpc.h b/include/uapi/misc/fastrpc.h index c6e2925f47e69..6cbe845138e07 100644 --- a/include/uapi/misc/fastrpc.h +++ b/include/uapi/misc/fastrpc.h @@ -16,6 +16,7 @@ #define FASTRPC_IOCTL_INIT_CREATE_STATIC _IOWR('R', 9, struct fastrpc_init_create_static) #define FASTRPC_IOCTL_MEM_MAP _IOWR('R', 10, struct fastrpc_mem_map) #define FASTRPC_IOCTL_MEM_UNMAP _IOWR('R', 11, struct fastrpc_mem_unmap) +#define FASTRPC_IOCTL_SET_OPTION _IOWR('R', 12, struct fastrpc_ioctl_set_option) #define FASTRPC_IOCTL_GET_DSP_INFO _IOWR('R', 13, struct fastrpc_ioctl_capability) /** @@ -67,6 +68,24 @@ enum fastrpc_proc_attr { /* Fastrpc attribute for memory protection of buffers */ #define FASTRPC_ATTR_SECUREMAP (1) +/** + * FASTRPC_POLL_MODE - Enable/disable poll mode for FastRPC invocations + * + * Poll mode is an optimization that allows the CPU to poll shared memory + * for completion instead of waiting for an interrupt-based response. + * This reduces latency for fast-completing operations. + * + * Restrictions: + * - Only supported for USER_PD (User Protection Domain) + * - Only applies to dynamic modules (handle > 20) + * - Static modules always use interrupt-based completion + * + * Values: + * - 0: Disable poll mode (use interrupt-based completion) + * - 1: Enable poll mode (poll shared memory for completion) + */ +#define FASTRPC_POLL_MODE (1) + struct fastrpc_invoke_args { __u64 ptr; __u64 length; @@ -133,6 +152,12 @@ struct fastrpc_mem_unmap { __s32 reserved[5]; }; +struct fastrpc_ioctl_set_option { + __u32 request_id; /* Request type (e.g., FASTRPC_POLL_MODE) */ + __u32 value; /* Request-specific value */ + __s32 reserved[6]; +}; + struct fastrpc_ioctl_capability { __u32 unused; /* deprecated, ignored by the kernel */ __u32 attribute_id;