[Feature]add MT2731_MP2_MR2_SVN388 baseline version
Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/devtools/met-driver/4.9/common/switch.c b/src/devtools/met-driver/4.9/common/switch.c
new file mode 100644
index 0000000..9ea3453
--- /dev/null
+++ b/src/devtools/met-driver/4.9/common/switch.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2018 MediaTek Inc.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/* include <asm/percpu.h> */
+#include <trace/events/sched.h>
+#include <linux/module.h>
+#include <trace/events/irq.h>
+#include <trace/events/power.h>
+
+#include "interface.h"
+#include "met_drv.h"
+#include "cpu_pmu.h"
+#include "switch.h"
+#include "sampler.h"
+#include "met_kernel_symbol.h"
+/* #include "trace.h" */
+
+/*
+ * IRQ_TIRGGER and CPU_IDLE_TRIGGER
+ */
+/* #define IRQ_TRIGGER */
+/* #define CPU_IDLE_TRIGGER */
+
+static DEFINE_PER_CPU(unsigned int, first_log);
+
+#ifdef __aarch64__
+/* #include <asm/compat.h> */
+#include <linux/compat.h>
+#endif
+
+noinline void mt_switch(struct task_struct *prev, struct task_struct *next)
+{
+ int cpu;
+ int prev_state = 0, next_state = 0;
+
+#ifdef __aarch64__
+ prev_state = !(is_compat_thread(task_thread_info(prev)));
+ next_state = !(is_compat_thread(task_thread_info(next)));
+#endif
+
+ cpu = smp_processor_id();
+ if (per_cpu(first_log, cpu)) {
+ MET_TRACE("%d, %d, %d, %d\n", prev->pid, prev_state, next->pid, next_state);
+ per_cpu(first_log, cpu) = 0;
+ }
+ if (prev_state != next_state)
+ MET_TRACE("%d, %d, %d, %d\n", prev->pid, prev_state, next->pid, next_state);
+}
+
+
+#if 0 /* move to kernel space */
+MET_DEFINE_PROBE(sched_switch,
+ TP_PROTO(bool preempt, struct task_struct *prev, struct task_struct *next))
+{
+ /* speedup sched_switch callback handle */
+ if (met_switch.mode == 0)
+ return;
+
+ if (met_switch.mode & MT_SWITCH_EVENT_TIMER)
+ met_event_timer_notify();
+
+ if (met_switch.mode & MT_SWITCH_64_32BIT)
+ mt_switch(prev, next);
+
+ if (met_switch.mode & MT_SWITCH_SCHEDSWITCH) {
+ if (get_pmu_profiling_version() == 1)
+ cpupmu_polling(0, smp_processor_id());
+#ifdef MET_SUPPORT_CPUPMU_V2
+ else if (get_pmu_profiling_version() == 2)
+ cpupmu_polling_v2(0, smp_processor_id());
+#endif
+ }
+}
+#endif
+
+void met_sched_switch(struct task_struct *prev, struct task_struct *next)
+{
+ /* speedup sched_switch callback handle */
+ if (met_switch.mode == 0)
+ return;
+
+ if (met_switch.mode & MT_SWITCH_EVENT_TIMER)
+ met_event_timer_notify();
+
+ if (met_switch.mode & MT_SWITCH_64_32BIT)
+ mt_switch(prev, next);
+
+ /* met_perf_cpupmu_status: 0: stop, others: polling */
+ if ((met_switch.mode & MT_SWITCH_SCHEDSWITCH) && met_perf_cpupmu_status)
+ met_perf_cpupmu_polling(0, smp_processor_id());
+}
+
+#ifdef IRQ_TRIGGER
+MET_DEFINE_PROBE(irq_handler_entry, TP_PROTO(int irq, struct irqaction *action))
+{
+ if (met_switch.mode & MT_SWITCH_EVENT_TIMER) {
+ met_event_timer_notify();
+ return;
+ }
+}
+#endif
+
+#ifdef CPU_IDLE_TRIGGER
+MET_DEFINE_PROBE(cpu_idle, TP_PROTO(unsigned int state, unsigned int cpu_id))
+{
+ if (met_switch.mode & MT_SWITCH_EVENT_TIMER) {
+ met_event_timer_notify();
+ return;
+ }
+}
+#endif
+
+#ifdef MET_ANYTIME
+/*
+ * create related subfs file node
+ */
+
+static ssize_t default_on_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "1\n");
+}
+
+static struct kobj_attribute default_on_attr = __ATTR(default_on, 0664, default_on_show, NULL);
+static struct kobject *kobj_cpu;
+#endif
+
+static int met_switch_create_subfs(struct kobject *parent)
+{
+ int ret = 0;
+
+ /* register tracepoints */
+#if 0
+ if (MET_REGISTER_TRACE(sched_switch)) {
+ pr_debug("can not register callback of sched_switch\n");
+ return -ENODEV;
+ }
+#else
+ if (met_reg_switch_symbol)
+ ret = met_reg_switch_symbol();
+#endif
+#ifdef CPU_IDLE_TRIGGER
+ if (MET_REGISTER_TRACE(cpu_idle)) {
+ pr_debug("can not register callback of irq_handler_entry\n");
+ return -ENODEV;
+ }
+#endif
+#ifdef IRQ_TRIGGER
+ if (MET_REGISTER_TRACE(irq_handler_entry)) {
+ pr_debug("can not register callback of irq_handler_entry\n");
+ return -ENODEV;
+ }
+#endif
+
+#ifdef MET_ANYTIME
+ /*
+ * to create default_on file node
+ * let user space can know we can support MET default on
+ */
+ kobj_cpu = parent;
+ ret = sysfs_create_file(kobj_cpu, &default_on_attr.attr);
+ if (ret != 0) {
+ pr_debug("Failed to create default_on in sysfs\n");
+ return -1;
+ }
+#endif
+
+ return ret;
+}
+
+
+static void met_switch_delete_subfs(void)
+{
+#ifdef MET_ANYTIME
+ if (kobj_cpu != NULL) {
+ sysfs_remove_file(kobj_cpu, &default_on_attr.attr);
+ kobj_cpu = NULL;
+ }
+#endif
+#ifdef IRQ_TRIGGER
+ MET_UNREGISTER_TRACE(irq_handler_entry);
+#endif
+#ifdef CPU_IDLE_TRIGGER
+ MET_UNREGISTER_TRACE(cpu_idle);
+#endif
+#if 0
+ MET_UNREGISTER_TRACE(sched_switch);
+#else
+ if (met_unreg_switch_symbol)
+ met_unreg_switch_symbol();
+#endif
+
+}
+
+
+static void (*cpu_timed_polling)(unsigned long long stamp, int cpu);
+/* static void (*cpu_tagged_polling)(unsigned long long stamp, int cpu); */
+
+static void met_switch_start(void)
+{
+ int cpu;
+
+ if (met_switch.mode & MT_SWITCH_SCHEDSWITCH) {
+ cpu_timed_polling = met_cpupmu.timed_polling;
+ /* cpu_tagged_polling = met_cpupmu.tagged_polling; */
+ met_cpupmu.timed_polling = NULL;
+ /* met_cpupmu.tagged_polling = NULL; */
+ }
+
+ for_each_possible_cpu(cpu) {
+ per_cpu(first_log, cpu) = 1;
+ }
+
+}
+
+
+static void met_switch_stop(void)
+{
+ int cpu;
+
+ if (met_switch.mode & MT_SWITCH_SCHEDSWITCH) {
+ met_cpupmu.timed_polling = cpu_timed_polling;
+ /* met_cpupmu.tagged_polling = cpu_tagged_polling; */
+ }
+
+ for_each_possible_cpu(cpu) {
+ per_cpu(first_log, cpu) = 0;
+ }
+
+}
+
+
+static int met_switch_process_argument(const char *arg, int len)
+{
+ unsigned int value;
+ /*ex: mxitem is 0x0005, max value should be (5-1) + (5-2) = 0x100 + 0x11 = 7 */
+ unsigned int max_value = ((MT_SWITCH_MX_ITEM * 2) - 3);
+
+
+ if (met_parse_num(arg, &value, len) < 0)
+ goto arg_switch_exit;
+
+ if ((value < 1) || (value > max_value))
+ goto arg_switch_exit;
+
+ met_switch.mode = value;
+ return 0;
+
+arg_switch_exit:
+ met_switch.mode = 0;
+ return -EINVAL;
+}
+
+static const char header[] =
+ "met-info [000] 0.0: met_switch_header: prev_pid,prev_state,next_pid,next_state\n";
+
+static const char help[] =
+" --switch=mode mode:0x1 - output CPUPMU whenever sched_switch\n"
+" mode:0x2 - output Aarch 32/64 state whenever state changed (no CPUPMU)\n"
+" mode:0x4 - force output count at tag_start/tag_end\n"
+" mode:0x8 - task switch timer\n"
+" mode:0xF - mode 0x1 + 0x2 + 04 + 08\n";
+
+static int met_switch_print_help(char *buf, int len)
+{
+ return snprintf(buf, PAGE_SIZE, help);
+}
+
+static int met_switch_print_header(char *buf, int len)
+{
+ int ret = 0;
+
+ ret =
+ snprintf(buf, PAGE_SIZE, "met-info [000] 0.0: mp_cpu_switch_base: %d\n",
+ met_switch.mode);
+ if (met_switch.mode & MT_SWITCH_64_32BIT)
+ ret += snprintf(buf + ret, PAGE_SIZE, header);
+
+ return ret;
+}
+
+
+struct metdevice met_switch = {
+ .name = "switch",
+ .type = MET_TYPE_PMU,
+ .create_subfs = met_switch_create_subfs,
+ .delete_subfs = met_switch_delete_subfs,
+ .start = met_switch_start,
+ .stop = met_switch_stop,
+ .process_argument = met_switch_process_argument,
+ .print_help = met_switch_print_help,
+ .print_header = met_switch_print_header,
+};