1
0
mirror of https://github.com/physwizz/a155-U-u1.git synced 2024-11-19 13:27:49 +00:00
a155-U-u1/kernel-5.10/drivers/misc/mediatek/aee/aed/slog.c
2024-03-11 06:53:12 +11:00

258 lines
6.1 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2015 MediaTek Inc.
*/
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/tracepoint.h>
#include <mt-plat/aee.h>
#define CREATE_TRACE_POINTS
#include <mt-plat/slog.h>
/**
* Data structures to store tracepoints information
*/
struct tracepoints_table {
const char *name;
const char *mod_name;
bool module;
void *func;
struct tracepoint *tp;
bool init;
};
static unsigned int ufs_count;
static unsigned int ccci_count;
static unsigned int gpu_count;
static unsigned int threshold;
static struct proc_dir_entry *dir;
void slog(const char *fmt, ...)
{
struct va_format vaf;
va_list args;
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
trace_slog(&vaf);
va_end(args);
}
static void probe_ufs_mtk_event(void *data, unsigned int type,
unsigned int val)
{
ufs_count++;
slog("#$#ufs#@#event#%lu:%lu(0x%x)#%d", type, val, val, ufs_count);
if ((threshold > 0) && ((ufs_count % threshold) == 0)) {
aee_kernel_exception("ufs", "occur:%d, threshold:%d\n", ufs_count, threshold);
}
}
static void probe_ccci_event(void *data, char *string, char *sub_string,
unsigned int sub_type, unsigned int resv)
{
ccci_count++;
slog("#$#%s#@#%s#%d:%d#%d", string, sub_string, sub_type, resv, ccci_count);
}
static void probe_gpu_hardstop_event(void *data, char *string, char *sub_string,
unsigned int gpu_freq, unsigned int gpu_volt, unsigned int gpu_vsram,
unsigned int stack_freq, unsigned int stack_volt, unsigned int stack_vsram)
{
gpu_count++;
slog("#$#%s#@#%s#%d:%d:%d:%d:%d:%d#%d",
string, sub_string, gpu_freq, gpu_volt, gpu_vsram,
stack_freq, stack_volt, stack_vsram, gpu_count);
}
static struct tracepoints_table interests[] = {
{.name = "ufs_mtk_event", .mod_name = NULL, .module = false, .func = probe_ufs_mtk_event},
{.name = "ccci_event", .mod_name = NULL, .module = false, .func = probe_ccci_event},
{.name = "gpu_hardstop", .mod_name = "mtk_gpufreq_wrapper", .module = true, .func = probe_gpu_hardstop_event},
};
/**
* Find the struct tracepoint* associated with a given tracepoint
* name.
*/
static void lookup_tracepoints(struct tracepoint *tp, void *ignore)
{
int i;
for (i = 0; i < ARRAY_SIZE(interests); i++) {
if ((interests[i].module == false) && (strcmp(interests[i].name, tp->name) == 0)) {
interests[i].tp = tp;
tracepoint_probe_register(interests[i].tp, interests[i].func, NULL);
interests[i].init = true;
}
}
}
static void cleanup(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(interests); i++) {
if (interests[i].init) {
tracepoint_probe_unregister(interests[i].tp,
interests[i].func, NULL);
}
}
}
#ifdef MODULE
static int slog_module_callback(struct notifier_block *nb,
unsigned long val, void *data)
{
struct module *mod = data;
tracepoint_ptr_t *iter, *begin, *end;
struct tracepoint *tp;
int i;
if (val !=MODULE_STATE_LIVE)
return NOTIFY_DONE;
for (i = 0; i < ARRAY_SIZE(interests); i++) {
if ((interests[i].module == true) && (interests[i].init == false)) {
begin = mod->tracepoints_ptrs;
end = mod->tracepoints_ptrs + mod->num_tracepoints;
for (iter = begin; iter < end; iter++) {
tp = tracepoint_ptr_deref(iter);
if (strcmp(interests[i].name, tp->name) == 0) {
interests[i].tp = tp;
tracepoint_probe_register(interests[i].tp, interests[i].func, NULL);
interests[i].init = true;
}
}
}
}
return NOTIFY_OK;
}
static struct notifier_block slog_module_nb = {
.notifier_call = slog_module_callback,
};
#endif
static int slog_threshold_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "slog threshold: %d\n", threshold);
return 0;
}
static char *_copy_from_user_for_proc(const char __user *buffer, size_t count)
{
char *buf = (char *)__get_free_page(GFP_USER);
if (!buf)
return NULL;
if (count >= PAGE_SIZE)
goto out;
if (copy_from_user(buf, buffer, count))
goto out;
buf[count] = '\0';
return buf;
out:
free_page((unsigned long)buf);
return NULL;
}
static ssize_t slog_threshold_proc_write(struct file *file,
const char __user *buffer, size_t count, loff_t *pos)
{
unsigned int num;
int rc;
char *buf = _copy_from_user_for_proc(buffer, count);
if (!buf)
return -EINVAL;
rc = kstrtouint(buf, 10, &num);
if (rc < 0)
pr_info("transfer string to int error\n");
else
threshold = num;
free_page((unsigned long)buf);
pr_info("set threshold to %d\n", threshold);
return count;
}
#define PROC_FOPS_RW(name) \
static int name ## _proc_open(struct inode *inode, struct file *file) \
{ \
return single_open(file, name ## _proc_show, PDE_DATA(inode)); \
} \
static const struct proc_ops name ## _proc_fops = { \
.proc_open = name ## _proc_open, \
.proc_read = seq_read, \
.proc_lseek = seq_lseek, \
.proc_release = single_release, \
.proc_write = name ## _proc_write, \
}
#define PROC_ENTRY(name) {__stringify(name), &name ## _proc_fops}
PROC_FOPS_RW(slog_threshold);
int slog_procfs_init(void)
{
int i = 0;
struct pentry {
const char *name;
const struct proc_ops *fops;
};
const struct pentry entries[] = {
PROC_ENTRY(slog_threshold),
};
dir = proc_mkdir("slog", NULL);
if (!dir) {
pr_info("mkdir /proc/slog failed\n");
return -ENOMEM;
}
for (i = 0; i < ARRAY_SIZE(entries); i++) {
if (!proc_create(entries[i].name, 0640, dir, entries[i].fops))
pr_info("create /proc/slog/%s failed\n", entries[i].name);
}
return 0;
}
int mtk_slog_init(void)
{
#ifdef MODULE
register_module_notifier(&slog_module_nb);
#endif
for_each_kernel_tracepoint(lookup_tracepoints, NULL);
slog_procfs_init();
return 0;
}
void mtk_slog_exit(void)
{
#ifdef MODULE
unregister_module_notifier(&slog_module_nb);
#endif
remove_proc_entry("slog_threshold", dir);
cleanup();
}