Skip to content

Commit 54f1bd4

Browse files
committed
FROMLIST: misc: fastrpc: Add polling mode support for fastRPC driver
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. 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/20260215182136.3995111-5-ekansh.gupta@oss.qualcomm.com/ Signed-off-by: Ekansh Gupta <ekansh.gupta@oss.qualcomm.com>
1 parent fc99f14 commit 54f1bd4

2 files changed

Lines changed: 145 additions & 7 deletions

File tree

drivers/misc/fastrpc.c

Lines changed: 135 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include <uapi/misc/fastrpc.h>
2424
#include <linux/of_reserved_mem.h>
2525
#include <linux/bits.h>
26+
#include <linux/compiler.h>
27+
#include <linux/iopoll.h>
2628

2729
#define ADSP_DOMAIN_ID (0)
2830
#define MDSP_DOMAIN_ID (1)
@@ -37,6 +39,7 @@
3739
#define FASTRPC_CTX_MAX (256)
3840
#define FASTRPC_INIT_HANDLE 1
3941
#define FASTRPC_DSP_UTILITIES_HANDLE 2
42+
#define FASTRPC_MAX_STATIC_HANDLE (20)
4043
#define FASTRPC_CTXID_MASK GENMASK(15, 8)
4144
#define INIT_FILELEN_MAX (2 * 1024 * 1024)
4245
#define INIT_FILE_NAMELEN_MAX (128)
@@ -105,6 +108,12 @@
105108

106109
#define miscdev_to_fdevice(d) container_of(d, struct fastrpc_device, miscdev)
107110

111+
/* Poll response number from remote processor for call completion */
112+
#define FASTRPC_POLL_RESPONSE (0xdecaf)
113+
114+
/* Polling mode timeout limit */
115+
#define FASTRPC_POLL_MAX_TIMEOUT_US (10000)
116+
108117
struct fastrpc_phy_page {
109118
dma_addr_t addr; /* dma address */
110119
u64 size; /* size of contiguous region */
@@ -235,8 +244,14 @@ struct fastrpc_invoke_ctx {
235244
u32 sc;
236245
u64 *fdlist;
237246
u32 *crc;
247+
/* Poll memory that DSP updates */
248+
u32 *poll;
238249
u64 ctxid;
239250
u64 msg_sz;
251+
/* work done status flag */
252+
bool is_work_done;
253+
/* process updates poll memory instead of glink response */
254+
bool is_polled;
240255
struct kref refcount;
241256
struct list_head node; /* list of ctxs */
242257
struct completion work;
@@ -307,6 +322,8 @@ struct fastrpc_user {
307322
int client_id;
308323
int pd;
309324
bool is_secure_dev;
325+
/* Flags poll mode state */
326+
bool poll_mode;
310327
/* Lock for lists */
311328
spinlock_t lock;
312329
/* lock for allocations */
@@ -922,7 +939,8 @@ static int fastrpc_get_meta_size(struct fastrpc_invoke_ctx *ctx)
922939
sizeof(struct fastrpc_invoke_buf) +
923940
sizeof(struct fastrpc_phy_page)) * ctx->nscalars +
924941
sizeof(u64) * FASTRPC_MAX_FDLIST +
925-
sizeof(u32) * FASTRPC_MAX_CRCLIST;
942+
sizeof(u32) * FASTRPC_MAX_CRCLIST +
943+
sizeof(u32);
926944

927945
return size;
928946
}
@@ -1018,6 +1036,9 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx)
10181036
list = fastrpc_invoke_buf_start(rpra, ctx->nscalars);
10191037
pages = fastrpc_phy_page_start(list, ctx->nscalars);
10201038
ctx->fdlist = (u64 *)(pages + ctx->nscalars);
1039+
ctx->poll = (u32 *)((uintptr_t)ctx->fdlist + sizeof(u64) * FASTRPC_MAX_FDLIST +
1040+
sizeof(u32) * FASTRPC_MAX_CRCLIST);
1041+
10211042
args = (uintptr_t)ctx->buf->virt + metalen;
10221043
rlen = pkt_size - metalen;
10231044
ctx->rpra = rpra;
@@ -1186,6 +1207,75 @@ static int fastrpc_invoke_send(struct fastrpc_session_ctx *sctx,
11861207

11871208
}
11881209

