[Feature]add MT2731_MP2_MR2_SVN388 baseline version

Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/devtools/met-driver/4.19/mt2712/cpu_pmu_v2.c b/src/devtools/met-driver/4.19/mt2712/cpu_pmu_v2.c
new file mode 100644
index 0000000..26dcbfa
--- /dev/null
+++ b/src/devtools/met-driver/4.19/mt2712/cpu_pmu_v2.c
@@ -0,0 +1,675 @@
+/*

+ * 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 <linux/slab.h>

+#include <linux/version.h>

+

+#include "interface.h"

+#include "trace.h"

+#include "cpu_pmu_v2.h"

+#include "v8_pmu_hw_v2.h"

+#include "met_drv.h"

+

+

+#define MET_USER_EVENT_SUPPORT

+

+#include <linux/kthread.h>

+#include <linux/kernel.h>

+#include <linux/sched.h>

+#include <linux/wait.h>

+#include <linux/signal.h>

+#include <linux/workqueue.h>

+#include <linux/perf_event.h>

+#include "met_kernel_symbol.h"

+

+

+/*******************************************************************************

+*				Type Define

+*******************************************************************************/

+#define CNTMAX 8

+

+

+/*******************************************************************************

+*				Fuction Pototypes

+*******************************************************************************/

+static inline struct met_pmu_v2 *get_met_pmu_by_cpu_id(const unsigned int cpu);

+static inline void set_met_pmu_by_cpu_id(const unsigned int cpu, struct met_pmu_v2 *met_pmu);

+

+static int reset_driver_stat(void);

+static struct met_pmu_v2 *lookup_pmu(struct kobject *kobj);

+

+static ssize_t mode_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf);

+

+static int cpupmu_create_subfs(struct kobject *parent);

+static void cpupmu_delete_subfs(void);

+static void _cpupmu_start(void *info);

+static void cpupmu_start(void);

+static void _cpupmu_stop(void *info);

+static void cpupmu_stop(void);

+static void cpupmu_polling(unsigned long long stamp, int cpu);

+extern void cpupmu_polling_v2(unsigned long long stamp, int cpu);

+static int cpupmu_print_help(char *buf, int len);

+static int cpupmu_print_header(char *buf, int len);

+static int cpupmu_process_argument(const char *arg, int len);

+

+

+/*******************************************************************************

+*				Globe Variables

+*******************************************************************************/

+static int module_status;

+

+struct cpu_pmu_hw_v2 *met_pmu_hw_v2;

+

+static unsigned int gPMU_CNT[2*MXNR_CPU_V2];

+static unsigned int gMAX_PMU_HW_CNT;

+

+static struct kobject *gKOBJ_CPU;

+static struct met_pmu_v2 *gMET_PMU[2*MXNR_CPU_V2];

+

+static struct kobj_attribute mode_attr = __ATTR(mode, 0444, mode_show, NULL);

+

+static const char cache_line_header[] =

+	"met-info [000] 0.0: met_cpu_cache_line_size: %d\n";

+static const char header[] =

+	"met-info [000] 0.0: met_cpu_header_v2: ";

+static const char help[] =

+	"  --cpu-pmu=CORE_ID:EVENT	     select CPU-PMU events. in %s,\n"

+	"				      you can enable at most \"%d general purpose events\"\n"

+	"				      plus \"one special 0xff (CPU_CYCLE) event\"\n";

+

+static DEFINE_PER_CPU(int[CNTMAX], perfCurr);

+static DEFINE_PER_CPU(int[CNTMAX], perfPrev);

+static DEFINE_PER_CPU(struct perf_event * [CNTMAX], pevent);

+static DEFINE_PER_CPU(struct perf_event_attr [CNTMAX], pevent_attr);

+static DEFINE_PER_CPU(int, perfSet);

+static DEFINE_PER_CPU(unsigned int, perf_task_init_done);

+static DEFINE_PER_CPU(unsigned int, perf_cpuid);

+

+static DEFINE_PER_CPU(struct delayed_work, cpu_pmu_dwork);

+static DEFINE_PER_CPU(struct delayed_work *, perf_delayed_work_setup);

+

