msm: ADSPRPC: Awake PM with a timeout
Awake PM with a timeout in kernel soon after response from DSP to keep the system awake and allow the ioctl call reach user space from kernel space. Change-Id: If518e17ec300565af2d16feca0524e741790ba7f Acked-by: Himateja Reddy <hmreddy@qualcomm.com> Signed-off-by: Anirudh Raghavendra <araghave@codeaurora.org> Signed-off-by: Edgar Flores <edgarf@codeaurora.org>
This commit is contained in:
parent
108427ae28
commit
ece1046cb9
@ -136,6 +136,9 @@
|
||||
#define FASTRPC_STATIC_HANDLE_MAX (20)
|
||||
#define FASTRPC_LATENCY_CTRL_ENB (1)
|
||||
|
||||
/* Maximum PM timeout that can be voted through fastrpc */
|
||||
#define MAX_PM_TIMEOUT_MS 50
|
||||
|
||||
/* timeout in us for busy polling after early response from remote processor */
|
||||
#define FASTRPC_POLL_TIME (4000)
|
||||
|
||||
@ -304,7 +307,6 @@ struct smq_invoke_ctx {
|
||||
uint32_t early_wake_time;
|
||||
/* work done status flag */
|
||||
bool is_work_done;
|
||||
bool pm_awake_voted;
|
||||
/* Store Async job in the context*/
|
||||
struct fastrpc_async_job asyncjob;
|
||||
/* Async early flag to check the state of context */
|
||||
@ -399,11 +401,9 @@ struct fastrpc_apps {
|
||||
bool legacy_remote_heap;
|
||||
/* Unique job id for each message */
|
||||
uint64_t jobid[NUM_CHANNELS];
|
||||
/* Secure subsystems like ADSP/SLPI will use secure client */
|
||||
struct wakeup_source *wake_source_secure;
|
||||
/* Non-secure subsystem like CDSP will use regular client */
|
||||
struct wakeup_source *wake_source;
|
||||
struct gid_list gidlist;
|
||||
struct device *secure_dev;
|
||||
struct device *non_secure_dev;
|
||||
};
|
||||
|
||||
struct fastrpc_mmap {
|
||||
@ -494,6 +494,11 @@ struct fastrpc_file {
|
||||
wait_queue_head_t async_wait_queue;
|
||||
/* IRQ safe spin lock for protecting async queue */
|
||||
spinlock_t aqlock;
|
||||
/* Secure subsystems like ADSP/SLPI will use secure client */
|
||||
struct wakeup_source *wake_source_secure;
|
||||
/* Non-secure subsystem like CDSP will use regular client */
|
||||
struct wakeup_source *wake_source;
|
||||
uint32_t ws_timeout;
|
||||
};
|
||||
|
||||
static struct fastrpc_apps gfa;
|
||||
@ -566,9 +571,7 @@ static struct fastrpc_channel_ctx gcinfo[NUM_CHANNELS] = {
|
||||
static int hlosvm[1] = {VMID_HLOS};
|
||||
static int hlosvmperm[1] = {PERM_READ | PERM_WRITE | PERM_EXEC};
|
||||
|
||||
static void fastrpc_pm_awake(int fl_wake_enable, bool *pm_awake_voted,
|
||||
int channel_type);
|
||||
static void fastrpc_pm_relax(bool *pm_awake_voted, int channel_type);
|
||||
static inline void fastrpc_pm_awake(struct fastrpc_file *fl, int channel_type);
|
||||
|
||||
static inline int64_t getnstimediff(struct timespec64 *start)
|
||||
{
|
||||
@ -1417,7 +1420,6 @@ static int context_alloc(struct fastrpc_file *fl, uint32_t kernel,
|
||||
ctx->magic = FASTRPC_CTX_MAGIC;
|
||||
ctx->rsp_flags = NORMAL_RESPONSE;
|
||||
ctx->is_work_done = false;
|
||||
ctx->pm_awake_voted = false;
|
||||
ctx->copybuf = NULL;
|
||||
ctx->is_early_wakeup = false;
|
||||
if (invokefd->job) {
|
||||
@ -1528,8 +1530,7 @@ static void fastrpc_queue_completed_async_job(struct smq_invoke_ctx *ctx)
|
||||
static void context_notify_user(struct smq_invoke_ctx *ctx,
|
||||
int retval, uint32_t rsp_flags, uint32_t early_wake_time)
|
||||
{
|
||||
fastrpc_pm_awake(ctx->fl->wake_enable, &ctx->pm_awake_voted,
|
||||
gcinfo[ctx->fl->cid].secure);
|
||||
fastrpc_pm_awake(ctx->fl, gcinfo[ctx->fl->cid].secure);
|
||||
ctx->retval = retval;
|
||||
ctx->rsp_flags = (enum fastrpc_response_flags)rsp_flags;
|
||||
trace_fastrpc_context_complete(ctx->fl->cid, (uint64_t)ctx, retval,
|
||||
@ -2207,31 +2208,22 @@ static void fastrpc_init(struct fastrpc_apps *me)
|
||||
me->channel[CDSP_DOMAIN_ID].secure = NON_SECURE_CHANNEL;
|
||||
}
|
||||
|
||||
static inline void fastrpc_pm_awake(int fl_wake_enable, bool *pm_awake_voted,
|
||||
int channel_type)
|
||||
static inline void fastrpc_pm_awake(struct fastrpc_file *fl, int channel_type)
|
||||
{
|
||||
struct fastrpc_apps *me = &gfa;
|
||||
struct wakeup_source *wake_source = NULL;
|
||||
|
||||
if (!fl_wake_enable || *pm_awake_voted)
|
||||
if (!fl->wake_enable || !fl->wake_source || !fl->wake_source_secure)
|
||||
return;
|
||||
/*
|
||||
* Vote with PM to abort any suspend in progress and
|
||||
* keep system awake for specified timeout
|
||||
*/
|
||||
if (channel_type == SECURE_CHANNEL)
|
||||
__pm_stay_awake(me->wake_source_secure);
|
||||
wake_source = fl->wake_source_secure;
|
||||
else if (channel_type == NON_SECURE_CHANNEL)
|
||||
__pm_stay_awake(me->wake_source);
|
||||
*pm_awake_voted = true;
|
||||
}
|
||||
wake_source = fl->wake_source;
|
||||
|
||||
static inline void fastrpc_pm_relax(bool *pm_awake_voted, int channel_type)
|
||||
{
|
||||
struct fastrpc_apps *me = &gfa;
|
||||
|
||||
if (!(*pm_awake_voted))
|
||||
return;
|
||||
if (channel_type == SECURE_CHANNEL)
|
||||
__pm_relax(me->wake_source_secure);
|
||||
else if (channel_type == NON_SECURE_CHANNEL)
|
||||
__pm_relax(me->wake_source);
|
||||
*pm_awake_voted = false;
|
||||
pm_wakeup_ws_event(wake_source, fl->ws_timeout, true);
|
||||
}
|
||||
|
||||
static inline int fastrpc_wait_for_response(struct smq_invoke_ctx *ctx,
|
||||
@ -2378,18 +2370,16 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode,
|
||||
int err = 0, interrupted = 0, cid = fl->cid;
|
||||
struct timespec64 invoket = {0};
|
||||
int64_t *perf_counter = NULL;
|
||||
bool pm_awake_voted = false;
|
||||
bool isasyncinvoke = false;
|
||||
|
||||
VERIFY(err, cid >= ADSP_DOMAIN_ID && cid < NUM_CHANNELS &&
|
||||
fl->sctx != NULL);
|
||||
fl->sctx != NULL);
|
||||
if (err) {
|
||||
pr_err("adsprpc: ERROR: %s: kernel session not initialized yet for %s\n",
|
||||
__func__, current->comm);
|
||||
err = -EBADR;
|
||||
goto bail;
|
||||
}
|
||||
fastrpc_pm_awake(fl->wake_enable, &pm_awake_voted, gcinfo[cid].secure);
|
||||
|
||||
if (fl->profile) {
|
||||
perf_counter = getperfcounter(fl, PERF_COUNT);
|
||||
@ -2449,9 +2439,7 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode,
|
||||
if (isasyncinvoke)
|
||||
goto invoke_end;
|
||||
wait:
|
||||
fastrpc_pm_relax(&pm_awake_voted, gcinfo[cid].secure);
|
||||
fastrpc_wait_for_completion(ctx, &interrupted, kernel, 0);
|
||||
pm_awake_voted = ctx->pm_awake_voted;
|
||||
VERIFY(err, 0 == (err = interrupted));
|
||||
if (err)
|
||||
goto bail;
|
||||
@ -2491,7 +2479,6 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode,
|
||||
if (fl->profile && !interrupted)
|
||||
fastrpc_update_invoke_count(invoke->handle, perf_counter,
|
||||
&invoket);
|
||||
fastrpc_pm_relax(&pm_awake_voted, gcinfo[cid].secure);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -3855,6 +3842,8 @@ static int fastrpc_file_free(struct fastrpc_file *fl)
|
||||
spin_lock(&fl->apps->hlock);
|
||||
hlist_del_init(&fl->hn);
|
||||
spin_unlock(&fl->apps->hlock);
|
||||
wakeup_source_unregister(fl->wake_source);
|
||||
wakeup_source_unregister(fl->wake_source_secure);
|
||||
kfree(fl->debug_buf);
|
||||
kfree(fl->gidlist.gids);
|
||||
|
||||
@ -4199,6 +4188,21 @@ static int fastrpc_channel_open(struct fastrpc_file *fl)
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline void fastrpc_register_wakeup_source(struct device *dev,
|
||||
const char *client_name, struct wakeup_source **device_wake_source)
|
||||
{
|
||||
struct wakeup_source *wake_source;
|
||||
|
||||
wake_source = wakeup_source_register(dev, client_name);
|
||||
if (IS_ERR_OR_NULL(wake_source)) {
|
||||
pr_err("adsprpc: Error: %s: %s: wakeup_source_register failed for %s (%s) with err %ld\n",
|
||||
__func__, current->comm, dev_name(dev),
|
||||
client_name, PTR_ERR(wake_source));
|
||||
return;
|
||||
}
|
||||
*device_wake_source = wake_source;
|
||||
}
|
||||
|
||||
static int fastrpc_device_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
int err = 0;
|
||||
@ -4237,6 +4241,10 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp)
|
||||
debugfs_file = debugfs_create_file(fl->debug_buf, 0644, debugfs_root,
|
||||
fl, &debugfs_fops);
|
||||
|
||||
fastrpc_register_wakeup_source(me->non_secure_dev, "adsprpc-non_secure",
|
||||
&fl->wake_source);
|
||||
fastrpc_register_wakeup_source(me->secure_dev, "adsprpc-secure",
|
||||
&fl->wake_source_secure);
|
||||
context_list_ctor(&fl->clst);
|
||||
spin_lock_init(&fl->hlock);
|
||||
spin_lock_init(&fl->aqlock);
|
||||
@ -4375,8 +4383,26 @@ static int fastrpc_internal_control(struct fastrpc_file *fl,
|
||||
cp->kalloc.kalloc_support = 1;
|
||||
break;
|
||||
case FASTRPC_CONTROL_WAKELOCK:
|
||||
if (fl->dev_minor != MINOR_NUM_SECURE_DEV) {
|
||||
pr_err("adsprpc: %s: %s: PM voting not allowed for non-secure device node %d\n",
|
||||
current->comm, __func__, fl->dev_minor);
|
||||
err = -EPERM;
|
||||
goto bail;
|
||||
}
|
||||
fl->wake_enable = cp->wp.enable;
|
||||
break;
|
||||
case FASTRPC_CONTROL_PM:
|
||||
if (!fl->wake_enable) {
|
||||
/* Kernel PM voting not requested by this application */
|
||||
err = -EACCES;
|
||||
goto bail;
|
||||
}
|
||||
if (cp->pm.timeout > MAX_PM_TIMEOUT_MS)
|
||||
fl->ws_timeout = MAX_PM_TIMEOUT_MS;
|
||||
else
|
||||
fl->ws_timeout = cp->pm.timeout;
|
||||
fastrpc_pm_awake(fl, gcinfo[fl->cid].secure);
|
||||
break;
|
||||
default:
|
||||
err = -EBADRQC;
|
||||
break;
|
||||
@ -5205,8 +5231,6 @@ static struct rpmsg_driver fastrpc_rpmsg_client = {
|
||||
static int __init fastrpc_device_init(void)
|
||||
{
|
||||
struct fastrpc_apps *me = &gfa;
|
||||
struct device *dev = NULL;
|
||||
struct device *secure_dev = NULL;
|
||||
int err = 0, i;
|
||||
|
||||
debugfs_root = debugfs_create_dir("adsprpc", NULL);
|
||||
@ -5237,26 +5261,26 @@ static int __init fastrpc_device_init(void)
|
||||
* Create devices and register with sysfs
|
||||
* Create first device with minor number 0
|
||||
*/
|
||||
dev = device_create(me->class, NULL,
|
||||
me->non_secure_dev = device_create(me->class, NULL,
|
||||
MKDEV(MAJOR(me->dev_no), MINOR_NUM_DEV),
|
||||
NULL, DEVICE_NAME);
|
||||
VERIFY(err, !IS_ERR_OR_NULL(dev));
|
||||
VERIFY(err, !IS_ERR_OR_NULL(me->non_secure_dev));
|
||||
if (err)
|
||||
goto device_create_bail;
|
||||
|
||||
/* Create secure device with minor number for secure device */
|
||||
secure_dev = device_create(me->class, NULL,
|
||||
me->secure_dev = device_create(me->class, NULL,
|
||||
MKDEV(MAJOR(me->dev_no), MINOR_NUM_SECURE_DEV),
|
||||
NULL, DEVICE_NAME_SECURE);
|
||||
VERIFY(err, !IS_ERR_OR_NULL(secure_dev));
|
||||
VERIFY(err, !IS_ERR_OR_NULL(me->secure_dev));
|
||||
if (err)
|
||||
goto device_create_bail;
|
||||
|
||||
for (i = 0; i < NUM_CHANNELS; i++) {
|
||||
me->jobid[i] = 1;
|
||||
me->channel[i].dev = secure_dev;
|
||||
me->channel[i].dev = me->secure_dev;
|
||||
if (i == CDSP_DOMAIN_ID)
|
||||
me->channel[i].dev = dev;
|
||||
me->channel[i].dev = me->non_secure_dev;
|
||||
me->channel[i].ssrcount = 0;
|
||||
me->channel[i].prevssrcount = 0;
|
||||
me->channel[i].issubsystemup = 1;
|
||||
@ -5283,23 +5307,6 @@ static int __init fastrpc_device_init(void)
|
||||
}
|
||||
me->rpmsg_register = 1;
|
||||
|
||||
me->wake_source = wakeup_source_register(dev, "adsprpc-non_secure");
|
||||
VERIFY(err, !IS_ERR_OR_NULL(me->wake_source));
|
||||
if (err) {
|
||||
pr_err("adsprpc: Error: %s: wakeup_source_register failed for %s with err %ld\n",
|
||||
__func__, dev_name(dev), PTR_ERR(me->wake_source));
|
||||
goto device_create_bail;
|
||||
}
|
||||
|
||||
me->wake_source_secure = wakeup_source_register(secure_dev,
|
||||
"adsprpc-secure");
|
||||
VERIFY(err, !IS_ERR_OR_NULL(me->wake_source_secure));
|
||||
if (err) {
|
||||
pr_err("adsprpc: Error: %s: wakeup_source_register failed for %s with err %ld\n",
|
||||
__func__, dev_name(secure_dev),
|
||||
PTR_ERR(me->wake_source_secure));
|
||||
goto device_create_bail;
|
||||
}
|
||||
return 0;
|
||||
device_create_bail:
|
||||
for (i = 0; i < NUM_CHANNELS; i++) {
|
||||
@ -5307,10 +5314,10 @@ static int __init fastrpc_device_init(void)
|
||||
subsys_notif_unregister_notifier(me->channel[i].handle,
|
||||
&me->channel[i].nb);
|
||||
}
|
||||
if (!IS_ERR_OR_NULL(dev))
|
||||
if (!IS_ERR_OR_NULL(me->non_secure_dev))
|
||||
device_destroy(me->class, MKDEV(MAJOR(me->dev_no),
|
||||
MINOR_NUM_DEV));
|
||||
if (!IS_ERR_OR_NULL(secure_dev))
|
||||
if (!IS_ERR_OR_NULL(me->secure_dev))
|
||||
device_destroy(me->class, MKDEV(MAJOR(me->dev_no),
|
||||
MINOR_NUM_SECURE_DEV));
|
||||
class_destroy(me->class);
|
||||
@ -5349,10 +5356,6 @@ 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);
|
||||
if (me->wake_source_secure)
|
||||
wakeup_source_unregister(me->wake_source_secure);
|
||||
kfree(me->gidlist.gids);
|
||||
debugfs_remove_recursive(debugfs_root);
|
||||
}
|
||||
|
@ -148,11 +148,21 @@ struct compat_fastrpc_ctrl_kalloc {
|
||||
compat_uint_t kalloc_support; /* Remote memory allocation from kernel */
|
||||
};
|
||||
|
||||
struct compat_fastrpc_ctrl_wakelock {
|
||||
compat_uint_t enable; /* wakelock control enable */
|
||||
};
|
||||
|
||||
struct compat_fastrpc_ctrl_pm {
|
||||
compat_uint_t timeout; /* timeout(in ms) for PM to keep system awake */
|
||||
};
|
||||
|
||||
struct compat_fastrpc_ioctl_control {
|
||||
compat_uint_t req;
|
||||
union {
|
||||
struct compat_fastrpc_ctrl_latency lp;
|
||||
struct compat_fastrpc_ctrl_kalloc kalloc;
|
||||
struct compat_fastrpc_ctrl_wakelock wp;
|
||||
struct compat_fastrpc_ctrl_pm pm;
|
||||
};
|
||||
};
|
||||
|
||||
@ -493,6 +503,12 @@ static int compat_get_fastrpc_ioctl_control(
|
||||
err |= put_user(p, &ctrl->lp.enable);
|
||||
err |= get_user(p, &ctrl32->lp.latency);
|
||||
err |= put_user(p, &ctrl->lp.latency);
|
||||
} else if (p == FASTRPC_CONTROL_WAKELOCK) {
|
||||
err |= get_user(p, &ctrl32->wp.enable);
|
||||
err |= put_user(p, &ctrl->wp.enable);
|
||||
} else if (p == FASTRPC_CONTROL_PM) {
|
||||
err |= get_user(p, &ctrl32->pm.timeout);
|
||||
err |= put_user(p, &ctrl->pm.timeout);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
@ -282,6 +282,7 @@ enum fastrpc_control_type {
|
||||
FASTRPC_CONTROL_SMMU = 2,
|
||||
FASTRPC_CONTROL_KALLOC = 3,
|
||||
FASTRPC_CONTROL_WAKELOCK = 4,
|
||||
FASTRPC_CONTROL_PM = 5,
|
||||
};
|
||||
|
||||
struct fastrpc_ctrl_latency {
|
||||
@ -297,12 +298,17 @@ struct fastrpc_ctrl_wakelock {
|
||||
uint32_t enable; /* wakelock control enable */
|
||||
};
|
||||
|
||||
struct fastrpc_ctrl_pm {
|
||||
uint32_t timeout; /* timeout(in ms) for PM to keep system awake */
|
||||
};
|
||||
|
||||
struct fastrpc_ioctl_control {
|
||||
uint32_t req;
|
||||
union {
|
||||
struct fastrpc_ctrl_latency lp;
|
||||
struct fastrpc_ctrl_kalloc kalloc;
|
||||
struct fastrpc_ctrl_wakelock wp;
|
||||
struct fastrpc_ctrl_pm pm;
|
||||
};
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user