1210+
static inline u32 fastrpc_poll_op(void *p)
1211+
{
1212+
struct fastrpc_invoke_ctx *ctx = p;
1213+
1214+
dma_rmb();
1215+
return READ_ONCE(*ctx->poll);
1216+
}
1217+
1218+
static int poll_for_remote_response(struct fastrpc_invoke_ctx *ctx)
1219+
{
1220+
u32 val;
1221+
int ret;
1222+
1223+
/*
1224+
* Poll until DSP writes FASTRPC_POLL_RESPONSE into *ctx->poll
1225+
* or until another path marks the work done.
1226+
*/
1227+
ret = read_poll_timeout_atomic(fastrpc_poll_op, val,
1228+
(val == FASTRPC_POLL_RESPONSE) ||
1229+
ctx->is_work_done, 1,
1230+
FASTRPC_POLL_MAX_TIMEOUT_US, false, ctx);
1231+
1232+
if (!ret && val == FASTRPC_POLL_RESPONSE) {
1233+
ctx->is_work_done = true;
1234+
ctx->retval = 0;
1235+
}
1236+
1237+
if (ret == -ETIMEDOUT)
1238+
ret = -EIO;
1239+
1240+
return ret;
1241+
}
1242+
1243+
static inline int fastrpc_wait_for_response(struct fastrpc_invoke_ctx *ctx,
1244+
u32 kernel)
1245+
{
1246+
int err = 0;
1247+
1248+
if (kernel) {
1249+
if (!wait_for_completion_timeout(&ctx->work, 10 * HZ))
1250+
err = -ETIMEDOUT;
1251+
} else {
1252+
err = wait_for_completion_interruptible(&ctx->work);
1253+
}
1254+
1255+
return err;
1256+
}
1257+
1258+
static int fastrpc_wait_for_completion(struct fastrpc_invoke_ctx *ctx,
1259+
u32 kernel)
1260+
{
1261+
int err;
1262+
1263+
do {
1264+
if (ctx->is_polled) {
1265+
err = poll_for_remote_response(ctx);
1266+
/* If polling timed out, move to normal response mode */
1267+
if (err)
1268+
ctx->is_polled = false;
1269+
} else {
1270+
err = fastrpc_wait_for_response(ctx, kernel);
1271+
if (err)
1272+
return err;
1273+
}
1274+
} while (!ctx->is_work_done);
1275+
1276+
return err;
1277+
}
1278+
11891279
static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel,
11901280
u32 handle, u32 sc,
11911281
struct fastrpc_invoke_args *args)
@@ -1221,16 +1311,26 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel,
12211311
if (err)
12221312
goto bail;
12231313

1224-
if (kernel) {
1225-
if (!wait_for_completion_timeout(&ctx->work, 10 * HZ))
1226-
err = -ETIMEDOUT;
1227-
} else {
1228-
err = wait_for_completion_interruptible(&ctx->work);
1229-
}
1314+
/*
1315+
* Set message context as polled if the call is for a user PD
1316+
* dynamic module and user has enabled poll mode.
1317+
*/
1318+
if (handle > FASTRPC_MAX_STATIC_HANDLE && fl->pd == USER_PD &&
1319+
fl->poll_mode)
1320+
ctx->is_polled = true;
1321+
1322+
err = fastrpc_wait_for_completion(ctx, kernel);
12301323

12311324
if (err)
12321325
goto bail;
12331326