+struct metdevice met_cpupmu_v2 = {

+	.name = "cpu-pmu",

+	.type = MET_TYPE_PMU,

+	.cpu_related = 1,

+	.create_subfs = cpupmu_create_subfs,

+	.delete_subfs = cpupmu_delete_subfs,

+	.start = cpupmu_start,

+	.stop = cpupmu_stop,

+	.polling_interval = 1,

+	.timed_polling = cpupmu_polling,

+	.print_help = cpupmu_print_help,

+	.print_header = cpupmu_print_header,

+	.process_argument = cpupmu_process_argument

+};

+

+

+/*******************************************************************************

+*				Iplement Start

+*******************************************************************************/

+static inline struct met_pmu_v2 *get_met_pmu_by_cpu_id(const unsigned int cpu)

+{

+	if (cpu < MXNR_CPU_V2)

+		return gMET_PMU[cpu];

+	else

+		return NULL;

+}

+

+

+static inline void set_met_pmu_by_cpu_id(const unsigned int cpu, struct met_pmu_v2 *met_pmu)

+{

+	if (cpu < MXNR_CPU_V2)

+		gMET_PMU[cpu] = met_pmu;

+}

+

+

+static int reset_driver_stat()

+{

+	int i;

+	int cpu;

+	struct met_pmu_v2 *met_pmu;

+

+	met_cpupmu_v2.mode = 0;

+	for_each_possible_cpu(cpu) {

+		met_pmu = get_met_pmu_by_cpu_id(cpu);

+		for (i = 0; i < gMAX_PMU_HW_CNT; i++) {

+			met_pmu[i].mode = MODE_DISABLED;

+			met_pmu[i].event = 0;

+		}

+		gPMU_CNT[cpu] = 0;

+	}

+	module_status = 0;

+	return 0;

+}

+

+

+static struct met_pmu_v2 *lookup_pmu(struct kobject *kobj)

+{

+	int i;

+	int cpu;

+	struct met_pmu_v2 *met_pmu;

+

+	for_each_possible_cpu(cpu) {

+		met_pmu = get_met_pmu_by_cpu_id(cpu);

+		for (i = 0; i < gMAX_PMU_HW_CNT; i++) {

+			if (met_pmu[i].kobj_cpu_pmu == kobj)

+				return &met_pmu[i];

+		}

+	}

+	return NULL;

+}

+

+

+static ssize_t mode_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)

+{

+	struct met_pmu_v2 *p = lookup_pmu(kobj);

+

+	if (p != NULL) {

+		switch (p->mode) {

+		case 0:

+			return snprintf(buf, PAGE_SIZE, "%hhd (disabled)\n", p->mode);

+		case 1:

+			return snprintf(buf, PAGE_SIZE, "%hhd (interrupt)\n", p->mode);

+		case 2:

+			return snprintf(buf, PAGE_SIZE, "%hhd (polling)\n", p->mode);

+		}

+	}

+	return -EINVAL;

+}

+

+

+static int cpupmu_create_subfs(struct kobject *parent)

+{

+	int ret = 0;

+	unsigned int i;

+	unsigned int cpu;

+	char buf[16];

+	struct met_pmu_v2 *met_pmu;

+

+	met_pmu_hw_v2 = cpu_pmu_hw_init_v2();

+	if (met_pmu_hw_v2 == NULL) {

+		PR_BOOTMSG("Failed to init CPU PMU HW!!\n");

+		return -ENODEV;

+	}

+	gMAX_PMU_HW_CNT = met_pmu_hw_v2->max_hw_count;

+

+	gKOBJ_CPU = parent;

+	for_each_possible_cpu(cpu) {

+		met_pmu = kmalloc_array(gMAX_PMU_HW_CNT, sizeof(struct met_pmu_v2), GFP_KERNEL);

+		if (met_pmu != NULL) {

+			memset(met_pmu, 0x0, gMAX_PMU_HW_CNT * sizeof(struct met_pmu_v2));

+			met_pmu_hw_v2->met_pmu[cpu] = met_pmu;

+			set_met_pmu_by_cpu_id(cpu, met_pmu);

+		} else

+			ret = -ENOMEM;

+

+		for (i = 0; i < gMAX_PMU_HW_CNT; i++) {

+			snprintf(buf, sizeof(buf), "CPU-%d-%d", cpu, i);

+			met_pmu[i].kobj_cpu_pmu = kobject_create_and_add(buf, gKOBJ_CPU);

+			if (met_pmu[i].kobj_cpu_pmu) {

+				ret = sysfs_create_file(met_pmu[i].kobj_cpu_pmu, &mode_attr.attr);

+				if (ret != 0) {

+					PR_BOOTMSG("Failed to create mode in sysfs\n");

+					goto out;

+				}

+			}

+		}

+	}

+ out:

+	if (ret != 0) {

+		for_each_possible_cpu(cpu) {

+			met_pmu = get_met_pmu_by_cpu_id(cpu);

+			if (met_pmu != NULL) {

+				kfree(met_pmu);

+				set_met_pmu_by_cpu_id(cpu, NULL);

+			}

+		}

+	}

+	return ret;

+}

