Merge "firmware: qcom_scm: Add trace points to scm driver"

This commit is contained in:
qctecmdr 2019-12-01 22:30:24 -08:00 • committed by Gerrit - the friendly Code Review server
commit ddbed2ec05
7 changed files with 49 additions and 812 deletions

View file

@ -1,4 +1,3 @@
CONFIG_QCOM_SECURE_CHAN_MANAGER=y
CONFIG_QCOM_IOMMU_IO_PGTABLE_QUIRKS=y
CONFIG_IOMMU_DEBUGFS=y
CONFIG_QCOM_LAZY_MAPPING=y

View file

@ -19,6 +19,9 @@
#include "qcom_scm.h"
#define CREATE_TRACE_POINTS
#include <trace/events/scm.h>
#define MAX_QCOM_SCM_ARGS 10
#define MAX_QCOM_SCM_RETS 3
@ -169,10 +172,15 @@ static void __qcom_scm_call_do_quirk(const struct arm_smccc_args *smc,
struct arm_smccc_res *res)
{
unsigned long a0 = smc->a[0];
ktime_t time;
const bool trace = trace_scm_call_enabled();
struct arm_smccc_quirk quirk = { .id = ARM_SMCCC_QUIRK_QCOM_A6 };
quirk.state.a6 = 0;
if (trace)
time = ktime_get();
do {
arm_smccc_smc_quirk(a0, smc->a[1], smc->a[2], smc->a[3],
smc->a[4], smc->a[5], quirk.state.a6,
@ -182,6 +190,9 @@ static void __qcom_scm_call_do_quirk(const struct arm_smccc_args *smc,
a0 = res->a0;
} while (res->a0 == QCOM_SCM_INTERRUPTED);
if (trace)
trace_scm_call(smc->a, res, ktime_us_delta(ktime_get(), time));
}
static int qcom_scm_call_smccc(struct device *dev,
@ -261,9 +272,7 @@ static int qcom_scm_call_smccc(struct device *dev,
do {
mutex_lock(&qcom_scm_lock);
__qcom_scm_call_do_quirk(&smc, &res);
mutex_unlock(&qcom_scm_lock);
if (res.a0 == QCOM_SCM_V2_EBUSY) {
@ -329,10 +338,19 @@ static inline void *legacy_get_response_buffer(
static void __qcom_scm_call_do(const struct arm_smccc_args *smc,
struct arm_smccc_res *res)
{
ktime_t time;
const bool trace = trace_scm_call_enabled();
if (trace)
time = ktime_get();
do {
arm_smccc_smc(smc->a[0], smc->a[1], smc->a[2], smc->a[3],
smc->a[4], smc->a[5], smc->a[6], smc->a[7], res);
} while (res->a0 == QCOM_SCM_INTERRUPTED);
if (trace)
trace_scm_call(smc->a, res, ktime_us_delta(ktime_get(), time));
}
/**
@ -438,6 +456,8 @@ static int qcom_scm_call_atomic_legacy(struct device *dev,
struct arm_smccc_args smc = {{0}};
struct arm_smccc_res res;
size_t i, arglen = desc->arginfo & 0xf;
const bool trace = trace_scm_call_enabled();
ktime_t time;
BUG_ON(arglen > LEGACY_ATOMIC_N_REG_ARGS);
@ -447,9 +467,14 @@ static int qcom_scm_call_atomic_legacy(struct device *dev,
for (i = 0; i < arglen; i++)
smc.a[i + LEGACY_ATOMIC_FIRST_REG_IDX] = desc->args[i];
if (trace)
time = ktime_get();
arm_smccc_smc(smc.a[0], smc.a[1], smc.a[2], smc.a[3],
smc.a[4], smc.a[5], smc.a[6], smc.a[7], &res);
if (trace)
trace_scm_call(smc.a, &res, ktime_us_delta(ktime_get(), time));
desc->res[0] = res.a1;
desc->res[1] = res.a2;
desc->res[2] = res.a3;

View file

@ -370,14 +370,6 @@ config QCOM_APR
used by audio driver to configure QDSP6
ASM, ADM and AFE modules.
config QCOM_SECURE_CHAN_MANAGER
tristate "Secure Channel Manager (SCM) support"
help
Say y or m here to enable Secure Channel Mananger (SCM)
support for Qualcomm SoC. SCM provides communication
channel to communicate with secure world (EL2 and EL3)
by using smc call.
config QCOM_SECURE_BUFFER
tristate "Helper functions for secure buffers through TZ"
depends on QCOM_SCM

View file

@ -28,8 +28,6 @@ obj-$(CONFIG_QCOM_SMP2P) += smp2p.o
obj-$(CONFIG_QSEE_IPC_IRQ_BRIDGE) += qsee_ipc_irq_bridge.o
obj-$(CONFIG_QCOM_SMSM) += smsm.o
obj-$(CONFIG_MSM_CORE_HANG_DETECT) += core_hang_detect.o
CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1, -Wno-asm-operand-widths)
obj-$(CONFIG_QCOM_SECURE_CHAN_MANAGER) += scm.o
obj-$(CONFIG_QCOM_SECURE_BUFFER) += secure_buffer.o
obj-$(CONFIG_QCOM_SOCINFO) += socinfo.o
obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o

View file

@ -1,623 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2010-2019, The Linux Foundation. All rights reserved.
*/
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
#include <soc/qcom/scm.h>
#define CREATE_TRACE_POINTS
#include <trace/events/scm.h>
#ifdef CONFIG_ARM64
/*
* This is used to ensure the compiler did actually allocate the register we
* asked it for some inline assembly sequences. Apparently we can't trust the
* compiler from one version to another so a bit of paranoia won't hurt. This
* string is meant to be concatenated with the inline asm string and will
* cause compilation to stop on mismatch. (for details, see gcc PR 15089)
*/
#define __asmeq(x, y) ".ifnc " x "," y " ; .err ; .endif\n\t"
#else
#include <asm/compiler.h>
#include <asm/cacheflush.h>
#endif
#define SCM_ENOMEM -9
#define SCM_EINVAL_ADDR -3
#define SCM_EINVAL_ARG -2
#define SCM_ERROR -1
#define SCM_INTERRUPTED 1
#define SCM_V2_EBUSY -12
static DEFINE_MUTEX(scm_lock);
#define SCM_EBUSY_WAIT_MS 30
#define SCM_EBUSY_MAX_RETRY 67
#define N_EXT_SCM_ARGS 7
#define FIRST_EXT_ARG_IDX 3
#define SMC_ATOMIC_SYSCALL 31
#define N_REGISTER_ARGS (MAX_SCM_ARGS - N_EXT_SCM_ARGS + 1)
#define SMC64_MASK 0x40000000
#define SMC_ATOMIC_MASK 0x80000000
#define IS_CALL_AVAIL_CMD 1
#ifdef CONFIG_ARM64
#define R0_STR "x0"
#define R1_STR "x1"
#define R2_STR "x2"
#define R3_STR "x3"
#define R4_STR "x4"
#define R5_STR "x5"
#define R6_STR "x6"
/* Outer caches unsupported on ARM64 platforms */
#define outer_flush_range(x, y)
#else
#define R0_STR "r0"
#define R1_STR "r1"
#define R2_STR "r2"
#define R3_STR "r3"
#define R4_STR "r4"
#define R5_STR "r5"
#define R6_STR "r6"
#endif
static struct device *qcom_scm_dev;
struct scm_dma_buf {
size_t size;
dma_addr_t extra_arg_buf_phy;
};
static int scm_remap_error(int err)
{
switch (err) {
case SCM_ERROR:
return -EOPNOTSUPP;
case SCM_EINVAL_ADDR:
case SCM_EINVAL_ARG:
return -EINVAL;
case SCM_ENOMEM:
return -ENOMEM;
case SCM_V2_EBUSY:
return -EBUSY;
}
return -EINVAL;
}
#ifdef CONFIG_ARM64
static int __scm_call_armv8_64(u64 x0, u64 x1, u64 x2, u64 x3, u64 x4, u64 x5,
u64 *ret1, u64 *ret2, u64 *ret3)
{
register u64 r0 asm("x0") = x0;
register u64 r1 asm("x1") = x1;
register u64 r2 asm("x2") = x2;
register u64 r3 asm("x3") = x3;
register u64 r4 asm("x4") = x4;
register u64 r5 asm("x5") = x5;
register u64 r6 asm("x6") = 0;
do {
asm volatile(
__asmeq("%0", R0_STR)
__asmeq("%1", R1_STR)
__asmeq("%2", R2_STR)
__asmeq("%3", R3_STR)
__asmeq("%4", R4_STR)
__asmeq("%5", R5_STR)
__asmeq("%6", R6_STR)
__asmeq("%7", R0_STR)
__asmeq("%8", R1_STR)
__asmeq("%9", R2_STR)
__asmeq("%10", R3_STR)
__asmeq("%11", R4_STR)
__asmeq("%12", R5_STR)
__asmeq("%13", R6_STR)
#ifdef REQUIRES_SEC
".arch_extension sec\n"
#endif
"smc #0\n"
: "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3),
"=r" (r4), "=r" (r5), "=r" (r6)
: "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4),
"r" (r5), "r" (r6)
: "x7", "x8", "x9", "x10", "x11", "x12", "x13",
"x14", "x15", "x16", "x17");
} while (r0 == SCM_INTERRUPTED);
if (ret1)
*ret1 = r1;
if (ret2)
*ret2 = r2;
if (ret3)
*ret3 = r3;
return r0;
}
static int __scm_call_armv8_32(u32 w0, u32 w1, u32 w2, u32 w3, u32 w4, u32 w5,
u64 *ret1, u64 *ret2, u64 *ret3)
{
register u32 r0 asm("w0") = w0;
register u32 r1 asm("w1") = w1;
register u32 r2 asm("w2") = w2;
register u32 r3 asm("w3") = w3;
register u32 r4 asm("w4") = w4;
register u32 r5 asm("w5") = w5;
register u32 r6 asm("w6") = 0;
do {
asm volatile(
__asmeq("%0", R0_STR)
__asmeq("%1", R1_STR)
__asmeq("%2", R2_STR)
__asmeq("%3", R3_STR)
__asmeq("%4", R4_STR)
__asmeq("%5", R5_STR)
__asmeq("%6", R6_STR)
__asmeq("%7", R0_STR)
__asmeq("%8", R1_STR)
__asmeq("%9", R2_STR)
__asmeq("%10", R3_STR)
__asmeq("%11", R4_STR)
__asmeq("%12", R5_STR)
__asmeq("%13", R6_STR)
#ifdef REQUIRES_SEC
".arch_extension sec\n"
#endif
"smc #0\n"
: "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3),
"=r" (r4), "=r" (r5), "=r" (r6)
: "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4),
"r" (r5), "r" (r6)
: "x7", "x8", "x9", "x10", "x11", "x12", "x13",
"x14", "x15", "x16", "x17");
} while (r0 == SCM_INTERRUPTED);
if (ret1)
*ret1 = r1;
if (ret2)
*ret2 = r2;
if (ret3)
*ret3 = r3;
return r0;
}
#else
static int __scm_call_armv8_32(u32 w0, u32 w1, u32 w2, u32 w3, u32 w4, u32 w5,
u64 *ret1, u64 *ret2, u64 *ret3)
{
register u32 r0 asm("r0") = w0;
register u32 r1 asm("r1") = w1;
register u32 r2 asm("r2") = w2;
register u32 r3 asm("r3") = w3;
register u32 r4 asm("r4") = w4;
register u32 r5 asm("r5") = w5;
register u32 r6 asm("r6") = 0;
do {
asm volatile(
__asmeq("%0", R0_STR)
__asmeq("%1", R1_STR)
__asmeq("%2", R2_STR)
__asmeq("%3", R3_STR)
__asmeq("%4", R4_STR)
__asmeq("%5", R5_STR)
__asmeq("%6", R6_STR)
__asmeq("%7", R0_STR)
__asmeq("%8", R1_STR)
__asmeq("%9", R2_STR)
__asmeq("%10", R3_STR)
__asmeq("%11", R4_STR)
__asmeq("%12", R5_STR)
__asmeq("%13", R6_STR)
#ifdef REQUIRES_SEC
".arch_extension sec\n"
#endif
"smc #0\n"
: "=r" (r0), "=r" (r1), "=r" (r2), "=r" (r3),
"=r" (r4), "=r" (r5), "=r" (r6)
: "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4),
"r" (r5), "r" (r6));
} while (r0 == SCM_INTERRUPTED);
if (ret1)
*ret1 = r1;
if (ret2)
*ret2 = r2;
if (ret3)
*ret3 = r3;
return r0;
}
static int __scm_call_armv8_64(u64 x0, u64 x1, u64 x2, u64 x3, u64 x4, u64 x5,
u64 *ret1, u64 *ret2, u64 *ret3)
{
return 0;
}
#endif
struct scm_extra_arg {
union {
u32 args32[N_EXT_SCM_ARGS];
u64 args64[N_EXT_SCM_ARGS];
};
};
static enum scm_interface_version {
SCM_UNKNOWN,
SCM_LEGACY,
SCM_ARMV8_32,
SCM_ARMV8_64,
} scm_version = SCM_UNKNOWN;
/* This will be set to specify SMC32 or SMC64 */
static u32 scm_version_mask;
static noinline bool is_scm_armv8(void)
{
int ret;
u64 ret1, x0;
if (likely(scm_version != SCM_UNKNOWN))
return (scm_version == SCM_ARMV8_32) ||
(scm_version == SCM_ARMV8_64);
/*
* This is a one time check that runs on the first ever
* invocation of is_scm_armv8. We might be called in atomic
* context so no mutexes etc. Also, we can't use the scm_call2
* or scm_call2_APIs directly since they depend on this init.
*/
/* First try a SMC64 call */
scm_version = SCM_ARMV8_64;
ret1 = 0;
x0 = SCM_SIP_FNID(SCM_SVC_INFO, IS_CALL_AVAIL_CMD) | SMC_ATOMIC_MASK;
ret = __scm_call_armv8_64(x0 | SMC64_MASK, SCM_ARGS(1), x0, 0, 0, 0,
&ret1, NULL, NULL);
if (ret || !ret1) {
/* Try SMC32 call */
ret1 = 0;
ret = __scm_call_armv8_32(x0, SCM_ARGS(1), x0, 0, 0, 0,
&ret1, NULL, NULL);
if (ret || !ret1)
return -ENODEV;
scm_version = SCM_ARMV8_32;
} else
scm_version_mask = SMC64_MASK;
pr_debug("scm_call: scm version is %x, mask is %x\n", scm_version,
scm_version_mask);
return (scm_version == SCM_ARMV8_32) ||
(scm_version == SCM_ARMV8_64);
}
/*
* If there are more than N_REGISTER_ARGS, allocate a buffer and place
* the additional arguments in it. The extra argument buffer will be
* pointed to by X5.
*/
static int allocate_extra_arg_buffer(struct scm_desc *desc,
struct scm_dma_buf *scm_dma_buf, gfp_t flags)
{
int i, j;
struct scm_extra_arg *argbuf;
dma_addr_t argbuf_phy;
int arglen = desc->arginfo & 0xf;
size_t argbuflen = PAGE_ALIGN(sizeof(struct scm_extra_arg));
desc->x5 = desc->args[FIRST_EXT_ARG_IDX];
if (likely(arglen <= N_REGISTER_ARGS)) {
desc->extra_arg_buf = NULL;
return 0;
}
if (!qcom_scm_dev)
return -EPROBE_DEFER;
argbuf = kzalloc(argbuflen, flags);
if (!argbuf)
return -ENOMEM;
desc->extra_arg_buf = argbuf;
j = FIRST_EXT_ARG_IDX;
if (scm_version == SCM_ARMV8_64)
for (i = 0; i < N_EXT_SCM_ARGS; i++)
argbuf->args64[i] = desc->args[j++];
else
for (i = 0; i < N_EXT_SCM_ARGS; i++)
argbuf->args32[i] = desc->args[j++];
desc->x5 = virt_to_phys(argbuf);
argbuf_phy = dma_map_single(qcom_scm_dev, argbuf,
argbuflen, DMA_TO_DEVICE);
if (dma_mapping_error(qcom_scm_dev, argbuf_phy)) {
kfree(argbuf);
return -ENOMEM;
}
scm_dma_buf->extra_arg_buf_phy = argbuf_phy;
scm_dma_buf->size = argbuflen;
outer_flush_range(virt_to_phys(argbuf),
virt_to_phys(argbuf) + argbuflen);
return 0;
}
static int __scm_call2(u32 fn_id, struct scm_desc *desc, bool retry)
{
int arglen = desc->arginfo & 0xf;
int ret, retry_count = 0;
u64 x0;
struct scm_dma_buf scm_dma_buf = {0};
ret = allocate_extra_arg_buffer(desc, &scm_dma_buf, GFP_NOIO);
if (ret)
return ret;
x0 = fn_id | scm_version_mask;
trace_scm_call_start(x0, desc);
do {
mutex_lock(&scm_lock);
desc->ret[0] = desc->ret[1] = desc->ret[2] = 0;
if (scm_version == SCM_ARMV8_64)
ret = __scm_call_armv8_64(x0, desc->arginfo,
desc->args[0], desc->args[1],
desc->args[2], desc->x5,
&desc->ret[0], &desc->ret[1],
&desc->ret[2]);
else
ret = __scm_call_armv8_32(x0, desc->arginfo,
desc->args[0], desc->args[1],
desc->args[2], desc->x5,
&desc->ret[0], &desc->ret[1],
&desc->ret[2]);
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));
out:
trace_scm_call_end(desc);
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]);
if (arglen > N_REGISTER_ARGS) {
dma_unmap_single(qcom_scm_dev, scm_dma_buf.extra_arg_buf_phy,
scm_dma_buf.size, DMA_TO_DEVICE);
kfree(desc->extra_arg_buf);
}
if (ret < 0)
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
*
* Similar to scm_call2 except that this can be invoked in atomic context.
* There is also no retry mechanism implemented. Please ensure that the
* secure world syscall can be executed in such a context and can complete
* in a timely manner.
*/
int scm_call2_atomic(u32 fn_id, struct scm_desc *desc)
{
int arglen = desc->arginfo & 0xf;
int ret;
u64 x0;
struct scm_dma_buf scm_dma_buf = {0};
ret = allocate_extra_arg_buffer(desc, &scm_dma_buf, GFP_ATOMIC);
if (ret)
return ret;
x0 = fn_id | BIT(SMC_ATOMIC_SYSCALL) | scm_version_mask;
trace_scm_call_start(x0, desc);
if (scm_version == SCM_ARMV8_64)
ret = __scm_call_armv8_64(x0, desc->arginfo, desc->args[0],
desc->args[1], desc->args[2],
desc->x5, &desc->ret[0],
&desc->ret[1], &desc->ret[2]);
else
ret = __scm_call_armv8_32(x0, desc->arginfo, desc->args[0],
desc->args[1], desc->args[2],
desc->x5, &desc->ret[0],
&desc->ret[1], &desc->ret[2]);
trace_scm_call_end(desc);
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]);
if (arglen > N_REGISTER_ARGS) {
dma_unmap_single(qcom_scm_dev, scm_dma_buf.extra_arg_buf_phy,
scm_dma_buf.size, DMA_TO_DEVICE);
kfree(desc->extra_arg_buf);
}
if (ret < 0)
return scm_remap_error(ret);
return ret;
}
EXPORT_SYMBOL(scm_call2_atomic);
#define SCM_IO_READ 0x1
#define SCM_IO_WRITE 0x2
u32 scm_io_read(phys_addr_t address)
{
struct scm_desc desc = {
.args[0] = address,
.arginfo = SCM_ARGS(1),
};
scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_IO, SCM_IO_READ), &desc);
return desc.ret[0];
}
EXPORT_SYMBOL(scm_io_read);
int scm_io_write(phys_addr_t address, u32 val)
{
int ret;
struct scm_desc desc = {
.args[0] = address,
.args[1] = val,
.arginfo = SCM_ARGS(2),
};
ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_IO, SCM_IO_WRITE),
&desc);
return ret;
}
EXPORT_SYMBOL(scm_io_write);
int scm_is_call_available(u32 svc_id, u32 cmd_id)
{
int ret;
struct scm_desc desc = {0};
desc.arginfo = SCM_ARGS(1);
desc.args[0] = SCM_SIP_FNID(svc_id, cmd_id);
ret = scm_call2(SCM_SIP_FNID(SCM_SVC_INFO, IS_CALL_AVAIL_CMD), &desc);
if (ret)
return ret;
return desc.ret[0];
}
EXPORT_SYMBOL(scm_is_call_available);
#define GET_FEAT_VERSION_CMD 3
int scm_get_feat_version(u32 feat)
{
struct scm_desc desc = {0};
int ret;
ret = scm_is_call_available(SCM_SVC_INFO, GET_FEAT_VERSION_CMD);
if (ret <= 0)
return 0;
desc.args[0] = feat;
desc.arginfo = SCM_ARGS(1);
ret = scm_call2(SCM_SIP_FNID(SCM_SVC_INFO, GET_FEAT_VERSION_CMD),
&desc);
if (!ret)
return desc.ret[0];
return 0;
}
EXPORT_SYMBOL(scm_get_feat_version);
static int qcom_scm_probe(struct platform_device *pdev)
{
int ret = 0;
if (unlikely(!is_scm_armv8())) {
dev_err(&pdev->dev, "SCM ARMv8 not supported\n");
return -ENODEV;
}
#ifdef CONFIG_ARM64
ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
#endif
if (!ret)
qcom_scm_dev = &pdev->dev;
return ret;
}
static const struct of_device_id qcom_scm_of_match[] = {
{ .compatible = "qcom,secure-chan-manager"},
{}
};
MODULE_DEVICE_TABLE(of, qcom_scm_of_match);
static struct platform_driver qcom_scm_driver = {
.probe = qcom_scm_probe,
.driver = {
.name = "qcom_secure_chan_manager",
.of_match_table = qcom_scm_of_match,
},
};
module_platform_driver(qcom_scm_driver);
MODULE_LICENSE("GPL v2");

