|
23 | 23 | #include <uapi/misc/fastrpc.h> |
24 | 24 | #include <linux/of_reserved_mem.h> |
25 | 25 | #include <linux/bits.h> |
| 26 | +#include <linux/compiler.h> |
| 27 | +#include <linux/iopoll.h> |
26 | 28 |
|
27 | 29 | #define ADSP_DOMAIN_ID (0) |
28 | 30 | #define MDSP_DOMAIN_ID (1) |
|
37 | 39 | #define FASTRPC_CTX_MAX (256) |
38 | 40 | #define FASTRPC_INIT_HANDLE 1 |
39 | 41 | #define FASTRPC_DSP_UTILITIES_HANDLE 2 |
| 42 | +#define FASTRPC_MAX_STATIC_HANDLE (20) |
40 | 43 | #define FASTRPC_CTXID_MASK GENMASK(15, 8) |
41 | 44 | #define INIT_FILELEN_MAX (2 * 1024 * 1024) |
42 | 45 | #define INIT_FILE_NAMELEN_MAX (128) |
|
105 | 108 |
|
106 | 109 | #define miscdev_to_fdevice(d) container_of(d, struct fastrpc_device, miscdev) |
107 | 110 |
|
| 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 | + |
108 | 117 | struct fastrpc_phy_page { |
109 | 118 | dma_addr_t addr; /* dma address */ |
110 | 119 | u64 size; /* size of contiguous region */ |
@@ -235,8 +244,14 @@ struct fastrpc_invoke_ctx { |
235 | 244 | u32 sc; |
236 | 245 | u64 *fdlist; |
237 | 246 | u32 *crc; |
| 247 | + /* Poll memory that DSP updates */ |
| 248 | + u32 *poll; |
238 | 249 | u64 ctxid; |
239 | 250 | 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; |
240 | 255 | struct kref refcount; |
241 | 256 | struct list_head node; /* list of ctxs */ |
242 | 257 | struct completion work; |
@@ -307,6 +322,8 @@ struct fastrpc_user { |
307 | 322 | int client_id; |
308 | 323 | int pd; |
309 | 324 | bool is_secure_dev; |
| 325 | + /* Flags poll mode state */ |
| 326 | + bool poll_mode; |
310 | 327 | /* Lock for lists */ |
311 | 328 | spinlock_t lock; |
312 | 329 | /* lock for allocations */ |
@@ -922,7 +939,8 @@ static int fastrpc_get_meta_size(struct fastrpc_invoke_ctx *ctx) |
922 | 939 | sizeof(struct fastrpc_invoke_buf) + |
923 | 940 | sizeof(struct fastrpc_phy_page)) * ctx->nscalars + |
924 | 941 | sizeof(u64) * FASTRPC_MAX_FDLIST + |
925 | | - sizeof(u32) * FASTRPC_MAX_CRCLIST; |
| 942 | + sizeof(u32) * FASTRPC_MAX_CRCLIST + |
| 943 | + sizeof(u32); |
926 | 944 |
|
927 | 945 | return size; |
928 | 946 | } |
@@ -1018,6 +1036,9 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx) |
1018 | 1036 | list = fastrpc_invoke_buf_start(rpra, ctx->nscalars); |
1019 | 1037 | pages = fastrpc_phy_page_start(list, ctx->nscalars); |
1020 | 1038 | 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 | + |
1021 | 1042 | args = (uintptr_t)ctx->buf->virt + metalen; |
1022 | 1043 | rlen = pkt_size - metalen; |
1023 | 1044 | ctx->rpra = rpra; |
@@ -1186,6 +1207,75 @@ static int fastrpc_invoke_send(struct fastrpc_session_ctx *sctx, |
1186 | 1207 |
|
1187 | 1208 | } |
1188 | 1209 |
|
| 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 | + |
1189 | 1279 | static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel, |
1190 | 1280 | u32 handle, u32 sc, |
1191 | 1281 | struct fastrpc_invoke_args *args) |
@@ -1221,16 +1311,26 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel, |
1221 | 1311 | if (err) |
1222 | 1312 | goto bail; |
1223 | 1313 |
|
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); |
1230 | 1323 |
|
1231 | 1324 | if (err) |
1232 | 1325 | goto bail; |
1233 | 1326 |
|
| 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 | + |
1234 | 1334 | /* make sure that all memory writes by DSP are seen by CPU */ |
1235 | 1335 | dma_rmb(); |
1236 | 1336 | /* populate all the output buffers with results */ |
@@ -1810,6 +1910,30 @@ static int fastrpc_get_info_from_kernel(struct fastrpc_ioctl_capability *cap, |
1810 | 1910 | return 0; |
1811 | 1911 | } |
1812 | 1912 |
|
| 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 | + |
1813 | 1937 | static int fastrpc_get_dsp_info(struct fastrpc_user *fl, char __user *argp) |
1814 | 1938 | { |
1815 | 1939 | struct fastrpc_ioctl_capability cap = {0}; |
@@ -2165,6 +2289,9 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int cmd, |
2165 | 2289 | case FASTRPC_IOCTL_MEM_UNMAP: |
2166 | 2290 | err = fastrpc_req_mem_unmap(fl, argp); |
2167 | 2291 | break; |
| 2292 | + case FASTRPC_IOCTL_SET_OPTION: |
| 2293 | + err = fastrpc_set_option(fl, argp); |
| 2294 | + break; |
2168 | 2295 | case FASTRPC_IOCTL_GET_DSP_INFO: |
2169 | 2296 | err = fastrpc_get_dsp_info(fl, argp); |
2170 | 2297 | break; |
@@ -2516,6 +2643,7 @@ static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data, |
2516 | 2643 | } |
2517 | 2644 |
|
2518 | 2645 | ctx->retval = rsp->retval; |
| 2646 | + ctx->is_work_done = true; |
2519 | 2647 | complete(&ctx->work); |
2520 | 2648 |
|
2521 | 2649 | /* |
|
0 commit comments