+

+

+static void cpupmu_delete_subfs(void)

+{

+	unsigned int i;

+	unsigned int cpu;

+	struct met_pmu_v2 *met_pmu;

+

+	for_each_possible_cpu(cpu) {

+		met_pmu = get_met_pmu_by_cpu_id(cpu);

+		if (met_pmu != NULL) {

+			for (i = 0; i < gMAX_PMU_HW_CNT; i++) {

+				sysfs_remove_file(met_pmu[i].kobj_cpu_pmu, &mode_attr.attr);

+				kobject_del(met_pmu[i].kobj_cpu_pmu);

+				kobject_put(met_pmu[i].kobj_cpu_pmu);

+				met_pmu[i].kobj_cpu_pmu = NULL;

+			}

+			kfree(met_pmu);

+		}

+		set_met_pmu_by_cpu_id(cpu, NULL);

+	}

+

+	if (gKOBJ_CPU != NULL) {

+		gKOBJ_CPU = NULL;

+	}

+

+	met_pmu_hw_v2  = NULL;

+}

+

+

+noinline void mp_cpu_v2(unsigned char cnt, unsigned int *value)

+{

+        if (cnt < MXNR_CPU_V2)

+	        MET_GENERAL_PRINT(MET_TRACE, cnt, value);

+}

+

+

+static void dummy_handler(struct perf_event *event, struct perf_sample_data *data,

+			  struct pt_regs *regs)

+{

+/* Required as perf_event_create_kernel_counter() requires an overflow handler, even though all we do is poll */

+}

+

+

+void perf_cpupmu_polling_v2(unsigned long long stamp, int cpu)

+{

+	int i, count, delta;

+	struct perf_event *ev;

+	unsigned int pmu_value[MXNR_CPU_V2];

+	struct met_pmu_v2 *met_pmu;

+	u64 value;

+

+	if (per_cpu(perfSet, cpu) == 0)

+		return;

+

+	memset(pmu_value, 0, sizeof(pmu_value));

+	count = 0;

+	met_pmu = get_met_pmu_by_cpu_id(cpu);

+	for (i = 0; i < gMAX_PMU_HW_CNT; i++) {

+		if (met_pmu[i].mode == 0)

+			continue;

+

+		ev = per_cpu(pevent, cpu)[i];

+		if ((ev != NULL) && (ev->state == PERF_EVENT_STATE_ACTIVE)) {

+			if (per_cpu(perfPrev, cpu)[i] == 0) {

+				met_perf_event_read_local_symbol(ev, &value, NULL, NULL);

+				per_cpu(perfPrev, cpu)[i] = value;

+				continue;

+			}

+			met_perf_event_read_local_symbol(ev, &value, NULL, NULL);

+			per_cpu(perfCurr, cpu)[i] = value;

+			delta = per_cpu(perfCurr, cpu)[i] - per_cpu(perfPrev, cpu)[i];

+			per_cpu(perfPrev, cpu)[i] = per_cpu(perfCurr, cpu)[i];

+			if (delta < 0)

+				delta *= -1;

+			pmu_value[i] = delta;

+			count++;

+		}

+	}

+

+	if (count == gPMU_CNT[cpu])

+		mp_cpu_v2(count, pmu_value);

+}

+

+

+static int perf_thread_set_perf_events_v2(unsigned int cpu)