View file

@ -1,141 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2010-2019, The Linux Foundation. All rights reserved.
*/
#ifndef __MACH_SCM_H
#define __MACH_SCM_H
#define SCM_SVC_BOOT 0x1
#define SCM_SVC_PIL 0x2
#define SCM_SVC_UTIL 0x3
#define SCM_SVC_TZ 0x4
#define SCM_SVC_IO 0x5
#define SCM_SVC_INFO 0x6
#define SCM_SVC_SSD 0x7
#define SCM_SVC_FUSE 0x8
#define SCM_SVC_PWR 0x9
#define SCM_SVC_MP 0xC
#define SCM_SVC_DCVS 0xD
#define SCM_SVC_ES 0x10
#define SCM_SVC_HDCP 0x11
#define SCM_SVC_MDTP 0x12
#define SCM_SVC_LMH 0x13
#define SCM_SVC_SMMU_PROGRAM 0x15
#define SCM_SVC_QDSS 0x16
#define SCM_SVC_RTIC 0x19
#define SCM_SVC_TZSCHEDULER 0xFC
#define SCM_FUSE_READ 0x7
#define SCM_CMD_HDCP 0x01
/* SCM Features */
#define SCM_SVC_SEC_CAMERA 0xD
#define DEFINE_SCM_BUFFER(__n) \
static char __n[PAGE_SIZE] __aligned(PAGE_SIZE)
#define SCM_BUFFER_SIZE(__buf) sizeof(__buf)
#define SCM_BUFFER_PHYS(__buf) virt_to_phys(__buf)
#define SCM_SIP_FNID(s, c) (((((s) & 0xFF) << 8) | ((c) & 0xFF)) | 0x02000000)
#define SCM_QSEEOS_FNID(s, c) (((((s) & 0xFF) << 8) | ((c) & 0xFF)) | \
0x32000000)
#define SCM_SVC_ID(s) (((s) & 0xFF00) >> 8)
#define MAX_SCM_ARGS 10
#define MAX_SCM_RETS 3
enum scm_arg_types {
SCM_VAL,
SCM_RO,
SCM_RW,
SCM_BUFVAL,
};
#define SCM_ARGS_IMPL(num, a, b, c, d, e, f, g, h, i, j, ...) (\
(((a) & 0xff) << 4) | \
(((b) & 0xff) << 6) | \
(((c) & 0xff) << 8) | \
(((d) & 0xff) << 10) | \
(((e) & 0xff) << 12) | \
(((f) & 0xff) << 14) | \
(((g) & 0xff) << 16) | \
(((h) & 0xff) << 18) | \
(((i) & 0xff) << 20) | \
(((j) & 0xff) << 22) | \
(num & 0xffff))
#define SCM_ARGS(...) SCM_ARGS_IMPL(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
/**
* struct scm_desc
* @arginfo: Metadata describing the arguments in args[]
* @args: The array of arguments for the secure syscall
* @ret: The values returned by the secure syscall
* @extra_arg_buf: The buffer containing extra arguments
(that don't fit in available registers)
* @x5: The 4rd argument to the secure syscall or physical address of
extra_arg_buf
*/
struct scm_desc {
u32 arginfo;
u64 args[MAX_SCM_ARGS];
u64 ret[MAX_SCM_RETS];
/* private */
void *extra_arg_buf;
u64 x5;
};
#if IS_ENABLED(CONFIG_QCOM_SECURE_CHAN_MANAGER)
#define SCM_VERSION(major, minor) (((major) << 16) | ((minor) & 0xFF))
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_is_call_available(u32 svc_id, u32 cmd_id);
extern u32 scm_io_read(phys_addr_t address);
extern int scm_io_write(phys_addr_t address, u32 val);
extern int scm_get_feat_version(u32 feat);
#else
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;
}
static inline int scm_get_feat_version(u32 feat)
{
return 0;
}
static inline int scm_is_call_available(u32 svc_id, u32 cmd_id)
{
return 0;
}
static inline u32 scm_io_read(phys_addr_t address)
{
return 0;
}
static inline int scm_io_write(phys_addr_t address, u32 val)
{
return 0;
}
#endif
#endif

