All of lore.kernel.org
 help / color / mirror / Atom feed
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

             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.