+{

+	int i, size;

+	struct perf_event *ev;

+	struct met_pmu_v2 *met_pmu;

+

+	size = sizeof(struct perf_event_attr);

+	if (per_cpu(perfSet, cpu) == 0) {

+		met_pmu = get_met_pmu_by_cpu_id(cpu);

+		for (i = 0; i < gMAX_PMU_HW_CNT; i++) {

+			per_cpu(pevent, cpu)[i] = NULL;

+			if (!met_pmu[i].mode) {/* Skip disabled counters */

+				continue;

+			}

+			per_cpu(perfPrev, cpu)[i] = 0;

+			per_cpu(perfCurr, cpu)[i] = 0;

+			memset(&per_cpu(pevent_attr, cpu)[i], 0, size);

+			per_cpu(pevent_attr, cpu)[i].config = met_pmu[i].event;

+			per_cpu(pevent_attr, cpu)[i].type = PERF_TYPE_RAW;

+			per_cpu(pevent_attr, cpu)[i].size = size;

+			per_cpu(pevent_attr, cpu)[i].sample_period = 0;

+			per_cpu(pevent_attr, cpu)[i].pinned = 1;

+			if (met_pmu[i].event == 0xff) {

+				per_cpu(pevent_attr, cpu)[i].type = PERF_TYPE_HARDWARE;

+				per_cpu(pevent_attr, cpu)[i].config = PERF_COUNT_HW_CPU_CYCLES;

+			}

+

+			per_cpu(pevent, cpu)[i] =

+			    perf_event_create_kernel_counter(&per_cpu(pevent_attr, cpu)[i], cpu, NULL,

+				     dummy_handler, NULL);

+			if (IS_ERR(per_cpu(pevent, cpu)[i])) {

+				per_cpu(pevent, cpu)[i] = NULL;

+				PR_BOOTMSG("CPU=%d, %s:%d\n", cpu, __FUNCTION__, __LINE__);

+				continue;

+			}

+

+			if (per_cpu(pevent, cpu)[i]->state != PERF_EVENT_STATE_ACTIVE) {

+				perf_event_release_kernel(per_cpu(pevent, cpu)[i]);

+				per_cpu(pevent, cpu)[i] = NULL;

+				PR_BOOTMSG("CPU=%d, %s:%d\n", cpu, __FUNCTION__, __LINE__);

+				continue;

+			}

+

+			ev = per_cpu(pevent, cpu)[i];

+			if (ev != NULL) {

+				perf_event_enable(ev);

+			}

+		} /* for all PMU counter */

+		per_cpu(perfSet, cpu) = 1;

+	} /* for perfSet */

+	return 0;

+}

+

+

+static void perf_thread_setup_v2(struct work_struct *work)

+{

+	unsigned int cpu;

+	struct delayed_work *dwork = to_delayed_work(work);

+

+	cpu = dwork->cpu;

+	if (per_cpu(perf_task_init_done, cpu) == 0) {

+		per_cpu(perf_task_init_done, cpu) = 1;

+		perf_thread_set_perf_events_v2(cpu);

+	}

+

+	return ;

+}

+

+

+void met_perf_cpupmu_online_v2(unsigned int cpu)

+{

+	if (met_cpupmu_v2.mode == 0) {

+		PR_BOOTMSG("CPU=%d, %s:%d\n", cpu, __FUNCTION__, __LINE__);

+		return;

+	}

+

+	per_cpu(perf_cpuid, cpu) = cpu;

+	if (per_cpu(perf_delayed_work_setup, cpu) == NULL) {

+		struct delayed_work *dwork;

+

+		dwork = &per_cpu(cpu_pmu_dwork, cpu);

+		dwork->cpu = cpu;

+		INIT_DELAYED_WORK(dwork, perf_thread_setup_v2);

+		schedule_delayed_work(dwork, 0);

+		per_cpu(perf_delayed_work_setup, cpu) = dwork;

+	}

+}

+

+

+void met_perf_cpupmu_down_v2(void *data)

+{

+	unsigned int cpu;

+	unsigned int i;

+	struct perf_event *ev;

+	struct met_pmu_v2 *met_pmu;

+

+	cpu = *((unsigned int *)data);

+	if (met_cpupmu_v2.mode == 0)

+		return;

+	if (per_cpu(perfSet, cpu) == 0)

+		return;

+

+	met_pmu = get_met_pmu_by_cpu_id(cpu);

+	per_cpu(perfSet, cpu) = 0;

+	for (i = 0; i < gMAX_PMU_HW_CNT; i++) {

+		if (!met_pmu[i].mode)

+			continue;

+		ev = per_cpu(pevent, cpu)[i];

+		if ((ev != NULL) && (ev->state == PERF_EVENT_STATE_ACTIVE)) {

+			perf_event_disable(ev);

+			perf_event_release_kernel(ev);

+		}

+	}

+	per_cpu(perf_task_init_done, cpu) = 0;

+	per_cpu(perf_delayed_work_setup, cpu) = NULL;

+}

