Loading drivers/char/adsprpc.c +307 −54 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ #include "adsprpc_compat.h" #include "adsprpc_shared.h" #include <soc/qcom/ramdump.h> #include <linux/delay.h> #include <linux/debugfs.h> #include <linux/pm_qos.h> #include <linux/stat.h> Loading Loading @@ -105,6 +106,25 @@ #define FASTRPC_STATIC_HANDLE_MAX (20) #define FASTRPC_LATENCY_CTRL_ENB (1) /* timeout in us for busy polling after early response from remote processor */ #define FASTRPC_EARLY_TIMEOUT (4000) /* timeout for polling for completion signal after user early completion hint */ #define FASTRPC_USER_EARLY_HINT_TIMEOUT (500) /* Early wake up poll completion number received from remote processor */ #define FASTRPC_EARLY_WAKEUP_POLL (0xabbccdde) /* latency in us, early wake up signal used below this value */ #define FASTRPC_EARLY_WAKEUP_LATENCY (200) /* response version number */ #define FASTRPC_RSP_VERSION2 (2) /* CPU feature information to DSP */ #define FASTRPC_CPUINFO_DEFAULT (0) #define FASTRPC_CPUINFO_EARLY_WAKEUP (1) #define INIT_FILELEN_MAX (2*1024*1024) #define INIT_MEMLEN_MAX (8*1024*1024) #define MAX_CACHE_BUF_SIZE (8*1024*1024) Loading Loading @@ -145,6 +165,11 @@ static int fastrpc_pdr_notifier_cb(struct notifier_block *nb, static struct dentry *debugfs_root; static struct dentry *debugfs_global_file; static inline void mem_barrier(void) { __asm__ __volatile__("dmb sy":::"memory"); } static inline uint64_t buf_page_start(uint64_t buf) { uint64_t start = (uint64_t) buf & PAGE_MASK; Loading Loading @@ -241,6 +266,12 @@ struct smq_invoke_ctx { uint32_t *crc; unsigned int magic; uint64_t ctxid; /* response flags from remote processor */ enum fastrpc_response_flags rspFlags; /* user hint of completion time */ uint32_t earlyWakeTime; /* work done status flag */ bool isWorkDone; }; struct fastrpc_ctx_lst { Loading Loading @@ -306,6 +337,9 @@ struct fastrpc_channel_ctx { int secure; struct fastrpc_dsp_capabilities dsp_cap_kernel; void *ipc_log_ctx; /* cpu capabilities shared to DSP */ uint64_t cpuinfo_todsp; bool cpuinfo_status; }; struct fastrpc_apps { Loading Loading @@ -434,6 +468,8 @@ static struct fastrpc_channel_ctx gcinfo[NUM_CHANNELS] = { .cid = ADSP_DOMAIN_ID, } }, .cpuinfo_todsp = FASTRPC_CPUINFO_DEFAULT, .cpuinfo_status = false, }, { .name = "mdsprpc-smd", Loading @@ -443,6 +479,8 @@ static struct fastrpc_channel_ctx gcinfo[NUM_CHANNELS] = { .cid = MDSP_DOMAIN_ID, } }, .cpuinfo_todsp = FASTRPC_CPUINFO_DEFAULT, .cpuinfo_status = false, }, { .name = "sdsprpc-smd", Loading @@ -457,6 +495,8 @@ static struct fastrpc_channel_ctx gcinfo[NUM_CHANNELS] = { .cid = SDSP_DOMAIN_ID, } }, .cpuinfo_todsp = FASTRPC_CPUINFO_DEFAULT, .cpuinfo_status = false, }, { .name = "cdsprpc-smd", Loading @@ -466,6 +506,8 @@ static struct fastrpc_channel_ctx gcinfo[NUM_CHANNELS] = { .cid = CDSP_DOMAIN_ID, } }, .cpuinfo_todsp = FASTRPC_CPUINFO_EARLY_WAKEUP, .cpuinfo_status = false, }, }; Loading Loading @@ -522,6 +564,41 @@ static inline int64_t *getperfcounter(struct fastrpc_file *fl, int key) return val; } static inline int poll_on_early_response(struct smq_invoke_ctx *ctx) { uint32_t ii = 0; uint32_t sc = ctx->sc; struct smq_invoke_buf *list; struct smq_phy_page *pages; uint64_t *fdlist; uint32_t *crclist, *poll; unsigned int inbufs, outbufs, handles; /* calculate poll memory location */ inbufs = REMOTE_SCALARS_INBUFS(sc); outbufs = REMOTE_SCALARS_OUTBUFS(sc); handles = REMOTE_SCALARS_INHANDLES(sc) + REMOTE_SCALARS_OUTHANDLES(sc); list = smq_invoke_buf_start(ctx->rpra, sc); pages = smq_phy_page_start(sc, list); fdlist = (uint64_t *)(pages + inbufs + outbufs + handles); crclist = (uint32_t *)(fdlist + M_FDLIST); poll = (uint32_t *)(crclist + M_CRCLIST); /* poll on memory for actual completion after receiving * early response from DSP. Return failure on timeout. **/ preempt_disable(); for (ii = 0; ii < FASTRPC_EARLY_TIMEOUT; ii++) { mem_barrier(); if (*poll == FASTRPC_EARLY_WAKEUP_POLL) { preempt_enable_no_resched(); return 0; } udelay(1); // busy wait for 1 us } preempt_enable_no_resched(); return -EIO; } static void fastrpc_buf_free(struct fastrpc_buf *buf, int cache) { Loading Loading @@ -1242,6 +1319,8 @@ static int context_alloc(struct fastrpc_file *fl, uint32_t kernel, ctx->tgid = fl->tgid; init_completion(&ctx->work); ctx->magic = FASTRPC_CTX_MAGIC; ctx->rspFlags = NORMAL_RESPONSE; ctx->isWorkDone = false; spin_lock(&fl->hlock); hlist_add_head(&ctx->hn, &clst->pending); Loading Loading @@ -1311,13 +1390,35 @@ static void context_free(struct smq_invoke_ctx *ctx) kfree(ctx); } static void context_notify_user(struct smq_invoke_ctx *ctx, int retval) static void context_notify_user(struct smq_invoke_ctx *ctx, int retval, uint32_t rspFlags, uint32_t earlyWakeTime) { ctx->retval = retval; switch (rspFlags) { case NORMAL_RESPONSE: /* normal response with return value */ ctx->retval = retval; ctx->isWorkDone = true; break; case USER_EARLY_SIGNAL: /* user hint of approximate time of completion */ ctx->earlyWakeTime = earlyWakeTime; break; case EARLY_RESPONSE: /* rpc framework early response with return value */ ctx->retval = retval; break; case COMPLETE_SIGNAL: /* rpc framework signal to clear if pending on ctx */ ctx->isWorkDone = true; break; default: break; } ctx->rspFlags = (enum fastrpc_response_flags)rspFlags; complete(&ctx->work); } static void fastrpc_notify_users(struct fastrpc_file *me) { struct smq_invoke_ctx *ictx; Loading @@ -1325,9 +1426,11 @@ static void fastrpc_notify_users(struct fastrpc_file *me) spin_lock(&me->hlock); hlist_for_each_entry_safe(ictx, n, &me->clst.pending, hn) { ictx->isWorkDone = true; complete(&ictx->work); } hlist_for_each_entry_safe(ictx, n, &me->clst.interrupted, hn) { ictx->isWorkDone = true; complete(&ictx->work); } spin_unlock(&me->hlock); Loading @@ -1341,13 +1444,17 @@ static void fastrpc_notify_users_staticpd_pdr(struct fastrpc_file *me) spin_lock(&me->hlock); hlist_for_each_entry_safe(ictx, n, &me->clst.pending, hn) { if (ictx->msg.pid) if (ictx->msg.pid) { ictx->isWorkDone = true; complete(&ictx->work); } } hlist_for_each_entry_safe(ictx, n, &me->clst.interrupted, hn) { if (ictx->msg.pid) if (ictx->msg.pid) { ictx->isWorkDone = true; complete(&ictx->work); } } spin_unlock(&me->hlock); } Loading Loading @@ -1439,7 +1546,7 @@ static void fastrpc_file_list_dtor(struct fastrpc_apps *me) static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) { remote_arg64_t *rpra, *lrpra; remote_arg64_t *rpra; remote_arg_t *lpra = ctx->lpra; struct smq_invoke_buf *list; struct smq_phy_page *pages, *ipage; Loading @@ -1454,7 +1561,11 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) int mflags = 0; uint64_t *fdlist; uint32_t *crclist; int64_t *perf_counter = getperfcounter(ctx->fl, PERF_COUNT); uint32_t earlyHint; int64_t *perf_counter = NULL; if (ctx->fl->profile) perf_counter = getperfcounter(ctx->fl, PERF_COUNT); /* calculate size of the metadata */ rpra = NULL; Loading Loading @@ -1493,8 +1604,10 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) ipage += 1; } mutex_unlock(&ctx->fl->map_mutex); /* metalen includes meta data, fds, crc and early wakeup hint */ metalen = copylen = (size_t)&ipage[0] + (sizeof(uint64_t) * M_FDLIST) + (sizeof(uint32_t) * M_CRCLIST); (sizeof(uint32_t) * M_CRCLIST) + sizeof(earlyHint); /* allocate new local rpra buffer */ lrpralen = (size_t)&list[0]; Loading @@ -1503,11 +1616,7 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) if (err) goto bail; } if (ctx->lbuf->virt) memset(ctx->lbuf->virt, 0, lrpralen); lrpra = ctx->lbuf->virt; ctx->lrpra = lrpra; ctx->lrpra = ctx->lbuf->virt; /* calculate len required for copying */ for (oix = 0; oix < inbufs + outbufs; ++oix) { Loading Loading @@ -1557,13 +1666,13 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) /* map ion buffers */ PERF(ctx->fl->profile, GET_COUNTER(perf_counter, PERF_MAP), for (i = 0; rpra && lrpra && i < inbufs + outbufs; ++i) { for (i = 0; rpra && i < inbufs + outbufs; ++i) { struct fastrpc_mmap *map = ctx->maps[i]; uint64_t buf = ptr_to_uint64(lpra[i].buf.pv); size_t len = lpra[i].buf.len; rpra[i].buf.pv = lrpra[i].buf.pv = 0; rpra[i].buf.len = lrpra[i].buf.len = len; rpra[i].buf.pv = 0; rpra[i].buf.len = len; if (!len) continue; if (map) { Loading Loading @@ -1591,7 +1700,7 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) pages[idx].addr = map->phys + offset; pages[idx].size = num << PAGE_SHIFT; } rpra[i].buf.pv = lrpra[i].buf.pv = buf; rpra[i].buf.pv = buf; } PERF_END); for (i = bufs; i < bufs + handles; ++i) { Loading @@ -1601,15 +1710,16 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) pages[i].size = map->size; } fdlist = (uint64_t *)&pages[bufs + handles]; for (i = 0; i < M_FDLIST; i++) fdlist[i] = 0; crclist = (uint32_t *)&fdlist[M_FDLIST]; memset(crclist, 0, sizeof(uint32_t)*M_CRCLIST); /* reset fds, crc and early wakeup hint memory */ /* remote process updates these values before responding */ memset(fdlist, 0, sizeof(uint64_t)*M_FDLIST + sizeof(uint32_t)*M_CRCLIST + sizeof(earlyHint)); /* copy non ion buffers */ PERF(ctx->fl->profile, GET_COUNTER(perf_counter, PERF_COPY), rlen = copylen - metalen; for (oix = 0; rpra && lrpra && oix < inbufs + outbufs; ++oix) { for (oix = 0; rpra && oix < inbufs + outbufs; ++oix) { int i = ctx->overps[oix]->raix; struct fastrpc_mmap *map = ctx->maps[i]; size_t mlen; Loading @@ -1628,7 +1738,7 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) VERIFY(err, rlen >= mlen); if (err) goto bail; rpra[i].buf.pv = lrpra[i].buf.pv = rpra[i].buf.pv = (args - ctx->overps[oix]->offset); pages[list[i].pgidx].addr = ctx->buf->phys - ctx->overps[oix]->offset + Loading Loading @@ -1661,7 +1771,7 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) if (map && (map->attr & FASTRPC_ATTR_COHERENT)) continue; if (rpra && lrpra && rpra[i].buf.len && if (rpra && rpra[i].buf.len && ctx->overps[oix]->mstart) { if (map && map->buf) { dma_buf_begin_cpu_access(map->buf, Loading @@ -1675,13 +1785,15 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) } } PERF_END); for (i = bufs; rpra && lrpra && i < bufs + handles; i++) { rpra[i].dma.fd = lrpra[i].dma.fd = ctx->fds[i]; rpra[i].dma.len = lrpra[i].dma.len = (uint32_t)lpra[i].buf.len; rpra[i].dma.offset = lrpra[i].dma.offset = (uint32_t)(uintptr_t)lpra[i].buf.pv; for (i = bufs; rpra && i < bufs + handles; i++) { rpra[i].dma.fd = ctx->fds[i]; rpra[i].dma.len = (uint32_t)lpra[i].buf.len; rpra[i].dma.offset = (uint32_t)(uintptr_t)lpra[i].buf.pv; } /* Copy rpra to local buffer */ if (ctx->lrpra && rpra && lrpralen > 0) memcpy(ctx->lrpra, rpra, lrpralen); bail: return err; } Loading Loading @@ -1904,6 +2016,107 @@ static void fastrpc_init(struct fastrpc_apps *me) static int fastrpc_release_current_dsp_process(struct fastrpc_file *fl); static inline int fastrpc_wait_for_response(struct smq_invoke_ctx *ctx, uint32_t kernel) { int interrupted = 0; if (kernel) wait_for_completion(&ctx->work); else { interrupted = wait_for_completion_interruptible(&ctx->work); } return interrupted; } static void fastrpc_wait_for_completion(struct smq_invoke_ctx *ctx, int *pInterrupted, uint32_t kernel) { int interrupted = 0, err = 0; uint32_t jj; bool wait_resp; uint32_t wTimeout = FASTRPC_USER_EARLY_HINT_TIMEOUT; uint32_t wakeTime = ctx->earlyWakeTime; while (ctx && !ctx->isWorkDone) { switch (ctx->rspFlags) { /* try polling on completion with timeout */ case USER_EARLY_SIGNAL: /* try wait if completion time is less than timeout */ /* disable preempt to avoid context switch latency */ preempt_disable(); jj = 0; wait_resp = false; for (; wakeTime < wTimeout && jj < wTimeout; jj++) { wait_resp = try_wait_for_completion(&ctx->work); if (wait_resp) break; udelay(1); } preempt_enable_no_resched(); if (!wait_resp) { interrupted = fastrpc_wait_for_response(ctx, kernel); *pInterrupted = interrupted; if (interrupted || ctx->isWorkDone) return; } break; /* busy poll on memory for actual job done */ case EARLY_RESPONSE: err = poll_on_early_response(ctx); /* Mark job done if poll on memory successful */ /* Wait for completion if poll on memory timoeut */ if (!err) ctx->isWorkDone = true; else if (!ctx->isWorkDone) { pr_info("poll timeout ctxid 0x%llx\n", ctx->ctxid); interrupted = fastrpc_wait_for_response(ctx, kernel); *pInterrupted = interrupted; if (interrupted || ctx->isWorkDone) return; } break; case COMPLETE_SIGNAL: case NORMAL_RESPONSE: interrupted = fastrpc_wait_for_response(ctx, kernel); *pInterrupted = interrupted; if (interrupted || ctx->isWorkDone) return; break; default: pr_err("adsprpc: unsupported response flags 0x%x\n", ctx->rspFlags); return; } /* end of switch */ } /* end of while loop */ } static void fastrpc_update_invoke_count(uint32_t handle, int64_t *perf_counter, struct timespec *invoket) { /* update invoke count for dynamic handles */ if (handle != FASTRPC_STATIC_HANDLE_LISTENER) { int64_t *count = GET_COUNTER(perf_counter, PERF_INVOKE); if (count) *count += getnstimediff(invoket); } if (handle > FASTRPC_STATIC_HANDLE_MAX) { int64_t *count = GET_COUNTER(perf_counter, PERF_COUNT); if (count) *count += 1; } } static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode, uint32_t kernel, struct fastrpc_ioctl_invoke_crc *inv) Loading @@ -1914,10 +2127,12 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode, int interrupted = 0; int err = 0; struct timespec invoket = {0}; int64_t *perf_counter = getperfcounter(fl, PERF_COUNT); int64_t *perf_counter = NULL; if (fl->profile) if (fl->profile) { perf_counter = getperfcounter(fl, PERF_COUNT); getnstimeofday(&invoket); } if (!kernel) { VERIFY(err, invoke->handle != Loading Loading @@ -1979,14 +2194,14 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode, if (err) goto bail; wait: if (kernel) wait_for_completion(&ctx->work); else { interrupted = wait_for_completion_interruptible(&ctx->work); fastrpc_wait_for_completion(ctx, &interrupted, kernel); VERIFY(err, 0 == (err = interrupted)); if (err) goto bail; } VERIFY(err, ctx->isWorkDone); if (err) goto bail; PERF(fl->profile, GET_COUNTER(perf_counter, PERF_INVARGS), inv_args(ctx); Loading @@ -2009,20 +2224,9 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode, if (fl->ssrcount != fl->apps->channel[cid].ssrcount) err = ECONNRESET; if (fl->profile && !interrupted) { if (invoke->handle != FASTRPC_STATIC_HANDLE_LISTENER) { int64_t *count = GET_COUNTER(perf_counter, PERF_INVOKE); if (count) *count += getnstimediff(&invoket); } if (invoke->handle > FASTRPC_STATIC_HANDLE_MAX) { int64_t *count = GET_COUNTER(perf_counter, PERF_COUNT); if (count) *count = *count+1; } } if (fl->profile && !interrupted) fastrpc_update_invoke_count(invoke->handle, perf_counter, &invoket); return err; } Loading Loading @@ -2337,6 +2541,40 @@ static int fastrpc_kstat(const char *filename, struct kstat *stat) return result; } static int fastrpc_send_cpuinfo_to_dsp(struct fastrpc_file *fl) { int err = 0; uint64_t cpuinfo = 0; struct fastrpc_apps *me = &gfa; struct fastrpc_ioctl_invoke_crc ioctl; remote_arg_t ra[2]; VERIFY(err, fl && fl->cid >= 0 && fl->cid < NUM_CHANNELS); if (err) goto bail; cpuinfo = me->channel[fl->cid].cpuinfo_todsp; /* return success if already updated to remote processor */ if (me->channel[fl->cid].cpuinfo_status) return 0; ra[0].buf.pv = (void *)&cpuinfo; ra[0].buf.len = sizeof(cpuinfo); ioctl.inv.handle = FASTRPC_STATIC_HANDLE_DSP_UTILITIES; ioctl.inv.sc = REMOTE_SCALARS_MAKE(1, 1, 0); ioctl.inv.pra = ra; ioctl.fds = NULL; ioctl.attrs = NULL; ioctl.crc = NULL; fl->pd = 1; err = fastrpc_internal_invoke(fl, FASTRPC_MODE_PARALLEL, 1, &ioctl); if (!err) me->channel[fl->cid].cpuinfo_status = true; bail: return err; } static int fastrpc_get_info_from_dsp(struct fastrpc_file *fl, uint32_t *dsp_attr, uint32_t dsp_attr_size, uint32_t domain) Loading Loading @@ -3056,8 +3294,9 @@ static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data, int len, void *priv, u32 addr) { struct smq_invoke_rsp *rsp = (struct smq_invoke_rsp *)data; struct smq_invoke_rspv2 *rspv2 = NULL; struct fastrpc_apps *me = &gfa; uint32_t index; uint32_t index, flags = 0, earlyWakeTime = 0; int err = 0; VERIFY(err, (rsp && len >= sizeof(*rsp))); Loading @@ -3075,6 +3314,9 @@ static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data, } #endif if (len >= sizeof(struct smq_invoke_rspv2)) rspv2 = (struct smq_invoke_rspv2 *)data; index = (uint32_t)((rsp->ctx & FASTRPC_CTXID_MASK) >> 4); VERIFY(err, index < FASTRPC_CTX_MAX); if (err) Loading @@ -3089,7 +3331,15 @@ static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data, if (err) goto bail; context_notify_user(me->ctxtable[index], rsp->retval); if (rspv2) { VERIFY(err, rspv2->version == FASTRPC_RSP_VERSION2); if (err) goto bail; flags = rspv2->flags; earlyWakeTime = rspv2->earlyWakeTime; } context_notify_user(me->ctxtable[index], rsp->retval, flags, earlyWakeTime); bail: if (err) pr_err("adsprpc: ERROR: %s: invalid response (data %pK, len %d) from remote subsystem (err %d)\n", Loading Loading @@ -3597,7 +3847,7 @@ static int fastrpc_internal_control(struct fastrpc_file *fl, struct fastrpc_ioctl_control *cp) { int err = 0; int latency; unsigned int latency; VERIFY(err, !IS_ERR_OR_NULL(fl) && !IS_ERR_OR_NULL(fl->apps)); if (err) Loading @@ -3619,6 +3869,9 @@ static int fastrpc_internal_control(struct fastrpc_file *fl, fl->qos_request = 1; } else pm_qos_update_request(&fl->pm_qos_req, latency); /* Ensure CPU feature map updated to DSP for early WakeUp */ fastrpc_send_cpuinfo_to_dsp(fl); break; case FASTRPC_CONTROL_KALLOC: cp->kalloc.kalloc_support = 1; Loading drivers/char/adsprpc_compat.c +3 −3 Original line number Diff line number Diff line Loading @@ -122,7 +122,7 @@ struct compat_fastrpc_ioctl_perf { /* kernel performance data */ #define FASTRPC_CONTROL_LATENCY (1) struct compat_fastrpc_ctrl_latency { compat_uint_t enable; /* latency control enable */ compat_uint_t level; /* level of control */ compat_uint_t latency; /* target latency in us */ }; #define FASTRPC_CONTROL_KALLOC (3) Loading Loading @@ -334,8 +334,8 @@ static int compat_get_fastrpc_ioctl_control( if (p == FASTRPC_CONTROL_LATENCY) { err |= get_user(p, &ctrl32->lp.enable); err |= put_user(p, &ctrl->lp.enable); err |= get_user(p, &ctrl32->lp.level); err |= put_user(p, &ctrl->lp.level); err |= get_user(p, &ctrl32->lp.latency); err |= put_user(p, &ctrl->lp.latency); } return err; Loading drivers/char/adsprpc_shared.h +17 −1 Original line number Diff line number Diff line Loading @@ -237,13 +237,14 @@ struct fastrpc_ioctl_perf { /* kernel performance data */ #define FASTRPC_CONTROL_LATENCY (1) struct fastrpc_ctrl_latency { uint32_t enable; /* latency control enable */ uint32_t level; /* level of control */ uint32_t latency; /* latency request in us */ }; #define FASTRPC_CONTROL_KALLOC (3) struct fastrpc_ctrl_kalloc { uint32_t kalloc_support; /* Remote memory allocation from kernel */ }; /* FASTRPC_CONTROL value 2 is reserved in user space */ struct fastrpc_ioctl_control { uint32_t req; Loading Loading @@ -291,6 +292,21 @@ struct smq_invoke_rsp { int retval; /* invoke return value */ }; enum fastrpc_response_flags { NORMAL_RESPONSE = 0, EARLY_RESPONSE = 1, USER_EARLY_SIGNAL = 2, COMPLETE_SIGNAL = 3 }; struct smq_invoke_rspv2 { uint64_t ctx; /* invoke caller context */ int retval; /* invoke return value */ uint32_t flags; /* early response flags */ uint32_t earlyWakeTime; /* user predicted early wakeup time in us */ uint32_t version; /* Version number for validation */ }; static inline struct smq_invoke_buf *smq_invoke_buf_start(remote_arg64_t *pra, uint32_t sc) { Loading Loading
drivers/char/adsprpc.c +307 −54 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ #include "adsprpc_compat.h" #include "adsprpc_shared.h" #include <soc/qcom/ramdump.h> #include <linux/delay.h> #include <linux/debugfs.h> #include <linux/pm_qos.h> #include <linux/stat.h> Loading Loading @@ -105,6 +106,25 @@ #define FASTRPC_STATIC_HANDLE_MAX (20) #define FASTRPC_LATENCY_CTRL_ENB (1) /* timeout in us for busy polling after early response from remote processor */ #define FASTRPC_EARLY_TIMEOUT (4000) /* timeout for polling for completion signal after user early completion hint */ #define FASTRPC_USER_EARLY_HINT_TIMEOUT (500) /* Early wake up poll completion number received from remote processor */ #define FASTRPC_EARLY_WAKEUP_POLL (0xabbccdde) /* latency in us, early wake up signal used below this value */ #define FASTRPC_EARLY_WAKEUP_LATENCY (200) /* response version number */ #define FASTRPC_RSP_VERSION2 (2) /* CPU feature information to DSP */ #define FASTRPC_CPUINFO_DEFAULT (0) #define FASTRPC_CPUINFO_EARLY_WAKEUP (1) #define INIT_FILELEN_MAX (2*1024*1024) #define INIT_MEMLEN_MAX (8*1024*1024) #define MAX_CACHE_BUF_SIZE (8*1024*1024) Loading Loading @@ -145,6 +165,11 @@ static int fastrpc_pdr_notifier_cb(struct notifier_block *nb, static struct dentry *debugfs_root; static struct dentry *debugfs_global_file; static inline void mem_barrier(void) { __asm__ __volatile__("dmb sy":::"memory"); } static inline uint64_t buf_page_start(uint64_t buf) { uint64_t start = (uint64_t) buf & PAGE_MASK; Loading Loading @@ -241,6 +266,12 @@ struct smq_invoke_ctx { uint32_t *crc; unsigned int magic; uint64_t ctxid; /* response flags from remote processor */ enum fastrpc_response_flags rspFlags; /* user hint of completion time */ uint32_t earlyWakeTime; /* work done status flag */ bool isWorkDone; }; struct fastrpc_ctx_lst { Loading Loading @@ -306,6 +337,9 @@ struct fastrpc_channel_ctx { int secure; struct fastrpc_dsp_capabilities dsp_cap_kernel; void *ipc_log_ctx; /* cpu capabilities shared to DSP */ uint64_t cpuinfo_todsp; bool cpuinfo_status; }; struct fastrpc_apps { Loading Loading @@ -434,6 +468,8 @@ static struct fastrpc_channel_ctx gcinfo[NUM_CHANNELS] = { .cid = ADSP_DOMAIN_ID, } }, .cpuinfo_todsp = FASTRPC_CPUINFO_DEFAULT, .cpuinfo_status = false, }, { .name = "mdsprpc-smd", Loading @@ -443,6 +479,8 @@ static struct fastrpc_channel_ctx gcinfo[NUM_CHANNELS] = { .cid = MDSP_DOMAIN_ID, } }, .cpuinfo_todsp = FASTRPC_CPUINFO_DEFAULT, .cpuinfo_status = false, }, { .name = "sdsprpc-smd", Loading @@ -457,6 +495,8 @@ static struct fastrpc_channel_ctx gcinfo[NUM_CHANNELS] = { .cid = SDSP_DOMAIN_ID, } }, .cpuinfo_todsp = FASTRPC_CPUINFO_DEFAULT, .cpuinfo_status = false, }, { .name = "cdsprpc-smd", Loading @@ -466,6 +506,8 @@ static struct fastrpc_channel_ctx gcinfo[NUM_CHANNELS] = { .cid = CDSP_DOMAIN_ID, } }, .cpuinfo_todsp = FASTRPC_CPUINFO_EARLY_WAKEUP, .cpuinfo_status = false, }, }; Loading Loading @@ -522,6 +564,41 @@ static inline int64_t *getperfcounter(struct fastrpc_file *fl, int key) return val; } static inline int poll_on_early_response(struct smq_invoke_ctx *ctx) { uint32_t ii = 0; uint32_t sc = ctx->sc; struct smq_invoke_buf *list; struct smq_phy_page *pages; uint64_t *fdlist; uint32_t *crclist, *poll; unsigned int inbufs, outbufs, handles; /* calculate poll memory location */ inbufs = REMOTE_SCALARS_INBUFS(sc); outbufs = REMOTE_SCALARS_OUTBUFS(sc); handles = REMOTE_SCALARS_INHANDLES(sc) + REMOTE_SCALARS_OUTHANDLES(sc); list = smq_invoke_buf_start(ctx->rpra, sc); pages = smq_phy_page_start(sc, list); fdlist = (uint64_t *)(pages + inbufs + outbufs + handles); crclist = (uint32_t *)(fdlist + M_FDLIST); poll = (uint32_t *)(crclist + M_CRCLIST); /* poll on memory for actual completion after receiving * early response from DSP. Return failure on timeout. **/ preempt_disable(); for (ii = 0; ii < FASTRPC_EARLY_TIMEOUT; ii++) { mem_barrier(); if (*poll == FASTRPC_EARLY_WAKEUP_POLL) { preempt_enable_no_resched(); return 0; } udelay(1); // busy wait for 1 us } preempt_enable_no_resched(); return -EIO; } static void fastrpc_buf_free(struct fastrpc_buf *buf, int cache) { Loading Loading @@ -1242,6 +1319,8 @@ static int context_alloc(struct fastrpc_file *fl, uint32_t kernel, ctx->tgid = fl->tgid; init_completion(&ctx->work); ctx->magic = FASTRPC_CTX_MAGIC; ctx->rspFlags = NORMAL_RESPONSE; ctx->isWorkDone = false; spin_lock(&fl->hlock); hlist_add_head(&ctx->hn, &clst->pending); Loading Loading @@ -1311,13 +1390,35 @@ static void context_free(struct smq_invoke_ctx *ctx) kfree(ctx); } static void context_notify_user(struct smq_invoke_ctx *ctx, int retval) static void context_notify_user(struct smq_invoke_ctx *ctx, int retval, uint32_t rspFlags, uint32_t earlyWakeTime) { ctx->retval = retval; switch (rspFlags) { case NORMAL_RESPONSE: /* normal response with return value */ ctx->retval = retval; ctx->isWorkDone = true; break; case USER_EARLY_SIGNAL: /* user hint of approximate time of completion */ ctx->earlyWakeTime = earlyWakeTime; break; case EARLY_RESPONSE: /* rpc framework early response with return value */ ctx->retval = retval; break; case COMPLETE_SIGNAL: /* rpc framework signal to clear if pending on ctx */ ctx->isWorkDone = true; break; default: break; } ctx->rspFlags = (enum fastrpc_response_flags)rspFlags; complete(&ctx->work); } static void fastrpc_notify_users(struct fastrpc_file *me) { struct smq_invoke_ctx *ictx; Loading @@ -1325,9 +1426,11 @@ static void fastrpc_notify_users(struct fastrpc_file *me) spin_lock(&me->hlock); hlist_for_each_entry_safe(ictx, n, &me->clst.pending, hn) { ictx->isWorkDone = true; complete(&ictx->work); } hlist_for_each_entry_safe(ictx, n, &me->clst.interrupted, hn) { ictx->isWorkDone = true; complete(&ictx->work); } spin_unlock(&me->hlock); Loading @@ -1341,13 +1444,17 @@ static void fastrpc_notify_users_staticpd_pdr(struct fastrpc_file *me) spin_lock(&me->hlock); hlist_for_each_entry_safe(ictx, n, &me->clst.pending, hn) { if (ictx->msg.pid) if (ictx->msg.pid) { ictx->isWorkDone = true; complete(&ictx->work); } } hlist_for_each_entry_safe(ictx, n, &me->clst.interrupted, hn) { if (ictx->msg.pid) if (ictx->msg.pid) { ictx->isWorkDone = true; complete(&ictx->work); } } spin_unlock(&me->hlock); } Loading Loading @@ -1439,7 +1546,7 @@ static void fastrpc_file_list_dtor(struct fastrpc_apps *me) static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) { remote_arg64_t *rpra, *lrpra; remote_arg64_t *rpra; remote_arg_t *lpra = ctx->lpra; struct smq_invoke_buf *list; struct smq_phy_page *pages, *ipage; Loading @@ -1454,7 +1561,11 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) int mflags = 0; uint64_t *fdlist; uint32_t *crclist; int64_t *perf_counter = getperfcounter(ctx->fl, PERF_COUNT); uint32_t earlyHint; int64_t *perf_counter = NULL; if (ctx->fl->profile) perf_counter = getperfcounter(ctx->fl, PERF_COUNT); /* calculate size of the metadata */ rpra = NULL; Loading Loading @@ -1493,8 +1604,10 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) ipage += 1; } mutex_unlock(&ctx->fl->map_mutex); /* metalen includes meta data, fds, crc and early wakeup hint */ metalen = copylen = (size_t)&ipage[0] + (sizeof(uint64_t) * M_FDLIST) + (sizeof(uint32_t) * M_CRCLIST); (sizeof(uint32_t) * M_CRCLIST) + sizeof(earlyHint); /* allocate new local rpra buffer */ lrpralen = (size_t)&list[0]; Loading @@ -1503,11 +1616,7 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) if (err) goto bail; } if (ctx->lbuf->virt) memset(ctx->lbuf->virt, 0, lrpralen); lrpra = ctx->lbuf->virt; ctx->lrpra = lrpra; ctx->lrpra = ctx->lbuf->virt; /* calculate len required for copying */ for (oix = 0; oix < inbufs + outbufs; ++oix) { Loading Loading @@ -1557,13 +1666,13 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) /* map ion buffers */ PERF(ctx->fl->profile, GET_COUNTER(perf_counter, PERF_MAP), for (i = 0; rpra && lrpra && i < inbufs + outbufs; ++i) { for (i = 0; rpra && i < inbufs + outbufs; ++i) { struct fastrpc_mmap *map = ctx->maps[i]; uint64_t buf = ptr_to_uint64(lpra[i].buf.pv); size_t len = lpra[i].buf.len; rpra[i].buf.pv = lrpra[i].buf.pv = 0; rpra[i].buf.len = lrpra[i].buf.len = len; rpra[i].buf.pv = 0; rpra[i].buf.len = len; if (!len) continue; if (map) { Loading Loading @@ -1591,7 +1700,7 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) pages[idx].addr = map->phys + offset; pages[idx].size = num << PAGE_SHIFT; } rpra[i].buf.pv = lrpra[i].buf.pv = buf; rpra[i].buf.pv = buf; } PERF_END); for (i = bufs; i < bufs + handles; ++i) { Loading @@ -1601,15 +1710,16 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) pages[i].size = map->size; } fdlist = (uint64_t *)&pages[bufs + handles]; for (i = 0; i < M_FDLIST; i++) fdlist[i] = 0; crclist = (uint32_t *)&fdlist[M_FDLIST]; memset(crclist, 0, sizeof(uint32_t)*M_CRCLIST); /* reset fds, crc and early wakeup hint memory */ /* remote process updates these values before responding */ memset(fdlist, 0, sizeof(uint64_t)*M_FDLIST + sizeof(uint32_t)*M_CRCLIST + sizeof(earlyHint)); /* copy non ion buffers */ PERF(ctx->fl->profile, GET_COUNTER(perf_counter, PERF_COPY), rlen = copylen - metalen; for (oix = 0; rpra && lrpra && oix < inbufs + outbufs; ++oix) { for (oix = 0; rpra && oix < inbufs + outbufs; ++oix) { int i = ctx->overps[oix]->raix; struct fastrpc_mmap *map = ctx->maps[i]; size_t mlen; Loading @@ -1628,7 +1738,7 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) VERIFY(err, rlen >= mlen); if (err) goto bail; rpra[i].buf.pv = lrpra[i].buf.pv = rpra[i].buf.pv = (args - ctx->overps[oix]->offset); pages[list[i].pgidx].addr = ctx->buf->phys - ctx->overps[oix]->offset + Loading Loading @@ -1661,7 +1771,7 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) if (map && (map->attr & FASTRPC_ATTR_COHERENT)) continue; if (rpra && lrpra && rpra[i].buf.len && if (rpra && rpra[i].buf.len && ctx->overps[oix]->mstart) { if (map && map->buf) { dma_buf_begin_cpu_access(map->buf, Loading @@ -1675,13 +1785,15 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) } } PERF_END); for (i = bufs; rpra && lrpra && i < bufs + handles; i++) { rpra[i].dma.fd = lrpra[i].dma.fd = ctx->fds[i]; rpra[i].dma.len = lrpra[i].dma.len = (uint32_t)lpra[i].buf.len; rpra[i].dma.offset = lrpra[i].dma.offset = (uint32_t)(uintptr_t)lpra[i].buf.pv; for (i = bufs; rpra && i < bufs + handles; i++) { rpra[i].dma.fd = ctx->fds[i]; rpra[i].dma.len = (uint32_t)lpra[i].buf.len; rpra[i].dma.offset = (uint32_t)(uintptr_t)lpra[i].buf.pv; } /* Copy rpra to local buffer */ if (ctx->lrpra && rpra && lrpralen > 0) memcpy(ctx->lrpra, rpra, lrpralen); bail: return err; } Loading Loading @@ -1904,6 +2016,107 @@ static void fastrpc_init(struct fastrpc_apps *me) static int fastrpc_release_current_dsp_process(struct fastrpc_file *fl); static inline int fastrpc_wait_for_response(struct smq_invoke_ctx *ctx, uint32_t kernel) { int interrupted = 0; if (kernel) wait_for_completion(&ctx->work); else { interrupted = wait_for_completion_interruptible(&ctx->work); } return interrupted; } static void fastrpc_wait_for_completion(struct smq_invoke_ctx *ctx, int *pInterrupted, uint32_t kernel) { int interrupted = 0, err = 0; uint32_t jj; bool wait_resp; uint32_t wTimeout = FASTRPC_USER_EARLY_HINT_TIMEOUT; uint32_t wakeTime = ctx->earlyWakeTime; while (ctx && !ctx->isWorkDone) { switch (ctx->rspFlags) { /* try polling on completion with timeout */ case USER_EARLY_SIGNAL: /* try wait if completion time is less than timeout */ /* disable preempt to avoid context switch latency */ preempt_disable(); jj = 0; wait_resp = false; for (; wakeTime < wTimeout && jj < wTimeout; jj++) { wait_resp = try_wait_for_completion(&ctx->work); if (wait_resp) break; udelay(1); } preempt_enable_no_resched(); if (!wait_resp) { interrupted = fastrpc_wait_for_response(ctx, kernel); *pInterrupted = interrupted; if (interrupted || ctx->isWorkDone) return; } break; /* busy poll on memory for actual job done */ case EARLY_RESPONSE: err = poll_on_early_response(ctx); /* Mark job done if poll on memory successful */ /* Wait for completion if poll on memory timoeut */ if (!err) ctx->isWorkDone = true; else if (!ctx->isWorkDone) { pr_info("poll timeout ctxid 0x%llx\n", ctx->ctxid); interrupted = fastrpc_wait_for_response(ctx, kernel); *pInterrupted = interrupted; if (interrupted || ctx->isWorkDone) return; } break; case COMPLETE_SIGNAL: case NORMAL_RESPONSE: interrupted = fastrpc_wait_for_response(ctx, kernel); *pInterrupted = interrupted; if (interrupted || ctx->isWorkDone) return; break; default: pr_err("adsprpc: unsupported response flags 0x%x\n", ctx->rspFlags); return; } /* end of switch */ } /* end of while loop */ } static void fastrpc_update_invoke_count(uint32_t handle, int64_t *perf_counter, struct timespec *invoket) { /* update invoke count for dynamic handles */ if (handle != FASTRPC_STATIC_HANDLE_LISTENER) { int64_t *count = GET_COUNTER(perf_counter, PERF_INVOKE); if (count) *count += getnstimediff(invoket); } if (handle > FASTRPC_STATIC_HANDLE_MAX) { int64_t *count = GET_COUNTER(perf_counter, PERF_COUNT); if (count) *count += 1; } } static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode, uint32_t kernel, struct fastrpc_ioctl_invoke_crc *inv) Loading @@ -1914,10 +2127,12 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode, int interrupted = 0; int err = 0; struct timespec invoket = {0}; int64_t *perf_counter = getperfcounter(fl, PERF_COUNT); int64_t *perf_counter = NULL; if (fl->profile) if (fl->profile) { perf_counter = getperfcounter(fl, PERF_COUNT); getnstimeofday(&invoket); } if (!kernel) { VERIFY(err, invoke->handle != Loading Loading @@ -1979,14 +2194,14 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode, if (err) goto bail; wait: if (kernel) wait_for_completion(&ctx->work); else { interrupted = wait_for_completion_interruptible(&ctx->work); fastrpc_wait_for_completion(ctx, &interrupted, kernel); VERIFY(err, 0 == (err = interrupted)); if (err) goto bail; } VERIFY(err, ctx->isWorkDone); if (err) goto bail; PERF(fl->profile, GET_COUNTER(perf_counter, PERF_INVARGS), inv_args(ctx); Loading @@ -2009,20 +2224,9 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode, if (fl->ssrcount != fl->apps->channel[cid].ssrcount) err = ECONNRESET; if (fl->profile && !interrupted) { if (invoke->handle != FASTRPC_STATIC_HANDLE_LISTENER) { int64_t *count = GET_COUNTER(perf_counter, PERF_INVOKE); if (count) *count += getnstimediff(&invoket); } if (invoke->handle > FASTRPC_STATIC_HANDLE_MAX) { int64_t *count = GET_COUNTER(perf_counter, PERF_COUNT); if (count) *count = *count+1; } } if (fl->profile && !interrupted) fastrpc_update_invoke_count(invoke->handle, perf_counter, &invoket); return err; } Loading Loading @@ -2337,6 +2541,40 @@ static int fastrpc_kstat(const char *filename, struct kstat *stat) return result; } static int fastrpc_send_cpuinfo_to_dsp(struct fastrpc_file *fl) { int err = 0; uint64_t cpuinfo = 0; struct fastrpc_apps *me = &gfa; struct fastrpc_ioctl_invoke_crc ioctl; remote_arg_t ra[2]; VERIFY(err, fl && fl->cid >= 0 && fl->cid < NUM_CHANNELS); if (err) goto bail; cpuinfo = me->channel[fl->cid].cpuinfo_todsp; /* return success if already updated to remote processor */ if (me->channel[fl->cid].cpuinfo_status) return 0; ra[0].buf.pv = (void *)&cpuinfo; ra[0].buf.len = sizeof(cpuinfo); ioctl.inv.handle = FASTRPC_STATIC_HANDLE_DSP_UTILITIES; ioctl.inv.sc = REMOTE_SCALARS_MAKE(1, 1, 0); ioctl.inv.pra = ra; ioctl.fds = NULL; ioctl.attrs = NULL; ioctl.crc = NULL; fl->pd = 1; err = fastrpc_internal_invoke(fl, FASTRPC_MODE_PARALLEL, 1, &ioctl); if (!err) me->channel[fl->cid].cpuinfo_status = true; bail: return err; } static int fastrpc_get_info_from_dsp(struct fastrpc_file *fl, uint32_t *dsp_attr, uint32_t dsp_attr_size, uint32_t domain) Loading Loading @@ -3056,8 +3294,9 @@ static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data, int len, void *priv, u32 addr) { struct smq_invoke_rsp *rsp = (struct smq_invoke_rsp *)data; struct smq_invoke_rspv2 *rspv2 = NULL; struct fastrpc_apps *me = &gfa; uint32_t index; uint32_t index, flags = 0, earlyWakeTime = 0; int err = 0; VERIFY(err, (rsp && len >= sizeof(*rsp))); Loading @@ -3075,6 +3314,9 @@ static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data, } #endif if (len >= sizeof(struct smq_invoke_rspv2)) rspv2 = (struct smq_invoke_rspv2 *)data; index = (uint32_t)((rsp->ctx & FASTRPC_CTXID_MASK) >> 4); VERIFY(err, index < FASTRPC_CTX_MAX); if (err) Loading @@ -3089,7 +3331,15 @@ static int fastrpc_rpmsg_callback(struct rpmsg_device *rpdev, void *data, if (err) goto bail; context_notify_user(me->ctxtable[index], rsp->retval); if (rspv2) { VERIFY(err, rspv2->version == FASTRPC_RSP_VERSION2); if (err) goto bail; flags = rspv2->flags; earlyWakeTime = rspv2->earlyWakeTime; } context_notify_user(me->ctxtable[index], rsp->retval, flags, earlyWakeTime); bail: if (err) pr_err("adsprpc: ERROR: %s: invalid response (data %pK, len %d) from remote subsystem (err %d)\n", Loading Loading @@ -3597,7 +3847,7 @@ static int fastrpc_internal_control(struct fastrpc_file *fl, struct fastrpc_ioctl_control *cp) { int err = 0; int latency; unsigned int latency; VERIFY(err, !IS_ERR_OR_NULL(fl) && !IS_ERR_OR_NULL(fl->apps)); if (err) Loading @@ -3619,6 +3869,9 @@ static int fastrpc_internal_control(struct fastrpc_file *fl, fl->qos_request = 1; } else pm_qos_update_request(&fl->pm_qos_req, latency); /* Ensure CPU feature map updated to DSP for early WakeUp */ fastrpc_send_cpuinfo_to_dsp(fl); break; case FASTRPC_CONTROL_KALLOC: cp->kalloc.kalloc_support = 1; Loading
drivers/char/adsprpc_compat.c +3 −3 Original line number Diff line number Diff line Loading @@ -122,7 +122,7 @@ struct compat_fastrpc_ioctl_perf { /* kernel performance data */ #define FASTRPC_CONTROL_LATENCY (1) struct compat_fastrpc_ctrl_latency { compat_uint_t enable; /* latency control enable */ compat_uint_t level; /* level of control */ compat_uint_t latency; /* target latency in us */ }; #define FASTRPC_CONTROL_KALLOC (3) Loading Loading @@ -334,8 +334,8 @@ static int compat_get_fastrpc_ioctl_control( if (p == FASTRPC_CONTROL_LATENCY) { err |= get_user(p, &ctrl32->lp.enable); err |= put_user(p, &ctrl->lp.enable); err |= get_user(p, &ctrl32->lp.level); err |= put_user(p, &ctrl->lp.level); err |= get_user(p, &ctrl32->lp.latency); err |= put_user(p, &ctrl->lp.latency); } return err; Loading
drivers/char/adsprpc_shared.h +17 −1 Original line number Diff line number Diff line Loading @@ -237,13 +237,14 @@ struct fastrpc_ioctl_perf { /* kernel performance data */ #define FASTRPC_CONTROL_LATENCY (1) struct fastrpc_ctrl_latency { uint32_t enable; /* latency control enable */ uint32_t level; /* level of control */ uint32_t latency; /* latency request in us */ }; #define FASTRPC_CONTROL_KALLOC (3) struct fastrpc_ctrl_kalloc { uint32_t kalloc_support; /* Remote memory allocation from kernel */ }; /* FASTRPC_CONTROL value 2 is reserved in user space */ struct fastrpc_ioctl_control { uint32_t req; Loading Loading @@ -291,6 +292,21 @@ struct smq_invoke_rsp { int retval; /* invoke return value */ }; enum fastrpc_response_flags { NORMAL_RESPONSE = 0, EARLY_RESPONSE = 1, USER_EARLY_SIGNAL = 2, COMPLETE_SIGNAL = 3 }; struct smq_invoke_rspv2 { uint64_t ctx; /* invoke caller context */ int retval; /* invoke return value */ uint32_t flags; /* early response flags */ uint32_t earlyWakeTime; /* user predicted early wakeup time in us */ uint32_t version; /* Version number for validation */ }; static inline struct smq_invoke_buf *smq_invoke_buf_start(remote_arg64_t *pra, uint32_t sc) { Loading