From: marek.bykowski@gmail.com
To: linux-arm-kernel@lists.infradead.org
Cc: Marek Bykowski <marek.bykowski@gmail.com>
Subject: [PATCH] drivers/firmware: arch64: Add SMC call testing module
Date: Tue, 9 Apr 2019 16:46:01 +0200 [thread overview]
Message-ID: <1554821161-4623-1-git-send-email-marek.bykowski@gmail.com> (raw)
From: Marek Bykowski <marek.bykowski@gmail.com>
The module measures the round-trip latency for both PSCI_VERSION and
SMCCC_ARCH_WORKAROUND_1 conforming to SMC Calling Convention v1.0 and v1.1
respectively for each of the CPUs. Knowing these latencies is becoming
critical in quantifying the performance impact resulting in from execution
of the mitigation to CVE-2017-5715. Generally the module application can be
extended into measuring an arbitrary SMC call duration.
The sample results for a SoC based on ARM Cortex-A57 MPCore Processor
running 16 CPUs is as follows:
SMC_VARIANT(0): smc_call_v10 [smc_time]
CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7 CPU8 CPU9 CPU10 CPU11 CPU12 CPU13 CPU14 CPU15
4812 5140 5039 5199 5265 5242 4571 4715 4879 4891 4886 4910 4016 4215 4015 4051
SMC_VARIANT(1): smc_call_v11 [smc_time]
CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7 CPU8 CPU9 CPU10 CPU11 CPU12 CPU13 CPU14 CPU15
476 481 489 489 496 496 496 496 496 496 504 496 480 481 469 477
Signed-off-by: Marek Bykowski <marek.bykowski@gmail.com>
---
drivers/firmware/Kconfig | 9 ++
drivers/firmware/Makefile | 1 +
drivers/firmware/smc_latency.c | 220 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 230 insertions(+)
create mode 100644 drivers/firmware/smc_latency.c
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index bca172d42c74..30777ac0ce1b 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -195,6 +195,15 @@ config QCOM_SCM
depends on ARM || ARM64
select RESET_CONTROLLER
+config SMC_LATENCY
+ tristate "Measure round-trip latency of the SMC calls"
+ depends on HAVE_ARM_SMCCC
+ default m
+ help
+ Say Y or M here to enable the measurement of the round-trip latency
+ for both PSCI_VERSION and SMCCC_ARCH_WORKAROUND_1 conforming to SMC
+ Calling Convention v1.0 and v1.1 respectively for each of the CPUs.
+
config QCOM_SCM_32
def_bool y
depends on QCOM_SCM && ARM
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 898ac41fa8b3..382bf01470f7 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_FW_CFG_SYSFS) += qemu_fw_cfg.o
obj-$(CONFIG_QCOM_SCM) += qcom_scm.o
obj-$(CONFIG_QCOM_SCM_64) += qcom_scm-64.o
obj-$(CONFIG_QCOM_SCM_32) += qcom_scm-32.o
+obj-$(CONFIG_SMC_LATENCY) += smc_latency.o
CFLAGS_qcom_scm-32.o :=$(call as-instr,.arch armv7-a\n.arch_extension sec,-DREQUIRES_SEC=1) -march=armv7-a
obj-y += broadcom/
diff --git a/drivers/firmware/smc_latency.c b/drivers/firmware/smc_latency.c
new file mode 100644
index 000000000000..fc3697697ed6
--- /dev/null
+++ b/drivers/firmware/smc_latency.c
@@ -0,0 +1,220 @@
+/*
+ *
+ * SMC testing module
+ *
+ * Copyright (C) 2019 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/proc_fs.h>
+#include <linux/slab.h>
+#include <linux/linkage.h>
+#include <linux/axxia-oem.h>
+#include <linux/uaccess.h>
+#include <linux/arm-smccc.h>
+#include <asm/smp_plat.h>
+#include <linux/seq_file.h>
+#include <uapi/linux/psci.h>
+
+#define SMC_DEBUG 0
+#if SMC_DEBUG
+#define smc_dbg(...) pr_info(__VA_ARGS__)
+#define seq_printf(...)
+#define seq_puts(...)
+#else
+#define smc_dbg(...)
+#define seq_printf(arg0, ...) seq_printf(arg0, __VA_ARGS__)
+#define seq_puts(arg0, ...) seq_puts(arg0, __VA_ARGS__)
+#endif
+
+struct _pt_regs {
+ unsigned long elr;
+ unsigned long regs[31];
+};
+
+typedef void (*smc_cb_t)(void *);
+
+static bool all_cpus;
+module_param(all_cpus, bool, 0644);
+MODULE_PARM_DESC(all_cpus, "Run smc call on executing or all cpus (default: all");
+
+void smc_call_v10(void *arg);
+void smc_call_v11(void *arg);
+
+smc_cb_t smc_call[] = {
+ smc_call_v10,
+ smc_call_v11
+};
+
+#define SMC_VARIANTS ARRAY_SIZE(smc_call)
+#define SMC_VARIANT(n) n
+#define for_each_smc(smc) \
+ for ((smc) = 0; (smc) < SMC_VARIANTS; (smc)++)
+
+unsigned long __percpu *time[SMC_VARIANTS];
+
+/* SMCCC 1.0 */
+void smc_call_v10(void *arg)
+{
+ struct pt_regs _regs = {0}, *regs = &_regs;
+ int smc = *(unsigned int *)arg;
+ struct arm_smccc_res res;
+ ktime_t start, end;
+
+ regs->regs[0] = PSCI_0_2_FN_PSCI_VERSION;
+
+ start = ktime_get();
+ arm_smccc_smc(regs->regs[0], regs->regs[1], regs->regs[2],
+ regs->regs[3], 0, 0, 0, 0, &res);
+ end = ktime_get();
+
+ this_cpu_write(*time[smc], ktime_to_ns(ktime_sub(end, start)));
+ smc_dbg("cpu%d %lu ns (ret %#lx)\n",
+ smc,
+ this_cpu_read(*time[smc]),
+ res.a0);
+}
+
+/* SMCCC 1.1 */
+void smc_call_v11(void *arg)
+{
+ int smc = *(unsigned int *)arg;
+ ktime_t start, end;
+
+ start = ktime_get();
+ arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL);
+ end = ktime_get();
+
+ this_cpu_write(*time[smc], ktime_to_ns(ktime_sub(end, start)));
+ smc_dbg("cpu%d %lu ns (ret %s)\n",
+ smc,
+ this_cpu_read(*time[smc]),
+ "RET0 in smc call");
+}
+
+void
+zeroise_times(void)
+{
+ int cpu, smc;
+
+ for_each_smc(smc) {
+ for_each_online_cpu(cpu) {
+ *per_cpu_ptr(time[smc], cpu) = 0;
+ }
+ }
+}
+
+static void run_test(void)
+{
+ int smc;
+
+ /* init the smc call regs before the next call round */
+ zeroise_times();
+
+ switch (all_cpus) {
+ case true:
+ for_each_smc(smc) {
+ int cpu;
+
+ for_each_online_cpu(cpu) {
+ int ret;
+
+ ret = smp_call_function_single(cpu, smc_call[smc],
+ (void *)&smc, 1);
+ if (ret)
+ WARN_ON(ret);
+ }
+ }
+ break;
+ case false:
+ for_each_smc(smc)
+ smc_call[smc]((void *)&smc);
+ break;
+ }
+}
+
+
+static int proc_smc_show(struct seq_file *m, void *v)
+{
+ int smc;
+
+ run_test();
+
+ for_each_smc(smc) {
+ int cpu;
+
+ seq_printf(m, "SMC_VARIANT(%u): %pf\n", smc, smc_call[smc]);
+ for_each_online_cpu(cpu)
+ seq_printf(m, "CPU%-2d ", cpu);
+ seq_puts(m, "\n");
+ for_each_online_cpu(cpu)
+ seq_printf(m, "%-5lu ",
+ *per_cpu_ptr(time[SMC_VARIANT(smc)], cpu));
+ seq_puts(m, "\n");
+ }
+
+ return 0;
+}
+
+static int proc_smc_open(struct inode *inode, struct file *file);
+static const struct file_operations proc_smc_operations = {
+ .open = proc_smc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int proc_smc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, proc_smc_show, NULL);
+}
+
+static struct proc_dir_entry *procent;
+static int __init proc_dma_init(void)
+{
+ procent = proc_create("axxia_smccall", 0444, NULL,
+ &proc_smc_operations);
+ return 0;
+}
+
+
+static int __init smctest_init(void)
+{
+ unsigned int smc;
+
+ for_each_smc(smc)
+ time[smc] = alloc_percpu(unsigned long);
+
+ zeroise_times();
+ proc_dma_init();
+
+ return 0;
+}
+late_initcall(smctest_init);
+
+static void __exit dmatest_exit(void)
+{
+ unsigned int smc;
+
+ for_each_smc(smc)
+ if (time[smc]) {
+ free_percpu(time[smc]);
+ time[smc] = NULL;
+ }
+
+ if (procent) {
+ proc_remove(procent);
+ procent = NULL;
+ }
+}
+
+module_exit(dmatest_exit);
+
+MODULE_AUTHOR("Marek Bykowski");
+MODULE_LICENSE("GPL v2");
--
2.16.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
next reply other threads:[~2019-04-09 14:46 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-04-09 14:46 marek.bykowski [this message]
2019-04-09 16:06 ` [PATCH] drivers/firmware: arch64: Add SMC call testing module Mark Rutland
2019-04-10 8:07 ` Marek
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1554821161-4623-1-git-send-email-marek.bykowski@gmail.com \
--to=marek.bykowski@gmail.com \
--cc=linux-arm-kernel@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.