+

+

+void met_perf_cpupmu_start_v2(void)

+{

+	unsigned int cpu;

+

+	for_each_online_cpu(cpu) {

+		met_perf_cpupmu_online_v2(cpu);

+	}

+}

+

+

+void met_perf_cpupmu_stop_v2(void)

+{

+	unsigned int cpu;

+

+	for_each_online_cpu(cpu) {

+		per_cpu(perf_cpuid, cpu) = cpu;

+		met_perf_cpupmu_down_v2((void *)&per_cpu(perf_cpuid, cpu));

+	}

+}

+

+

+static void cpupmu_polling(unsigned long long stamp, int cpu)

+{

+	int count;

+	struct met_pmu_v2 *met_pmu;

+	unsigned int pmu_value[MXNR_CPU_V2];

+

+	met_pmu = get_met_pmu_by_cpu_id(cpu);

+	if (met_cpu_pmu_method == 0) {

+		count = met_pmu_hw_v2->polling(met_pmu, gMAX_PMU_HW_CNT, pmu_value);

+		mp_cpu_v2(count, pmu_value);

+	} else

+		perf_cpupmu_polling_v2(stamp, cpu);

+}

+

+

+void cpupmu_polling_v2(unsigned long long stamp, int cpu)

+{

+	cpupmu_polling(stamp, cpu);

+}

+

+

+static void _cpupmu_start(void *info)

+{

+	unsigned int *cpu = (unsigned int *)info;

+	struct met_pmu_v2 *met_pmu;

+

+	met_pmu = get_met_pmu_by_cpu_id(*cpu);

+	met_pmu_hw_v2->start(met_pmu, gMAX_PMU_HW_CNT);

+}

+

+static void cpupmu_start(void)

+{

+	if (module_status == 1) {

+		PR_BOOTMSG("%s:%d\n", __FUNCTION__, __LINE__);

+		return;

+	}

+

+	if (met_cpu_pmu_method == 0) {

+		int this_cpu = smp_processor_id();

+		int cpu;

+

+		for_each_possible_cpu(cpu) {

+			if (cpu == this_cpu)

+				_cpupmu_start(&cpu);

+			else

+				met_smp_call_function_single_symbol(cpu, _cpupmu_start, &cpu, 1);

+		}

+	}

+	module_status = 1;

+}

+

+static void _cpupmu_stop(void *info)

+{

+	(void)info;

+

+	met_pmu_hw_v2->stop(gMAX_PMU_HW_CNT);

+}

+

+static void cpupmu_stop(void)

+{

+	if (module_status == 0) {

+		PR_BOOTMSG("%s:%d\n", __FUNCTION__, __LINE__);

+		return;

+	}

+

+	if (met_cpu_pmu_method == 0) {

+		int this_cpu = smp_processor_id();

+		int cpu;

+

+		for_each_possible_cpu(cpu) {

+			if (cpu == this_cpu)

+				_cpupmu_stop(&cpu);

+			else

+				met_smp_call_function_single_symbol(cpu, _cpupmu_stop, &cpu, 1);

+		}

+	}

+	module_status = 0;

+}

+

+static int cpupmu_print_help(char *buf, int len)

+{

+	return snprintf(buf, PAGE_SIZE, help, met_pmu_hw_v2->name, gMAX_PMU_HW_CNT - 1);

+}

+

+static int cpupmu_print_header(char *buf, int len)