1327+
if (!ctx->is_work_done) {
1328+
err = -ETIMEDOUT;
1329+
dev_dbg(fl->sctx->dev, "Invalid workdone state for handle 0x%x, sc 0x%x\n",
1330+
handle, sc);
1331+
goto bail;
1332+
}
1333+
12341334
/* make sure that all memory writes by DSP are seen by CPU */
12351335
dma_rmb();
12361336
/* populate all the output buffers with results */
@@ -1810,6 +1910,30 @@ static int fastrpc_get_info_from_kernel(struct fastrpc_ioctl_capability *cap,
18101910
return 0;
18111911
}
18121912

1913+
static int fastrpc_set_option(struct fastrpc_user *fl, char __user *argp)
1914+
{
1915+
struct fastrpc_ioctl_set_option opt = {0};
1916+
int i;
1917+
1918+
if (copy_from_user(&opt, argp, sizeof(opt)))
1919+
return -EFAULT;
1920+
1921+
for (i = 0; i < ARRAY_SIZE(opt.reserved); i++) {
1922+
if (opt.reserved[i] != 0)
1923+
return -EINVAL;
1924+
}
1925+
1926+
if (opt.req != FASTRPC_POLL_MODE)
1927+
return -EINVAL;
1928+
1929+
if (opt.value)
1930+
fl->poll_mode = true;
1931+
else
1932+
fl->poll_mode = false;
1933+
1934+
return 0;
1935+
}
1936+
18131937
static int fastrpc_get_dsp_info(struct fastrpc_user *fl, char __user *argp)
18141938
{
18151939
struct fastrpc_ioctl_capability cap = {0};
@@ -2165,6 +2289,9 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int cmd,
21652289
case FASTRPC_IOCTL_MEM_UNMAP:
21662290
err = fastrpc_req_mem_unmap(fl, argp);
21672291
break;
2292+
case FASTRPC_IOCTL_SET_OPTION:
2293+
err = fastrpc_set_option(fl, argp);
2294+
break;
21682295
case FASTRPC_IOCTL_GET_DSP_INFO:
21692296
err = fastrpc_get_dsp_info(fl, argp);
21702297
break;
@@ -2516,6 +2643,7 @@ static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
25162643
}
25172644

25182645
ctx->retval = rsp->retval;
2646+
ctx->is_work_done = true;
25192647
complete(&ctx->work);
25202648

25212649
/*

include/uapi/misc/fastrpc.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#define FASTRPC_IOCTL_INIT_CREATE_STATIC _IOWR('R', 9, struct fastrpc_init_create_static)
1717
#define FASTRPC_IOCTL_MEM_MAP _IOWR('R', 10, struct fastrpc_mem_map)
1818
#define FASTRPC_IOCTL_MEM_UNMAP _IOWR('R', 11, struct fastrpc_mem_unmap)
19+
#define FASTRPC_IOCTL_SET_OPTION _IOWR('R', 12, struct fastrpc_ioctl_set_option)
1920
#define FASTRPC_IOCTL_GET_DSP_INFO _IOWR('R', 13, struct fastrpc_ioctl_capability)
2021

2122
/**
@@ -67,6 +68,9 @@ enum fastrpc_proc_attr {
6768
/* Fastrpc attribute for memory protection of buffers */
6869
#define FASTRPC_ATTR_SECUREMAP (1)
6970

71+
/* Set option request ID to enable poll mode */
72+
#define FASTRPC_POLL_MODE (1)
73+
7074
struct fastrpc_invoke_args {
7175
__u64 ptr;
7276
__u64 length;
@@ -133,6 +137,12 @@ struct fastrpc_mem_unmap {
133137
__s32 reserved[5];
134138
};
135139

140+
struct fastrpc_ioctl_set_option {
141+
__u32 req; /* request id */
142+
__u32 value; /* value */
143+
__s32 reserved[6];
144+
};
145+
136146
struct fastrpc_ioctl_capability {
137147
__u32 unused; /* deprecated, ignored by the kernel */
138148
__u32 attribute_id;

0 commit comments

Comments
 (0)