|
22 | 22 | #include <linux/firmware/qcom/qcom_scm.h> |
23 | 23 | #include <uapi/misc/fastrpc.h> |
24 | 24 | #include <linux/of_reserved_mem.h> |
| 25 | +#include <linux/compiler.h> |
| 26 | +#include <linux/iopoll.h> |
25 | 27 | #include <linux/bitfield.h> |
26 | 28 |
|
27 | 29 | #define ADSP_DOMAIN_ID (0) |
|
38 | 40 | #define FASTRPC_CTX_MAX (256) |
39 | 41 | #define FASTRPC_INIT_HANDLE 1 |
40 | 42 | #define FASTRPC_DSP_UTILITIES_HANDLE 2 |
| 43 | +#define FASTRPC_MAX_STATIC_HANDLE (20) |
41 | 44 | #define FASTRPC_CTXID_MASK GENMASK(15, 8) |
42 | 45 | #define INIT_FILELEN_MAX (2 * 1024 * 1024) |
43 | 46 | #define INIT_FILE_NAMELEN_MAX (128) |
|
106 | 109 |
|
107 | 110 | #define miscdev_to_fdevice(d) container_of(d, struct fastrpc_device, miscdev) |
108 | 111 |
|
| 112 | +/* Poll response number from remote processor for call completion */ |
| 113 | +#define FASTRPC_POLL_RESPONSE (0xdecaf) |
| 114 | + |
| 115 | +/* Polling mode timeout limit */ |
| 116 | +#define FASTRPC_POLL_MAX_TIMEOUT_US (10000) |
| 117 | + |
109 | 118 | struct fastrpc_phy_page { |
110 | 119 | u64 addr; /* physical address */ |
111 | 120 | u64 size; /* size of contiguous region */ |
@@ -236,8 +245,14 @@ struct fastrpc_invoke_ctx { |
236 | 245 | u32 sc; |
237 | 246 | u64 *fdlist; |
238 | 247 | u32 *crc; |
| 248 | + /* Poll memory that DSP updates */ |
| 249 | + u32 *poll; |
239 | 250 | u64 ctxid; |
240 | 251 | u64 msg_sz; |
| 252 | + /* work done status flag */ |
| 253 | + bool is_work_done; |
| 254 | + /* process updates poll memory instead of glink response */ |
| 255 | + bool is_polled; |
241 | 256 | struct kref refcount; |
242 | 257 | struct list_head node; /* list of ctxs */ |
243 | 258 | struct completion work; |
@@ -301,6 +316,8 @@ struct fastrpc_user { |
301 | 316 | int client_id; |
302 | 317 | int pd; |
303 | 318 | bool is_secure_dev; |
| 319 | + /* Flags poll mode state */ |
| 320 | + bool poll_mode; |
304 | 321 | /* Lock for lists */ |
305 | 322 | spinlock_t lock; |
306 | 323 | /* lock for allocations */ |
@@ -894,7 +911,8 @@ static int fastrpc_get_meta_size(struct fastrpc_invoke_ctx *ctx) |
894 | 911 | sizeof(struct fastrpc_invoke_buf) + |
895 | 912 | sizeof(struct fastrpc_phy_page)) * ctx->nscalars + |
896 | 913 | sizeof(u64) * FASTRPC_MAX_FDLIST + |
897 | | - sizeof(u32) * FASTRPC_MAX_CRCLIST; |
| 914 | + sizeof(u32) * FASTRPC_MAX_CRCLIST + |
| 915 | + sizeof(u32); |
898 | 916 |
|
899 | 917 | return size; |
900 | 918 | } |
@@ -990,6 +1008,7 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx) |
990 | 1008 | list = fastrpc_invoke_buf_start(rpra, ctx->nscalars); |
991 | 1009 | pages = fastrpc_phy_page_start(list, ctx->nscalars); |
992 | 1010 | ctx->fdlist = (u64 *)(pages + ctx->nscalars); |
| 1011 | + ctx->poll = (u32 *)(ctx->fdlist + FASTRPC_MAX_FDLIST + FASTRPC_MAX_CRCLIST); |
993 | 1012 | args = (uintptr_t)ctx->buf->virt + metalen; |
994 | 1013 | rlen = pkt_size - metalen; |
995 | 1014 | ctx->rpra = rpra; |
@@ -1158,6 +1177,75 @@ static int fastrpc_invoke_send(struct fastrpc_session_ctx *sctx, |
1158 | 1177 |
|
1159 | 1178 | } |
1160 | 1179 |
|
| 1180 | +static inline u32 fastrpc_poll_op(void *p) |
| 1181 | +{ |
| 1182 | + struct fastrpc_invoke_ctx *ctx = p; |
| 1183 | + |
| 1184 | + dma_rmb(); |
| 1185 | + return READ_ONCE(*ctx->poll); |
| 1186 | +} |
| 1187 | + |
| 1188 | +static int poll_for_remote_response(struct fastrpc_invoke_ctx *ctx) |
| 1189 | +{ |
| 1190 | + u32 val; |
| 1191 | + int ret; |
| 1192 | + |
| 1193 | + /* |
| 1194 | + * Poll until DSP writes FASTRPC_POLL_RESPONSE into *ctx->poll |
| 1195 | + * or until another path marks the work done. |
| 1196 | + */ |
| 1197 | + ret = read_poll_timeout_atomic(fastrpc_poll_op, val, |
| 1198 | + (val == FASTRPC_POLL_RESPONSE) || |
| 1199 | + ctx->is_work_done, 1, |
| 1200 | + FASTRPC_POLL_MAX_TIMEOUT_US, false, ctx); |
| 1201 | + |
| 1202 | + if (!ret && val == FASTRPC_POLL_RESPONSE) { |
| 1203 | + ctx->is_work_done = true; |
| 1204 | + ctx->retval = 0; |
| 1205 | + } |
| 1206 | + |
| 1207 | + if (ret == -ETIMEDOUT) |
| 1208 | + ret = -EIO; |
| 1209 | + |
| 1210 | + return ret; |
| 1211 | +} |
| 1212 | + |
| 1213 | +static inline int fastrpc_wait_for_response(struct fastrpc_invoke_ctx *ctx, |
| 1214 | + u32 kernel) |
| 1215 | +{ |
| 1216 | + int err = 0; |
| 1217 | + |
| 1218 | + if (kernel) { |
| 1219 | + if (!wait_for_completion_timeout(&ctx->work, 10 * HZ)) |
| 1220 | + err = -ETIMEDOUT; |
| 1221 | + } else { |
| 1222 | + err = wait_for_completion_interruptible(&ctx->work); |
| 1223 | + } |
| 1224 | + |
| 1225 | + return err; |
| 1226 | +} |
| 1227 | + |
| 1228 | +static int fastrpc_wait_for_completion(struct fastrpc_invoke_ctx *ctx, |
| 1229 | + u32 kernel) |
| 1230 | +{ |
| 1231 | + int err; |
| 1232 | + |
| 1233 | + do { |
| 1234 | + if (ctx->is_polled) { |
| 1235 | + err = poll_for_remote_response(ctx); |
| 1236 | + /* If polling timed out, move to normal response mode */ |
| 1237 | + if (err) |
| 1238 | + ctx->is_polled = false; |
| 1239 | + } else { |
| 1240 | + err = fastrpc_wait_for_response(ctx, kernel); |
| 1241 | + if (err) |
| 1242 | + return err; |
| 1243 | + } |
| 1244 | + } while (!ctx->is_work_done); |
| 1245 | + |
| 1246 | + return err; |
| 1247 | +} |
| 1248 | + |
1161 | 1249 | static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel, |
1162 | 1250 | u32 handle, u32 sc, |
1163 | 1251 | struct fastrpc_invoke_args *args) |
@@ -1193,16 +1281,25 @@ static int fastrpc_internal_invoke(struct fastrpc_user *fl, u32 kernel, |
1193 | 1281 | if (err) |
1194 | 1282 | goto bail; |
1195 | 1283 |
|
1196 | | - if (kernel) { |
1197 | | - if (!wait_for_completion_timeout(&ctx->work, 10 * HZ)) |
1198 | | - err = -ETIMEDOUT; |
1199 | | - } else { |
1200 | | - err = wait_for_completion_interruptible(&ctx->work); |
1201 | | - } |
| 1284 | + /* |
| 1285 | + * Set message context as polled if the call is for a user PD |
| 1286 | + * dynamic module and user has enabled poll mode. |
| 1287 | + */ |
| 1288 | + if (handle > FASTRPC_MAX_STATIC_HANDLE && fl->pd == USER_PD && |
| 1289 | + fl->poll_mode) |
| 1290 | + ctx->is_polled = true; |
| 1291 | + |
| 1292 | + err = fastrpc_wait_for_completion(ctx, kernel); |
1202 | 1293 |
|
1203 | 1294 | if (err) |
1204 | 1295 | goto bail; |
1205 | 1296 |
|
| 1297 | + if (!ctx->is_work_done) { |
| 1298 | + err = -ETIMEDOUT; |
| 1299 | + dev_dbg(fl->sctx->dev, "Invalid workdone state for handle 0x%x, sc 0x%x\n", |
| 1300 | + handle, sc); |
| 1301 | + goto bail; |
| 1302 | + } |
1206 | 1303 | /* make sure that all memory writes by DSP are seen by CPU */ |
1207 | 1304 | dma_rmb(); |
1208 | 1305 | /* populate all the output buffers with results */ |
@@ -1780,6 +1877,30 @@ static int fastrpc_get_info_from_kernel(struct fastrpc_ioctl_capability *cap, |
1780 | 1877 | return 0; |
1781 | 1878 | } |
1782 | 1879 |
|
| 1880 | +static int fastrpc_set_option(struct fastrpc_user *fl, char __user *argp) |
| 1881 | +{ |
| 1882 | + struct fastrpc_ioctl_set_option opt = {0}; |
| 1883 | + int i; |
| 1884 | + |
| 1885 | + if (copy_from_user(&opt, argp, sizeof(opt))) |
| 1886 | + return -EFAULT; |
| 1887 | + |
| 1888 | + for (i = 0; i < ARRAY_SIZE(opt.reserved); i++) { |
| 1889 | + if (opt.reserved[i] != 0) |
| 1890 | + return -EINVAL; |
| 1891 | + } |
| 1892 | + |
| 1893 | + if (opt.req != FASTRPC_POLL_MODE) |
| 1894 | + return -EINVAL; |
| 1895 | + |
| 1896 | + if (opt.value) |
| 1897 | + fl->poll_mode = true; |
| 1898 | + else |
| 1899 | + fl->poll_mode = false; |
| 1900 | + |
| 1901 | + return 0; |
| 1902 | +} |
| 1903 | + |
1783 | 1904 | static int fastrpc_get_dsp_info(struct fastrpc_user *fl, char __user *argp) |
1784 | 1905 | { |
1785 | 1906 | struct fastrpc_ioctl_capability cap = {0}; |
@@ -2134,6 +2255,9 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int cmd, |
2134 | 2255 | case FASTRPC_IOCTL_MEM_UNMAP: |
2135 | 2256 | err = fastrpc_req_mem_unmap(fl, argp); |
2136 | 2257 | break; |
| 2258 | + case FASTRPC_IOCTL_SET_OPTION: |
| 2259 | + err = fastrpc_set_option(fl, argp); |
| 2260 | + break; |
2137 | 2261 | case FASTRPC_IOCTL_GET_DSP_INFO: |
2138 | 2262 | err = fastrpc_get_dsp_info(fl, argp); |
2139 | 2263 | break; |
@@ -2465,6 +2589,7 @@ static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data, |
2465 | 2589 |
|
2466 | 2590 | ctx->retval = rsp->retval; |
2467 | 2591 | complete(&ctx->work); |
| 2592 | + ctx->is_work_done = true; |
2468 | 2593 |
|
2469 | 2594 | /* |
2470 | 2595 | * The DMA buffer associated with the context cannot be freed in |
|
0 commit comments