+{

+	int i;

+	int ret = 0;

+	int pmu_cnt = 0;

+	char name[32];

+	unsigned int cpu;

+	struct met_pmu_v2 *met_pmu;

+

+	/*append CPU PMU access method*/

+	if (met_cpu_pmu_method == 0)

+		ret += snprintf(buf + ret, PAGE_SIZE,

+			"met-info [000] 0.0: CPU_PMU_method: PMU registers\n");

+	else

+		ret += snprintf(buf + ret, PAGE_SIZE,

+			"met-info [000] 0.0: CPU_PMU_method: perf APIs\n");

+

+	/*append cache line size*/

+	ret += snprintf(buf + ret, PAGE_SIZE - ret, cache_line_header, cache_line_size());

+	ret += snprintf(buf + ret, PAGE_SIZE - ret, header);

+	for_each_online_cpu(cpu) {

+		int cnt = 0;

+

+		pmu_cnt = gPMU_CNT[cpu];

+		met_pmu = get_met_pmu_by_cpu_id(cpu);

+		for (i = 0; i < pmu_cnt; i++) {

+			if (met_pmu[i].mode == 0)

+				continue;

+

+			if (met_pmu_hw_v2->get_event_desc && 0 == met_pmu_hw_v2->get_event_desc(met_pmu[i].event, name)) {

+				if (cnt == 0) {

+					ret += snprintf(buf + ret, PAGE_SIZE - ret, "CPU-%d=0x%x:%s", cpu, met_pmu[i].event, name);

+					cnt++;

+				} else

+					ret += snprintf(buf + ret, PAGE_SIZE - ret, ",0x%x:%s", met_pmu[i].event, name);

+			}

+			met_pmu[i].mode = 0;

+		}

+		if (cnt > 0 && cpu < MXNR_CPU_V2 - 1)

+			ret += snprintf(buf + ret, PAGE_SIZE - ret, ";");

+	}

+	ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");

+	met_cpupmu_v2.mode = 0;

+	reset_driver_stat();

+	return ret;

+}

+

+/*

+ * "met-cmd --start --pmu_core_evt=0:0x3,0x16,0x17"

+ */

+static int cpupmu_process_argument(const char *arg, int len)

+{

+	int ret;

+	unsigned int cpu;

+	unsigned int value;

+	unsigned int idx = 0;

+	char *str = NULL;

+	char *token = NULL;

+	struct met_pmu_v2 *met_pmu = NULL;

+

+	if (met_cpu_pmu_method == 0)

+		gMAX_PMU_HW_CNT = met_pmu_hw_v2->max_hw_count;

+	else

+		gMAX_PMU_HW_CNT = perf_num_counters();

+

+	if (gMAX_PMU_HW_CNT == 0) {

+		PR_BOOTMSG("%s:%d\n", __FUNCTION__, __LINE__);

+		goto arg_out;

+	}

+

+	str = kstrdup(arg, GFP_KERNEL);

+	token = strsep(&str, ":");

+	ret = met_parse_num(token, &cpu, strlen(token));

+	if (ret != 0) {

+		PR_BOOTMSG("%s:%d\n", __FUNCTION__, __LINE__);

+		goto arg_out;

+	}

+

+	met_pmu = get_met_pmu_by_cpu_id(cpu);

+	while (token && met_pmu && idx < gMAX_PMU_HW_CNT) {

+		token = strsep(&str, ",\r\n");

+		if (token) {

+			ret = met_parse_num(token, &value, strlen(token));

+			if (ret != 0) {

+				PR_BOOTMSG("%s:%d\n", __FUNCTION__, __LINE__);

+				goto arg_out;

+			}

+			if (value != 0xff) {

+				if (idx >= (gMAX_PMU_HW_CNT - 1)) {

+					PR_BOOTMSG("%s:%d\n", __FUNCTION__, __LINE__);

+					goto arg_out;

+				}

+				met_pmu[idx].mode = MODE_POLLING;

+				met_pmu[idx].event = value;

+				idx++;

+				gPMU_CNT[cpu]++;

+			} else {

+				if (met_cpu_pmu_method == 0) {

+					met_pmu[gMAX_PMU_HW_CNT - 1].mode = MODE_POLLING;

+					met_pmu[gMAX_PMU_HW_CNT - 1].event = 0xff;

+					gPMU_CNT[cpu]++;

+				} else {

+					if (idx > (gMAX_PMU_HW_CNT - 1)) {

+						PR_BOOTMSG("%s:%d\n", __FUNCTION__, __LINE__);

+						goto arg_out;

+					}

+					met_pmu[idx].mode = MODE_POLLING;

+					met_pmu[idx].event = 0xff;

+					idx++;

+					gPMU_CNT[cpu]++;

+				}

+			}

+			if (met_pmu_hw_v2->check_event(met_pmu, gPMU_CNT[cpu], value) < 0) {

+				PR_BOOTMSG("%s:%d\n", __FUNCTION__, __LINE__);

+				goto arg_out;

+			}

+		}

+	}

+	met_cpupmu_v2.mode = 1;

+	module_status = 0;

+	return 0;

+

+arg_out:

+	if (str)

+		kfree(str);

+	reset_driver_stat();

+	return -EINVAL;

+}