diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index c3823ec9bf85..c43358e7a466 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -225,6 +225,7 @@ struct smq_invoke_ctx { struct fastrpc_buf *lbuf; size_t used; struct fastrpc_file *fl; + uint32_t handle; uint32_t sc; struct overlap *overs; struct overlap **overps; @@ -310,6 +311,8 @@ struct fastrpc_apps { spinlock_t ctxlock; struct smq_invoke_ctx *ctxtable[FASTRPC_CTX_MAX]; bool legacy_remote_heap; + struct wakeup_source *wake_source; + unsigned int wake_count; }; struct fastrpc_mmap { @@ -391,6 +394,8 @@ struct fastrpc_file { /* Identifies the device (MINOR_NUM_DEV / MINOR_NUM_SECURE_DEV) */ int dev_minor; char *debug_buf; + /* Flag to enable PM wake/relax voting for every remote invoke */ + int wake_enable; }; static struct fastrpc_apps gfa; @@ -1228,6 +1233,7 @@ static int context_alloc(struct fastrpc_file *fl, uint32_t kernel, goto bail; } ctx->crc = (uint32_t *)invokefd->crc; + ctx->handle = invoke->handle; ctx->sc = invoke->sc; if (bufs) { VERIFY(err, 0 == context_build_overlap(ctx)); @@ -1907,7 +1913,36 @@ static void fastrpc_init(struct fastrpc_apps *me) me->channel[CDSP_DOMAIN_ID].secure = NON_SECURE_CHANNEL; } -static int fastrpc_release_current_dsp_process(struct fastrpc_file *fl); +static inline void fastrpc_pm_awake(int fl_wake_enable, int *wake_enable) +{ + struct fastrpc_apps *me = &gfa; + + if (!fl_wake_enable) + return; + + spin_lock(&me->hlock); + if (!me->wake_count) + __pm_stay_awake(me->wake_source); + me->wake_count++; + spin_unlock(&me->hlock); + *wake_enable = 1; +} + +static inline void fastrpc_pm_relax(int *wake_enable) +{ + struct fastrpc_apps *me = &gfa; + + if (!(*wake_enable)) + return; + + spin_lock(&me->hlock); + if (me->wake_count) + me->wake_count--; + if (!me->wake_count) + __pm_relax(me->wake_source); + spin_unlock(&me->hlock); + *wake_enable = 0; +} static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode, uint32_t kernel, @@ -1916,6 +1951,7 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode, struct smq_invoke_ctx *ctx = NULL; struct fastrpc_ioctl_invoke *invoke = &inv->inv; int err = 0, cid = -1, interrupted = 0; + int wake_enable = 0; struct timespec invoket = {0}; int64_t *perf_counter = NULL; @@ -1932,6 +1968,7 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode, } perf_counter = getperfcounter(fl, PERF_COUNT); + fastrpc_pm_awake(fl->wake_enable, &wake_enable); if (fl->profile) getnstimeofday(&invoket); @@ -1982,14 +2019,15 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode, if (err) goto bail; wait: + fastrpc_pm_relax(&wake_enable); if (kernel) wait_for_completion(&ctx->work); - else { + else interrupted = wait_for_completion_interruptible(&ctx->work); - VERIFY(err, 0 == (err = interrupted)); - if (err) - goto bail; - } + fastrpc_pm_awake(fl->wake_enable, &wake_enable); + VERIFY(err, 0 == (err = interrupted)); + if (err) + goto bail; PERF(fl->profile, GET_COUNTER(perf_counter, PERF_INVARGS), if (!fl->sctx->smmu.coherent) @@ -2027,6 +2065,7 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode, *count = *count+1; } } + fastrpc_pm_relax(&wake_enable); return err; } @@ -2808,9 +2847,12 @@ static int fastrpc_session_alloc_locked(struct fastrpc_channel_ctx *chan, break; } } - VERIFY(err, idx < chan->sesscount); - if (err) + if (idx >= chan->sesscount) { + err = -EUSERS; + pr_err("adsprpc: ERROR %d: %s: max concurrent sessions limit (%d) already reached on %s\n", + err, __func__, chan->sesscount, chan->subsys); goto bail; + } chan->session[idx].smmu.faults = 0; } else { VERIFY(err, me->dev != NULL); @@ -3265,7 +3307,7 @@ static int fastrpc_channel_open(struct fastrpc_file *fl) VERIFY(err, fl && fl->sctx && fl->cid >= 0 && fl->cid < NUM_CHANNELS); if (err) { - pr_err("adsprpc: ERROR: %s: user application %s domain is not set\n", + pr_err("adsprpc: ERROR: %s: kernel session not initialized yet for %s\n", __func__, current->comm); err = -EBADR; return err; @@ -3423,8 +3465,8 @@ static int fastrpc_get_info(struct fastrpc_file *fl, uint32_t *info) fl->cid = cid; fl->ssrcount = fl->apps->channel[cid].ssrcount; mutex_lock(&fl->apps->channel[cid].smd_mutex); - VERIFY(err, !fastrpc_session_alloc_locked( - &fl->apps->channel[cid], 0, &fl->sctx)); + err = fastrpc_session_alloc_locked(&fl->apps->channel[cid], + 0, &fl->sctx); mutex_unlock(&fl->apps->channel[cid].smd_mutex); if (err) goto bail; @@ -3467,8 +3509,11 @@ static int fastrpc_internal_control(struct fastrpc_file *fl, case FASTRPC_CONTROL_KALLOC: cp->kalloc.kalloc_support = 1; break; + case FASTRPC_CONTROL_WAKELOCK: + fl->wake_enable = cp->wp.enable; + break; default: - err = -ENOTTY; + err = -EBADRQC; break; } bail: @@ -4385,11 +4430,19 @@ static int __init fastrpc_device_init(void) err = register_rpmsg_driver(&fastrpc_rpmsg_client); if (err) { - pr_err("adsprpc: register_rpmsg_driver: failed with err %d\n", - err); + pr_err("adsprpc: %s: register_rpmsg_driver failed with err %d\n", + __func__, err); goto device_create_bail; } me->rpmsg_register = 1; + + me->wake_source = wakeup_source_register(NULL, "adsprpc"); + VERIFY(err, !IS_ERR_OR_NULL(me->wake_source)); + if (err) { + pr_err("adsprpc: Error: %s: wakeup_source_register failed with err %d\n", + __func__, PTR_ERR(me->wake_source)); + goto device_create_bail; + } return 0; device_create_bail: for (i = 0; i < NUM_CHANNELS; i++) { @@ -4438,6 +4491,8 @@ static void __exit fastrpc_device_exit(void) unregister_chrdev_region(me->dev_no, NUM_CHANNELS); if (me->rpmsg_register == 1) unregister_rpmsg_driver(&fastrpc_rpmsg_client); + if (me->wake_source) + wakeup_source_unregister(me->wake_source); debugfs_remove_recursive(debugfs_root); } diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h index 91ce793d00aa..43026050135b 100644 --- a/drivers/char/adsprpc_shared.h +++ b/drivers/char/adsprpc_shared.h @@ -241,22 +241,32 @@ struct fastrpc_ioctl_perf { /* kernel performance data */ uintptr_t keys; }; -#define FASTRPC_CONTROL_LATENCY (1) +enum fastrpc_control_type { + FASTRPC_CONTROL_LATENCY = 1, + FASTRPC_CONTROL_SMMU = 2, + FASTRPC_CONTROL_KALLOC = 3, + FASTRPC_CONTROL_WAKELOCK = 4, +}; + struct fastrpc_ctrl_latency { uint32_t enable; /* latency control enable */ uint32_t level; /* level of control */ }; -#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_ctrl_wakelock { + uint32_t enable; /* wakelock control enable */ +}; + struct fastrpc_ioctl_control { uint32_t req; union { struct fastrpc_ctrl_latency lp; struct fastrpc_ctrl_kalloc kalloc; + struct fastrpc_ctrl_wakelock wp; }; };