View file

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2016, 2018, The Linux Foundation. All rights reserved.
* Copyright (c) 2016, 2018-2019 The Linux Foundation. All rights reserved.
*/
#undef TRACE_SYSTEM
@ -10,50 +10,37 @@
#define _TRACE_SCM_H
#include <linux/types.h>
#include <linux/tracepoint.h>
#include <soc/qcom/scm.h>
#include <linux/arm-smccc.h>
TRACE_EVENT(scm_call_start,
TRACE_EVENT(scm_call,
TP_PROTO(u64 x0, struct scm_desc *p),
TP_PROTO(const unsigned long *a, const struct arm_smccc_res *r,
const s64 delta),
TP_ARGS(x0, p),
TP_ARGS(a, r, delta),
TP_STRUCT__entry(
__field(u64, x0)
__field(u32, arginfo)
__array(u64, args, MAX_SCM_ARGS)
__field(u64, x5)
__array(u64, args, 8)
__array(unsigned long, ret, 4)
__field(s64, delta)
),
TP_fast_assign(
__entry->x0 = x0;
__entry->arginfo = p->arginfo;
memcpy(__entry->args, p->args, sizeof(__entry->args));
__entry->x5 = p->x5;
memcpy(__entry->args, a, sizeof(__entry->args));
__entry->ret[0] = r->a0;
__entry->ret[1] = r->a1;
__entry->ret[2] = r->a2;
__entry->ret[3] = r->a3;
__entry->delta = delta;
),
TP_printk("func id=%#llx (args: %#x, %#llx, %#llx, %#llx, %#llx)",
__entry->x0, __entry->arginfo, __entry->args[0],
__entry->args[1], __entry->args[2], __entry->x5)
);
TRACE_EVENT(scm_call_end,
TP_PROTO(struct scm_desc *p),
TP_ARGS(p),
TP_STRUCT__entry(
__array(u64, ret, MAX_SCM_RETS)
),
TP_fast_assign(
memcpy(__entry->ret, p->ret, sizeof(__entry->ret));
),
TP_printk("ret: %#llx, %#llx, %#llx",
__entry->ret[0], __entry->ret[1], __entry->ret[2])
TP_printk("%3ld [%#lx %#lx %#lx %#lx %#lx %#lx %#lx %#lx] (%#lx %#lx %#lx %#lx)",
__entry->delta,
__entry->args[0], __entry->args[1], __entry->args[2],
__entry->args[3], __entry->args[4], __entry->args[5],
__entry->args[6], __entry->args[7],
__entry->ret[0], __entry->ret[1],
__entry->ret[2], __entry->ret[3])
);
#endif /* _TRACE_SCM_H */