[9610] soc: samsung: smc: Add DEBUG_SNAPSHOT_LOGGING_SMC feature
authorJunho Choi <junhosj.choi@samsung.com>
Fri, 20 Jul 2018 05:26:26 +0000 (14:26 +0900)
committerSunyoung Kang <sy0816.kang@samsung.com>
Mon, 23 Jul 2018 08:04:37 +0000 (17:04 +0900)
This feature logs the information like clock, latency and etc.
of every SMCs.

Change-Id: I1984510424fbe6668128121ccd5495fd74623920
Signed-off-by: Junho Choi <junhosj.choi@samsung.com>
drivers/soc/samsung/Kconfig
drivers/soc/samsung/exynos-smc.c

index 19837cf16db080837e73c9a14eb941c42307dc51..06e6fbbc3bdbe17283b1f0d0c2955c40bfd3ecc2 100644 (file)
@@ -159,4 +159,14 @@ config USI_V2
        bool "Enable Universal Serial Interface version 2"
        default y
 
+config EXYNOS_SMC_LOG_THRESHOLD
+       int "threshold of detection(microsecond)"
+       range 0 1000000
+       default 0
+
+config DEBUG_SNAPSHOT_LOGGING_SMC
+       bool "Exynos Logging SMC"
+       depends on DEBUG_SNAPSHOT
+       default y
+
 endif
index 6c850adbd064477529568c737894a279e61578bd..aeb0b0db4dd94ee5cdd20e3f279317a4c2833843 100644 (file)
 #include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/smc.h>
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include <linux/device.h>
 #include <linux/sched/clock.h>
 
-#define CONFIG_EXYNOS_SMC_LOGGING
+#include <asm/smp.h>
 
-#ifdef CONFIG_EXYNOS_SMC_LOGGING
-#define EXYNOS_SMC_LOG_SIZE    1024
+#ifdef CONFIG_DEBUG_SNAPSHOT_LOGGING_SMC
+#define EXYNOS_SMC_LOG_SIZE    (1024)
 
