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;