/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2019 MediaTek Inc. */ #define MET_USER_EVENT_SUPPORT /*Turn met user event*/ #include #include #include "vpu_cmn.h" #include "vpu_reg.h" #include "vpu_profile.h" /* MET: define to enable MET */ #if defined(VPU_MET_READY) #include #define CREATE_TRACE_POINTS #include "met_vpusys_events.h" #endif #define DEFAULT_POLLING_PERIOD_NS (1000000) #define COUNTER_PID (0) /*(65535)*/ /*task_pid_nr(current)*/ #define BEGINEND_PID (0) /*(65535)*/ /*task_pid_nr(current)*/ #define ASYNCBEGINEND_PID (0) /*(65535)*/ /*task_pid_nr(current)*/ static int m_vpu_profile_state; static struct hrtimer hr_timer; static uint64_t vpu_base[MTK_VPU_CORE]; static bool vpu_on[MTK_VPU_CORE]; static struct mutex profile_mutex; static int profiling_counter; static int stop_result; static int vpu_counter[MTK_VPU_CORE][4]; /* * mini trace system * [KATRACE] mini trace system */ #define KATRACE_MESSAGE_LENGTH 1024 static noinline int tracing_mark_write(const char *buf) { #if defined(VPU_MET_READY) TRACE_PUTS(buf); #endif return 0; } /* * [KATRACE] Begin-End */ #define KATRACE_BEGIN(name) katrace_begin_body(name) void katrace_begin_body(const char *name) { char buf[KATRACE_MESSAGE_LENGTH]; int len = snprintf(buf, sizeof(buf), "B|%d|%s", BEGINEND_PID, name); if (len >= (int) sizeof(buf)) { LOG_DBG("Truncated name in %s: %s\n", __func__, name); len = sizeof(buf) - 1; } tracing_mark_write(buf); } #define KATRACE_END() katrace_end() inline void katrace_end(void) { char c = 'E'; tracing_mark_write(&c); } #define WRITE_MSG(format_begin, format_end, pid, name, value) { \ char buf[KATRACE_MESSAGE_LENGTH]; \ int len = snprintf(buf, sizeof(buf), \ format_begin "%s" format_end, pid, \ name, value); \ if (len >= (int) sizeof(buf)) { \ /* Given the sizeof(buf), and all of the current */ \ /* format buffers, it is impossible for name_len */ \ /* to be < 0 if len >= sizeof(buf). */ \ int name_len = strlen(name) - (len - sizeof(buf)) - 1; \ /* Truncate the name to make the message fit. */ \ LOG_DBG("Truncated name in %s: %s\n", __func__, name); \ len = snprintf(buf, sizeof(buf), \ format_begin "%.*s" format_end, pid, \ name_len, name, value); \ } \ tracing_mark_write(buf); \ } /* * [KATRACE] Counter Integer */ #define KATRACE_INT(name, value) katrace_int_body(name, value) void katrace_int_body(const char *name, int32_t value) { WRITE_MSG("C|%d|", "|%d", COUNTER_PID, name, value); } /* * [KATRACE] Async Begin-End */ #define KATRACE_ASYNC_BEGIN(name, cookie) \ katrace_async_begin_body(name, cookie) void katrace_async_begin_body(const char *name, int32_t cookie) { WRITE_MSG("S|%d|", "|%d", ASYNCBEGINEND_PID, name, cookie); } #define KATRACE_ASYNC_END(name, cookie) katrace_async_end_body(name, cookie) void katrace_async_end_body(const char *name, int32_t cookie) { WRITE_MSG("F|%d|", "|%d", ASYNCBEGINEND_PID, name, cookie); } /* * VPU event based MET funcs */ void vpu_met_event_enter(int core, int algo_id, int dsp_freq) { #if defined(VPU_MET_READY) trace_VPU__D2D_enter(core, algo_id, dsp_freq); #endif } void vpu_met_event_leave(int core, int algo_id) { #if defined(VPU_MET_READY) trace_VPU__D2D_leave(core, algo_id, 0); #endif } void vpu_met_packet(long long wclk, char action, int core, int pid, int sessid, char *str_desc, int val) { #if defined(VPU_MET_READY) trace___MET_PACKET__(wclk, action, core, pid, sessid, str_desc, val); #endif } /* * VPU event based MET funcs */ void vpu_met_event_dvfs(int vcore_opp, int dsp_freq, int ipu_if_freq, int dsp1_freq, int dsp2_freq) { #if defined(VPU_MET_READY) trace_VPU__DVFS(vcore_opp, dsp_freq, ipu_if_freq, dsp1_freq, dsp2_freq); #endif } /* * VPU counter reader */ static void vpu_profile_core_read(int core) { int i; uint32_t value[4]; /* read register and send to met */ for (i = 0; i < 4; i++) { uint32_t counter; counter = vpu_read_reg32(vpu_base[core], DEBUG_BASE_OFFSET + 0x1080 + i * 4); value[i] = (counter - vpu_counter[core][i]); vpu_counter[core][i] = counter; } LOG_DBG("[vpu_profile_%d] read %d/%d/%d/%d\n", core, value[0], value[1], value[2], value[3]); LOG_DBG("[vpu_profile_%d] read %d/%d/%d/%d\n", core, value1, value2, value3, value4); #if defined(VPU_MET_READY) trace_VPU__polling(core, value[0], value[1], value[2], value[3]); #endif } static void vpu_profile_register_read(void) { int i = 0; for (i = 0 ; i < MTK_VPU_CORE; i++) if (vpu_on[i]) vpu_profile_core_read(i); } /* * VPU Polling Function */ static enum hrtimer_restart vpu_profile_polling(struct hrtimer *timer) { LOG_DBG("%s +\n", __func__); /*call functions need to be called periodically*/ vpu_profile_register_read(); hrtimer_forward_now(&hr_timer, ns_to_ktime(DEFAULT_POLLING_PERIOD_NS)); LOG_DBG("%s -\n", __func__); return HRTIMER_RESTART; } static int vpu_profile_timer_start(void) { hrtimer_init(&hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); hr_timer.function = vpu_profile_polling; hrtimer_start(&hr_timer, ns_to_ktime(DEFAULT_POLLING_PERIOD_NS), HRTIMER_MODE_REL); return 0; } static int vpu_profile_timer_try_stop(void) { int ret = 0; ret = hrtimer_try_to_cancel(&hr_timer); return ret; } static int vpu_profile_timer_stop(void) { hrtimer_cancel(&hr_timer); return 0; } static uint32_t make_pm_ctrl(uint32_t selector, uint32_t mask) { uint32_t ctrl = PERF_PMCTRL_TRACELEVEL; ctrl |= selector << PERF_PMCTRL_SELECT_SHIFT; ctrl |= mask << PERF_PMCTRL_MASK_SHIFT; return ctrl; } static void vpu_profile_core_start(int core) { uint64_t ptr_axi_2; uint64_t ptr_pmg, ptr_pmctrl0, ptr_pmstat0, ptr_pmcounter0; uint32_t ctrl[4]; int i; ptr_axi_2 = vpu_base[core] + g_vpu_reg_descs[REG_AXI_DEFAULT2].offset; ptr_pmg = vpu_base[core] + DEBUG_BASE_OFFSET + 0x1000; ptr_pmcounter0 = vpu_base[core] + DEBUG_BASE_OFFSET + 0x1080; ptr_pmctrl0 = vpu_base[core] + DEBUG_BASE_OFFSET + 0x1100; ptr_pmstat0 = vpu_base[core] + DEBUG_BASE_OFFSET + 0x1180; /* enable */ VPU_SET_BIT(ptr_axi_2, 0); VPU_SET_BIT(ptr_axi_2, 1); VPU_SET_BIT(ptr_axi_2, 2); VPU_SET_BIT(ptr_axi_2, 3); ctrl[0] = make_pm_ctrl(XTPERF_CNT_INSN, XTPERF_MASK_INSN_ALL); ctrl[1] = make_pm_ctrl(XTPERF_CNT_IDMA, XTPERF_MASK_IDMA_ACTIVE_CYCLES); ctrl[2] = make_pm_ctrl(XTPERF_CNT_D_STALL, XTPERF_MASK_D_STALL_UNCACHED_LOAD); ctrl[3] = make_pm_ctrl(XTPERF_CNT_I_STALL, XTPERF_MASK_I_STALL_CACHE_MISS); /*ctrl[2] = make_pm_ctrl(XTPERF_CNT_EXR, XTPERF_MASK_EXR_ALL);*/ /*ctrl[3] = make_pm_ctrl(XTPERF_CNT_BUBBLES, XTPERF_MASK_BUBBLES_ALL);*/ /* read register and send to met */ for (i = 0; i < 4; i++) { vpu_write_reg32(ptr_pmctrl0, i * 4, ctrl[i]); vpu_write_reg32(ptr_pmstat0, i * 4, 0); vpu_write_reg32(ptr_pmcounter0, i * 4, 0); vpu_counter[core][i] = 0; } /* 0: PERF_PMG_ENABLE */ VPU_SET_BIT(ptr_pmg, 0); } static int vpu_profile_start(int core) { LOG_DBG("%s +\n", __func__); if (vpu_on[core]) vpu_profile_core_start(core); LOG_DBG("%s -\n", __func__); return 0; } static int vpu_profile_stop(int type) { LOG_INF("%s (%d)+\n", __func__, type); if (type) stop_result = vpu_profile_timer_try_stop(); else vpu_profile_timer_stop(); LOG_DBG("%s (%d/%d)-\n", __func__, type, stop_result); return 0; } int vpu_profile_state_set(int core, int val) { switch (val) { case 0: mutex_lock(&profile_mutex); profiling_counter--; vpu_on[core] = false; LOG_INF("[vpu_profile_%d->%d] (stop) counter(%d, %d)\n", core, vpu_on[core], m_vpu_profile_state, profiling_counter); if (profiling_counter == 0) { m_vpu_profile_state = val; mutex_unlock(&profile_mutex); vpu_profile_stop(0); } else { mutex_unlock(&profile_mutex); } break; case 1: mutex_lock(&profile_mutex); profiling_counter++; vpu_on[core] = true; LOG_INF("[vpu_profile_%d->%d] (start) counter(%d, %d)\n", core, vpu_on[core], m_vpu_profile_state, profiling_counter); m_vpu_profile_state = val; mutex_unlock(&profile_mutex); vpu_profile_start(core); if (profiling_counter == 1) vpu_profile_timer_start(); break; default: /*unsupported command*/ return -1; } LOG_DBG("vpu_profile (%d) -\n", val); return 0; } int vpu_profile_state_get(void) { return m_vpu_profile_state; } int vpu_init_profile(int core, struct vpu_device *device) { int i = 0; m_vpu_profile_state = 0; stop_result = 0; vpu_base[core] = device->vpu_base[core]; for (i = 0 ; i < MTK_VPU_CORE; i++) vpu_on[i] = false; profiling_counter = 0; mutex_init(&profile_mutex); return 0; } int vpu_uninit_profile(void) { int i = 0; for (i = 0 ; i < MTK_VPU_CORE; i++) vpu_on[i] = false; if (stop_result) vpu_profile_stop(0); return 0; }