soc: qcom: scm: Add a noretry variant for scm_call2
scm_call2 can block scm calls up to 2s due to its retry mechanism whenever the secure firmware is busy waiting for certain processing by the client who in turn is waiting upon its scm call to either complete or return with failure. Upon early return, client can process the pending requests to free up secure firmware and unblock processing of all pending scm calls. Add a noretry variant for scm_call2 which can be used by clients who do not intend to wait for 2s for return status. Change-Id: I1f0849464a64c32a4de4510fa5787b0ab328725c Signed-off-by: Kaushal Kumar <kaushalk@codeaurora.org>
This commit is contained in:
parent
b6cce1559b
commit
9fbd3acbf7
2 changed files with 52 additions and 27 deletions
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2010-2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
@ -635,28 +635,7 @@ static int allocate_extra_arg_buffer(struct scm_desc *desc, gfp_t flags)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* scm_call2() - Invoke a syscall in the secure world
|
||||
* @fn_id: The function ID for this syscall
|
||||
* @desc: Descriptor structure containing arguments and return values
|
||||
*
|
||||
* Sends a command to the SCM and waits for the command to finish processing.
|
||||
* This should *only* be called in pre-emptible context.
|
||||
*
|
||||
* A note on cache maintenance:
|
||||
* Note that any buffers that are expected to be accessed by the secure world
|
||||
* must be flushed before invoking scm_call and invalidated in the cache
|
||||
* immediately after scm_call returns. An important point that must be noted
|
||||
* is that on ARMV8 architectures, invalidation actually also causes a dirty
|
||||
* cache line to be cleaned (flushed + unset-dirty-bit). Therefore it is of
|
||||
* paramount importance that the buffer be flushed before invoking scm_call2,
|
||||
* even if you don't care about the contents of that buffer.
|
||||
*
|
||||
* Note that cache maintenance on the argument buffer (desc->args) is taken care
|
||||
* of by scm_call2; however, callers are responsible for any other cached
|
||||
* buffers passed over to the secure world.
|
||||
*/
|
||||
int scm_call2(u32 fn_id, struct scm_desc *desc)
|
||||
static int __scm_call2(u32 fn_id, struct scm_desc *desc, bool retry)
|
||||
{
|
||||
int arglen = desc->arginfo & 0xf;
|
||||
int ret, retry_count = 0;
|
||||
|
@ -670,7 +649,6 @@ int scm_call2(u32 fn_id, struct scm_desc *desc)
|
|||
return ret;
|
||||
|
||||
x0 = fn_id | scm_version_mask;
|
||||
|
||||
do {
|
||||
mutex_lock(&scm_lock);
|
||||
|
||||
|
@ -700,13 +678,15 @@ int scm_call2(u32 fn_id, struct scm_desc *desc)
|
|||
mutex_unlock(&scm_lmh_lock);
|
||||
|
||||
mutex_unlock(&scm_lock);
|
||||
if (!retry)
|
||||
goto out;
|
||||
|
||||
if (ret == SCM_V2_EBUSY)
|
||||
msleep(SCM_EBUSY_WAIT_MS);
|
||||
if (retry_count == 33)
|
||||
pr_warn("scm: secure world has been busy for 1 second!\n");
|
||||
} while (ret == SCM_V2_EBUSY && (retry_count++ < SCM_EBUSY_MAX_RETRY));
|
||||
|
||||
} while (ret == SCM_V2_EBUSY && (retry_count++ < SCM_EBUSY_MAX_RETRY));
|
||||
out:
|
||||
if (ret < 0)
|
||||
pr_err("scm_call failed: func id %#llx, ret: %d, syscall returns: %#llx, %#llx, %#llx\n",
|
||||
x0, ret, desc->ret[0], desc->ret[1], desc->ret[2]);
|
||||
|
@ -717,8 +697,46 @@ int scm_call2(u32 fn_id, struct scm_desc *desc)
|
|||
return scm_remap_error(ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* scm_call2() - Invoke a syscall in the secure world
|
||||
* @fn_id: The function ID for this syscall
|
||||
* @desc: Descriptor structure containing arguments and return values
|
||||
*
|
||||
* Sends a command to the SCM and waits for the command to finish processing.
|
||||
* This should *only* be called in pre-emptible context.
|
||||
*
|
||||
* A note on cache maintenance:
|
||||
* Note that any buffers that are expected to be accessed by the secure world
|
||||
* must be flushed before invoking scm_call and invalidated in the cache
|
||||
* immediately after scm_call returns. An important point that must be noted
|
||||
* is that on ARMV8 architectures, invalidation actually also causes a dirty
|
||||
* cache line to be cleaned (flushed + unset-dirty-bit). Therefore it is of
|
||||
* paramount importance that the buffer be flushed before invoking scm_call2,
|
||||
* even if you don't care about the contents of that buffer.
|
||||
*
|
||||
* Note that cache maintenance on the argument buffer (desc->args) is taken care
|
||||
* of by scm_call2; however, callers are responsible for any other cached
|
||||
* buffers passed over to the secure world.
|
||||
*/
|
||||
int scm_call2(u32 fn_id, struct scm_desc *desc)
|
||||
{
|
||||
return __scm_call2(fn_id, desc, true);
|
||||
}
|
||||
EXPORT_SYMBOL(scm_call2);
|
||||
|
||||
/**
|
||||
* scm_call2_noretry() - Invoke a syscall in the secure world
|
||||
*
|
||||
* Similar to scm_call2 except that there is no retry mechanism
|
||||
* implemented.
|
||||
*/
|
||||
int scm_call2_noretry(u32 fn_id, struct scm_desc *desc)
|
||||
{
|
||||
return __scm_call2(fn_id, desc, false);
|
||||
}
|
||||
EXPORT_SYMBOL(scm_call2_noretry);
|
||||
|
||||
/**
|
||||
* scm_call2_atomic() - Invoke a syscall in the secure world
|
||||
*
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2010-2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
@ -101,6 +101,8 @@ extern int scm_call(u32 svc_id, u32 cmd_id, const void *cmd_buf, size_t cmd_len,
|
|||
|
||||
extern int scm_call2(u32 cmd_id, struct scm_desc *desc);
|
||||
|
||||
extern int scm_call2_noretry(u32 cmd_id, struct scm_desc *desc);
|
||||
|
||||
extern int scm_call2_atomic(u32 cmd_id, struct scm_desc *desc);
|
||||
|
||||
extern int scm_call_noalloc(u32 svc_id, u32 cmd_id, const void *cmd_buf,
|
||||
|
@ -150,6 +152,11 @@ static inline int scm_call2(u32 cmd_id, struct scm_desc *desc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int scm_call2_noretry(u32 cmd_id, struct scm_desc *desc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int scm_call2_atomic(u32 cmd_id, struct scm_desc *desc)
|
||||
{
|
||||
return 0;
|
||||
|
|
Loading…
Add table
Reference in a new issue