blob: 203708cc24f2007d08b3794b80b1ae57c44c21c4 [file] [log] [blame]
/*
* 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/page.h>
#include "interface.h"
#include "met_drv.h"
#ifdef CONFIG_GPU_TRACEPOINTS
#include <trace/events/gpu.h>
#define show_secs_from_ns(ns) \
({ \
u64 t = ns + (NSEC_PER_USEC / 2); \
do_div(t, NSEC_PER_SEC); \
t; \
})
#define show_usecs_from_ns(ns) \
({ \
u64 t = ns + (NSEC_PER_USEC / 2) ; \
u32 rem; \
do_div(t, NSEC_PER_USEC); \
rem = do_div(t, USEC_PER_SEC); \
})
static int event_gpu_registered;
static int event_gpu_enabled;
noinline void gpu_sched_switch(const char *gpu_name, u64 timestamp,
u32 next_ctx_id, s32 next_prio, u32 next_job_id)
{
MET_TRACE("gpu_name=%s ts=%llu.%06lu next_ctx_id=%lu next_prio=%ld next_job_id=%lu\n",
gpu_name,
(unsigned long long)show_secs_from_ns(timestamp),
(unsigned long)show_usecs_from_ns(timestamp),
(unsigned long)next_ctx_id, (long)next_prio, (unsigned long)next_job_id);
}
MET_DEFINE_PROBE(gpu_sched_switch, TP_PROTO(const char *gpu_name, u64 timestamp,
u32 next_ctx_id, s32 next_prio, u32 next_job_id))
{
gpu_sched_switch(gpu_name, timestamp, next_ctx_id, next_prio, next_job_id);
}
noinline void gpu_job_enqueue(u32 ctx_id, u32 job_id, const char *type)
{
MET_TRACE("ctx_id=%lu job_id=%lu type=%s",
(unsigned long)ctx_id, (unsigned long)job_id, type);
}
MET_DEFINE_PROBE(gpu_job_enqueue, TP_PROTO(u32 ctx_id, u32 job_id, const char *type))
{
gpu_job_enqueue(ctx_id, job_id, type);
}
#endif
#ifdef MET_EVENT_POWER_SUPPORT
#include "met_power.h"
#include "met_kernel_symbol.h"
static int event_power_registered;
static int event_power_enabled;
const char *
met_trace_print_symbols_seq(char* pclass_name, unsigned long val,
const struct trace_print_flags *symbol_array)
{
int i;
size_t new_fsize=0;
char _buf[32];
const char *ret = pclass_name;
for (i = 0; symbol_array[i].name; i++) {
if (val != symbol_array[i].mask)
continue;
new_fsize = sprintf(pclass_name, symbol_array[i].name, strlen(symbol_array[i].name));
break;
}
if (new_fsize == 0) {
snprintf(_buf, 32, "0x%lx", val);
new_fsize = sprintf(pclass_name, _buf, strlen(_buf));
}
return ret;
}
#define __print_symbolic(pclass_name, value, symbol_array...) \
({ \
static const struct trace_print_flags symbols[] = \
{ symbol_array, { -1, NULL }}; \
met_trace_print_symbols_seq(pclass_name, value, symbols); \
})
#ifdef pm_qos_update_request
#undef pm_qos_update_request
#endif
void pm_qos_update_request(int pm_qos_class, s32 value, char *owner)
{
char class_name[64];
MET_TRACE("pm_qos_class=%s value=%d owner=%s\n",
__print_symbolic(class_name, pm_qos_class,
{ _PM_QOS_CPU_DMA_LATENCY, "CPU_DMA_LATENCY" },
{ _PM_QOS_NETWORK_LATENCY, "NETWORK_LATENCY" },
{ _PM_QOS_NETWORK_THROUGHPUT, "NETWORK_THROUGHPUT" }),
value, owner);
}
//#endif
#ifdef pm_qos_update_target
#undef pm_qos_update_target
#endif
void pm_qos_update_target(unsigned int action, int prev_value, int curr_value)
{
char class_name[64];
MET_TRACE("action=%s prev_value=%d curr_value=%d\n",
__print_symbolic(class_name, action,
{ _PM_QOS_ADD_REQ, "ADD_REQ" },
{ _PM_QOS_UPDATE_REQ, "UPDATE_REQ" },
{ _PM_QOS_REMOVE_REQ, "REMOVE_REQ" }),
prev_value, curr_value);
}
#endif
//#endif
static int reset_driver_stat(void)
{
#ifdef CONFIG_GPU_TRACEPOINTS
event_gpu_enabled = 0;
#endif
#ifdef MET_EVENT_POWER_SUPPORT
event_power_enabled = 0;
#endif
met_trace_event.mode = 0;
return 0;
}
static void met_event_start(void)
{
#ifdef CONFIG_GPU_TRACEPOINTS
/* register trace event for gpu */
do {
if (!event_gpu_enabled)
break;
if (MET_REGISTER_TRACE(gpu_sched_switch)) {
pr_debug("can not register callback of gpu_sched_switch\n");
break;
}
if (MET_REGISTER_TRACE(gpu_job_enqueue)) {
pr_debug("can not register callback of gpu_job_enqueue\n");
MET_UNREGISTER_TRACE(gpu_sched_switch);
break;
}
event_gpu_registered = 1;
} while (0);
#endif
#ifdef MET_EVENT_POWER_SUPPORT
/* register trace event for power */
do {
if (!event_power_enabled)
break;
if (met_reg_event_power_symbol)
if (met_reg_event_power_symbol()) {
pr_debug("can not register callback of met_reg_event_power\n");
break;
}
event_power_registered = 1;
} while (0);
#endif
}
static void met_event_stop(void)
{
#ifdef CONFIG_GPU_TRACEPOINTS
/* unregister trace event for gpu */
if (event_gpu_registered) {
MET_UNREGISTER_TRACE(gpu_job_enqueue);
MET_UNREGISTER_TRACE(gpu_sched_switch);
event_gpu_registered = 0;
}
#endif
#ifdef MET_EVENT_POWER_SUPPORT
/* unregister trace event for power */
if (event_power_registered) {
if (met_unreg_event_power_symbol)
met_unreg_event_power_symbol();
event_power_registered = 0;
}
#endif
}
static int met_event_process_argument(const char *arg, int len)
{
int ret = -1;
#ifdef CONFIG_GPU_TRACEPOINTS
if (strcasecmp(arg, "gpu") == 0) {
event_gpu_enabled = 1;
met_trace_event.mode = 1;
ret = 0;
}
#endif
#ifdef MET_EVENT_POWER_SUPPORT
if (strcasecmp(arg, "power") == 0) {
event_power_enabled = 1;
met_trace_event.mode = 1;
ret = 0;
}
#endif
return ret;
}
static const char help[] = "\b"
#ifdef CONFIG_GPU_TRACEPOINTS
" --event=gpu output gpu trace events\n"
#endif
#ifdef MET_EVENT_POWER_SUPPORT
" --event=power output pmqos trace events\n"
#endif
;
static int met_event_print_help(char *buf, int len)
{
return snprintf(buf, PAGE_SIZE, help);
}
static const char header[] =
"met-info [000] 0.0: met_ftrace_event:"
#ifdef CONFIG_GPU_TRACEPOINTS
" gpu:gpu_sched_switch gpu:gpu_job_enqueue"
#endif
#ifdef MET_EVENT_POWER_SUPPORT
" power:pm_qos_update_request power:pm_qos_update_target"
#endif
"\n";
static int met_event_print_header(char *buf, int len)
{
int ret;
ret = snprintf(buf, PAGE_SIZE, header);
return ret;
}
struct metdevice met_trace_event = {
.name = "event",
.type = MET_TYPE_PMU,
.start = met_event_start,
.stop = met_event_stop,
.reset = reset_driver_stat,
.process_argument = met_event_process_argument,
.print_help = met_event_print_help,
.print_header = met_event_print_header,
};