-struct exynos_smc_log_entry {
-        u64 cpu_clk;
-        u32 cmd;
-       u32 arg1;
-       u32 arg2;
-       u32 arg3;
+static DEFINE_SPINLOCK(smc_log_lock);
+
+static struct bus_type esmc_subsys = {
+       .name = "exynos-smc",
+       .dev_name = "exynos-smc",
+};
+
+struct esmc_log {
+       unsigned long cpu_clk;          /* cpu clock */
+       unsigned long long start_time;  /* start time */
+       unsigned long sp;               /* call stack */
+       unsigned long long end_time;    /* end time */
+       unsigned long long latency;     /* latency */
+       unsigned long cmd;
+       unsigned long arg1;
+       unsigned long arg2;
+       unsigned long arg3;
+};
+
+struct esmc_log smc_log[NR_CPUS][EXYNOS_SMC_LOG_SIZE];
+static uint32_t smc_log_idx[NR_CPUS];
+
+static unsigned int esmc_log_threshold =
+               CONFIG_EXYNOS_SMC_LOG_THRESHOLD;
+
+static ssize_t esmc_log_threshold_show(struct kobject *kobj,
+               struct kobj_attribute *attr, char *buf)
+{
+       ssize_t n;
+
+       n = scnprintf(buf, 46, "threshold : %12u us\n", esmc_log_threshold);
+
+       return n;
+}
+
+static ssize_t esmc_log_threshold_store(struct kobject *kobj,
+               struct kobj_attribute *attr,
+               const char *buf, size_t count)
+{
+       unsigned long val;
+       int err;
+
+       err = kstrtoul(buf, 0, &val);
+
+       if (err != 0) {
+               pr_err("can't read threshold value with err 0x%x\n", err);
+       } else {
+               esmc_log_threshold = val;
+               pr_info("threshold value : %lu\n", val);
+       }
+
+       return count;
+}
+
+static struct kobj_attribute esmc_log_threshold_attr =
+       __ATTR(threshold_esmc_log, 0644, esmc_log_threshold_show,
+                                       esmc_log_threshold_store);
+
+static struct attribute *esmc_sysfs_attrs[] = {
+       &esmc_log_threshold_attr.attr,
+       NULL,
 };
 
-static DEFINE_SPINLOCK(drm_smc_log_lock);
+static struct attribute_group esmc_sysfs_group = {
+       .attrs = esmc_sysfs_attrs,
+};
 
-struct exynos_smc_log_entry drm_smc_log[EXYNOS_SMC_LOG_SIZE];
+static const struct attribute_group *esmc_sysfs_groups[] = {
+       &esmc_sysfs_group,
+       NULL,
+};
 
-static unsigned int drm_smc_log_idx;
+static int __init esmc_sysfs_init(void)
+{
+       int ret = 0;
+
+       ret = subsys_system_register(&esmc_subsys, esmc_sysfs_groups);
+       if (ret)
+               pr_err("fail to register exynos-smc subsys\n");
+
+       return ret;
+}
+late_initcall(esmc_sysfs_init);
 #endif
 
 int exynos_smc(unsigned long cmd, unsigned long arg1, unsigned long arg2, unsigned long arg3)
 {
-#ifdef CONFIG_EXYNOS_SMC_LOGGING
-       unsigned long flags;
+       int32_t ret;
+#ifdef CONFIG_DEBUG_SNAPSHOT_LOGGING_SMC
+       unsigned long flags, stime, etime, latency;
+       unsigned int cpu, idx;
+
+       cpu = raw_smp_processor_id();
+       stime = cpu_clock(cpu);
 #endif
 
-#ifdef CONFIG_EXYNOS_SMC_LOGGING
-       if ((uint32_t)cmd >= SMC_PROTECTION_SET && (uint32_t)cmd < MC_FC_SET_CFW_PROT) {
-               pr_debug("%s: cmd: 0x%x, arg1: 0x%x, arg2: 0x%x, arg3: 0x%x\n",
-                       __func__, (u32)cmd, (u32)arg1, (u32)arg2, (u32)arg3);
-               spin_lock_irqsave(&drm_smc_log_lock, flags);
-               drm_smc_log[drm_smc_log_idx].cpu_clk = local_clock();
-               drm_smc_log[drm_smc_log_idx].cmd = (u32)cmd;
-               drm_smc_log[drm_smc_log_idx].arg1 = (u32)arg1;
-               drm_smc_log[drm_smc_log_idx].arg2 = (u32)arg2;
-               drm_smc_log[drm_smc_log_idx].arg3 = (u32)arg3;
-               drm_smc_log_idx++;
-               if (drm_smc_log_idx == EXYNOS_SMC_LOG_SIZE)
-                       drm_smc_log_idx = 0;
-               spin_unlock_irqrestore(&drm_smc_log_lock, flags);
+       ret = __exynos_smc(cmd, arg1, arg2, arg3);
+
+#ifdef CONFIG_DEBUG_SNAPSHOT_LOGGING_SMC
+       etime = cpu_clock(cpu);
+       latency = etime - stime;
+
+       spin_lock_irqsave(&smc_log_lock, flags);
+
+       if (latency > (esmc_log_threshold * 1000)) {
+               idx = smc_log_idx[cpu];
+
+               smc_log[cpu][idx].cpu_clk = local_clock();
+               smc_log[cpu][idx].latency = latency;
+               smc_log[cpu][idx].start_time = stime;
+               smc_log[cpu][idx].end_time = etime;
+               smc_log[cpu][idx].sp = (uint64_t)current_stack_pointer;
+               smc_log[cpu][idx].cmd = cmd;
+               smc_log[cpu][idx].arg1 = arg1;
+               smc_log[cpu][idx].arg2 = arg2;
+               smc_log[cpu][idx].arg3 = arg3;
+
+               smc_log_idx[cpu]++;
+               if (smc_log_idx[cpu] == EXYNOS_SMC_LOG_SIZE)
+                       smc_log_idx[cpu] = 0;
        }
-#endif
 
-       return __exynos_smc(cmd, arg1, arg2, arg3);
+       spin_unlock_irqrestore(&smc_log_lock, flags);
+#endif
+       return ret;
 }