kernel-brax3-ubuntu-touch/drivers/misc/mediatek/performance/fpsgo_v3/fpsgo_main.c
erascape f319b992b1 kernel-5.15: Initial import brax3 UT kernel
* halium configs enabled

Signed-off-by: erascape <erascape@proton.me>
2025-09-23 15:17:10 +00:00

886 lines
19 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include <linux/kthread.h>
#include <sched/sched.h>
#include <linux/unistd.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/cpufreq.h>
#include <linux/topology.h>
#include <linux/arch_topology.h>
#include <linux/cpumask.h>
#include <trace/events/power.h>
#include <linux/tracepoint.h>
#include <linux/kallsyms.h>
#include "mt-plat/fpsgo_common.h"
#include "fpsgo_base.h"
#include "fpsgo_sysfs.h"
#include "fpsgo_usedext.h"
#include "fpsgo_cpu_policy.h"
#include "fbt_cpu.h"
#include "fstb.h"
#include "fps_composer.h"
#include "xgf.h"
#include "mtk_drm_arr.h"
#include "gbe_common.h"
#define CREATE_TRACE_POINTS
#define TARGET_UNLIMITED_FPS 240
enum FPSGO_NOTIFIER_PUSH_TYPE {
FPSGO_NOTIFIER_SWITCH_FPSGO = 0x00,
FPSGO_NOTIFIER_QUEUE_DEQUEUE = 0x01,
FPSGO_NOTIFIER_CONNECT = 0x02,
FPSGO_NOTIFIER_DFRC_FPS = 0x03,
FPSGO_NOTIFIER_BQID = 0x04,
FPSGO_NOTIFIER_VSYNC = 0x05,
FPSGO_NOTIFIER_SWAP_BUFFER = 0x06,
FPSGO_NOTIFIER_SBE_RESCUE = 0x07,
};
/* TODO: use union*/
struct FPSGO_NOTIFIER_PUSH_TAG {
enum FPSGO_NOTIFIER_PUSH_TYPE ePushType;
int pid;
unsigned long long cur_ts;
int enable;
int qudeq_cmd;
unsigned int queue_arg;
unsigned long long bufID;
int connectedAPI;
int queue_SF;
unsigned long long identifier;
int create;
int dfrc_fps;
int enhance;
unsigned long long frameID;
struct list_head queue_list;
};
static struct mutex notify_lock;
static struct task_struct *kfpsgo_tsk;
static int fpsgo_enable;
static int fpsgo_force_onoff;
static int gpu_boost_enable_perf;
static int gpu_boost_enable_camera;
static int perfserv_ta;
int powerhal_tid;
void (*rsu_cpufreq_notifier_fp)(int cluster_id, unsigned long freq);
/* TODO: event register & dispatch */
int fpsgo_is_enable(void)
{
int enable;
mutex_lock(&notify_lock);
enable = fpsgo_enable;
mutex_unlock(&notify_lock);
FPSGO_LOGI("[FPSGO_CTRL] isenable %d\n", enable);
return enable;
}
static void fpsgo_notifier_wq_cb_vsync(unsigned long long ts)
{
FPSGO_LOGI("[FPSGO_CB] vsync: %llu\n", ts);
if (!fpsgo_is_enable())
return;
fpsgo_ctrl2fbt_vsync(ts);
}
static void fpsgo_notifier_wq_cb_swap_buffer(int pid)
{
FPSGO_LOGI("[FPSGO_CB] swap_buffer: %d\n", pid);
if (!fpsgo_is_enable())
return;
fpsgo_update_swap_buffer(pid);
}
static void fpsgo_notifier_wq_cb_sbe_rescue(int pid, int start, int enhance,
unsigned long long frameID)
{
FPSGO_LOGI("[FPSGO_CB] sbe_rescue: %d\n", pid);
if (!fpsgo_is_enable())
return;
fpsgo_sbe_rescue_traverse(pid, start, enhance, frameID);
}
static void fpsgo_notifier_wq_cb_dfrc_fps(int dfrc_fps)
{
FPSGO_LOGI("[FPSGO_CB] dfrc_fps %d\n", dfrc_fps);
fpsgo_ctrl2fstb_dfrc_fps(dfrc_fps);
fpsgo_ctrl2fbt_dfrc_fps(dfrc_fps);
}
static void fpsgo_notifier_wq_cb_connect(int pid,
int connectedAPI, unsigned long long id)
{
FPSGO_LOGI(
"[FPSGO_CB] connect: pid %d, API %d, id %llu\n",
pid, connectedAPI, id);
if (connectedAPI == WINDOW_DISCONNECT)
fpsgo_ctrl2comp_disconnect_api(pid, connectedAPI, id);
else
fpsgo_ctrl2comp_connect_api(pid, connectedAPI, id);
}
static void fpsgo_notifier_wq_cb_bqid(int pid, unsigned long long bufID,
int queue_SF, unsigned long long id, int create)
{
FPSGO_LOGI(
"[FPSGO_CB] bqid: pid %d, bufID %llu, queue_SF %d, id %llu, create %d\n",
pid, bufID, queue_SF, id, create);
fpsgo_ctrl2comp_bqid(pid, bufID, queue_SF, id, create);
}
static void fpsgo_notifier_wq_cb_qudeq(int qudeq,
unsigned int startend, int cur_pid,
unsigned long long curr_ts, unsigned long long id)
{
FPSGO_LOGI("[FPSGO_CB] qudeq: %d-%d, pid %d, ts %llu, id %llu\n",
qudeq, startend, cur_pid, curr_ts, id);
if (!fpsgo_is_enable())
return;
switch (qudeq) {
case 1:
if (startend) {
FPSGO_LOGI("[FPSGO_CB] QUEUE Start: pid %d\n",
cur_pid);
fpsgo_ctrl2comp_enqueue_start(cur_pid,
curr_ts, id);
} else {
FPSGO_LOGI("[FPSGO_CB] QUEUE End: pid %d\n",
cur_pid);
fpsgo_ctrl2comp_enqueue_end(cur_pid, curr_ts,
id);
}
break;
case 0:
if (startend) {
FPSGO_LOGI("[FPSGO_CB] DEQUEUE Start: pid %d\n",
cur_pid);
fpsgo_ctrl2comp_dequeue_start(cur_pid,
curr_ts, id);
} else {
FPSGO_LOGI("[FPSGO_CB] DEQUEUE End: pid %d\n",
cur_pid);
fpsgo_ctrl2comp_dequeue_end(cur_pid,
curr_ts, id);
}
break;
default:
break;
}
}
static void fpsgo_notifier_wq_cb_enable(int enable)
{
FPSGO_LOGI(
"[FPSGO_CB] enable %d, fpsgo_enable %d, force_onoff %d\n",
enable, fpsgo_enable, fpsgo_force_onoff);
mutex_lock(&notify_lock);
if (enable == fpsgo_enable) {
mutex_unlock(&notify_lock);
return;
}
if (fpsgo_force_onoff != FPSGO_FREE &&
enable != fpsgo_force_onoff) {
mutex_unlock(&notify_lock);
return;
}
fpsgo_ctrl2fbt_switch_fbt(enable);
fpsgo_ctrl2fstb_switch_fstb(enable);
fpsgo_ctrl2xgf_switch_xgf(enable);
fpsgo_enable = enable;
if (!fpsgo_enable)
fpsgo_clear();
FPSGO_LOGI("[FPSGO_CB] fpsgo_enable %d\n",
fpsgo_enable);
mutex_unlock(&notify_lock);
}
static LIST_HEAD(head);
static int condition_notifier_wq;
static DEFINE_MUTEX(notifier_wq_lock);
static DECLARE_WAIT_QUEUE_HEAD(notifier_wq_queue);
static void fpsgo_queue_work(struct FPSGO_NOTIFIER_PUSH_TAG *vpPush)
{
mutex_lock(&notifier_wq_lock);
list_add_tail(&vpPush->queue_list, &head);
condition_notifier_wq = 1;
mutex_unlock(&notifier_wq_lock);
wake_up_interruptible(&notifier_wq_queue);
}
static void fpsgo_notifier_wq_cb(void)
{
struct FPSGO_NOTIFIER_PUSH_TAG *vpPush;
wait_event_interruptible(notifier_wq_queue, condition_notifier_wq);
mutex_lock(&notifier_wq_lock);
if (!list_empty(&head)) {
vpPush = list_first_entry(&head,
struct FPSGO_NOTIFIER_PUSH_TAG, queue_list);
list_del(&vpPush->queue_list);
if (list_empty(&head))
condition_notifier_wq = 0;
mutex_unlock(&notifier_wq_lock);
} else {
condition_notifier_wq = 0;
mutex_unlock(&notifier_wq_lock);
return;
}
switch (vpPush->ePushType) {
case FPSGO_NOTIFIER_SWITCH_FPSGO:
fpsgo_notifier_wq_cb_enable(vpPush->enable);
break;
case FPSGO_NOTIFIER_QUEUE_DEQUEUE:
fpsgo_notifier_wq_cb_qudeq(vpPush->qudeq_cmd,
vpPush->queue_arg, vpPush->pid,
vpPush->cur_ts, vpPush->identifier);
break;
case FPSGO_NOTIFIER_CONNECT:
fpsgo_notifier_wq_cb_connect(vpPush->pid,
vpPush->connectedAPI, vpPush->identifier);
break;
case FPSGO_NOTIFIER_DFRC_FPS:
fpsgo_notifier_wq_cb_dfrc_fps(vpPush->dfrc_fps);
break;
case FPSGO_NOTIFIER_BQID:
fpsgo_notifier_wq_cb_bqid(vpPush->pid, vpPush->bufID,
vpPush->queue_SF, vpPush->identifier, vpPush->create);
break;
case FPSGO_NOTIFIER_VSYNC:
fpsgo_notifier_wq_cb_vsync(vpPush->cur_ts);
break;
case FPSGO_NOTIFIER_SWAP_BUFFER:
fpsgo_notifier_wq_cb_swap_buffer(vpPush->pid);
break;
case FPSGO_NOTIFIER_SBE_RESCUE:
fpsgo_notifier_wq_cb_sbe_rescue(vpPush->pid, vpPush->enable, vpPush->enhance,
vpPush->frameID);
break;
default:
FPSGO_LOGE("[FPSGO_CTRL] unhandled push type = %d\n",
vpPush->ePushType);
break;
}
fpsgo_free(vpPush, sizeof(struct FPSGO_NOTIFIER_PUSH_TAG));
}
static int kfpsgo(void *arg)
{
struct sched_attr attr = {};
attr.sched_policy = -1;
attr.sched_flags =
SCHED_FLAG_KEEP_ALL |
SCHED_FLAG_UTIL_CLAMP |
SCHED_FLAG_RESET_ON_FORK;
attr.sched_util_min = 1;
attr.sched_util_max = 1024;
if (sched_setattr_nocheck(current, &attr) != 0)
FPSGO_LOGE("[FPSGO_CTRL] %s set uclamp fail\n", __func__);
set_user_nice(current, -20);
while (!kthread_should_stop())
fpsgo_notifier_wq_cb();
return 0;
}
void fpsgo_notify_qudeq(int qudeq,
unsigned int startend,
int pid, unsigned long long id)
{
unsigned long long cur_ts;
struct FPSGO_NOTIFIER_PUSH_TAG *vpPush;
FPSGO_LOGI("[FPSGO_CTRL] qudeq %d-%d, id %llu pid %d\n",
qudeq, startend, id, pid);
if (!fpsgo_is_enable())
return;
vpPush =
(struct FPSGO_NOTIFIER_PUSH_TAG *)
fpsgo_alloc_atomic(sizeof(struct FPSGO_NOTIFIER_PUSH_TAG));
if (!vpPush) {
FPSGO_LOGE("[FPSGO_CTRL] OOM\n");
return;
}
if (!kfpsgo_tsk) {
FPSGO_LOGE("[FPSGO_CTRL] NULL WorkQueue\n");
fpsgo_free(vpPush, sizeof(struct FPSGO_NOTIFIER_PUSH_TAG));
return;
}
cur_ts = fpsgo_get_time();
vpPush->ePushType = FPSGO_NOTIFIER_QUEUE_DEQUEUE;
vpPush->pid = pid;
vpPush->cur_ts = cur_ts;
vpPush->qudeq_cmd = qudeq;
vpPush->queue_arg = startend;
vpPush->identifier = id;
fpsgo_queue_work(vpPush);
}
void fpsgo_notify_connect(int pid,
int connectedAPI, unsigned long long id)
{
struct FPSGO_NOTIFIER_PUSH_TAG *vpPush;
FPSGO_LOGI(
"[FPSGO_CTRL] connect pid %d, id %llu, API %d\n",
pid, id, connectedAPI);
vpPush =
(struct FPSGO_NOTIFIER_PUSH_TAG *)
fpsgo_alloc_atomic(sizeof(struct FPSGO_NOTIFIER_PUSH_TAG));
if (!vpPush) {
FPSGO_LOGE("[FPSGO_CTRL] OOM\n");
return;
}
if (!kfpsgo_tsk) {
FPSGO_LOGE("[FPSGO_CTRL] NULL WorkQueue\n");
fpsgo_free(vpPush, sizeof(struct FPSGO_NOTIFIER_PUSH_TAG));
return;
}
vpPush->ePushType = FPSGO_NOTIFIER_CONNECT;
vpPush->pid = pid;
vpPush->connectedAPI = connectedAPI;
vpPush->identifier = id;
fpsgo_queue_work(vpPush);
}
void fpsgo_notify_bqid(int pid, unsigned long long bufID,
int queue_SF, unsigned long long id, int create)
{
struct FPSGO_NOTIFIER_PUSH_TAG *vpPush;
FPSGO_LOGI("[FPSGO_CTRL] bqid pid %d, buf %llu, queue_SF %d, id %llu\n",
pid, bufID, queue_SF, id);
vpPush = (struct FPSGO_NOTIFIER_PUSH_TAG *)
fpsgo_alloc_atomic(sizeof(struct FPSGO_NOTIFIER_PUSH_TAG));
if (!vpPush) {
FPSGO_LOGE("[FPSGO_CTRL] OOM\n");
return;
}
if (!kfpsgo_tsk) {
FPSGO_LOGE("[FPSGO_CTRL] NULL WorkQueue\n");
fpsgo_free(vpPush, sizeof(struct FPSGO_NOTIFIER_PUSH_TAG));
return;
}
vpPush->ePushType = FPSGO_NOTIFIER_BQID;
vpPush->pid = pid;
vpPush->bufID = bufID;
vpPush->queue_SF = queue_SF;
vpPush->identifier = id;
vpPush->create = create;
fpsgo_queue_work(vpPush);
}
int fpsgo_perfserv_ta_value(void)
{
int value;
mutex_lock(&notify_lock);
value = perfserv_ta;
mutex_unlock(&notify_lock);
return value;
}
void fpsgo_set_perfserv_ta(int value)
{
mutex_lock(&notify_lock);
perfserv_ta = value;
mutex_unlock(&notify_lock);
fpsgo_ctrl2fbt_switch_uclamp(!value);
}
void fpsgo_notify_vsync(void)
{
struct FPSGO_NOTIFIER_PUSH_TAG *vpPush;
FPSGO_LOGI("[FPSGO_CTRL] vsync\n");
if (!fpsgo_is_enable())
return;
vpPush = (struct FPSGO_NOTIFIER_PUSH_TAG *)
fpsgo_alloc_atomic(sizeof(struct FPSGO_NOTIFIER_PUSH_TAG));
if (!vpPush) {
FPSGO_LOGE("[FPSGO_CTRL] OOM\n");
return;
}
if (!kfpsgo_tsk) {
FPSGO_LOGE("[FPSGO_CTRL] NULL WorkQueue\n");
fpsgo_free(vpPush, sizeof(struct FPSGO_NOTIFIER_PUSH_TAG));
return;
}
vpPush->ePushType = FPSGO_NOTIFIER_VSYNC;
vpPush->cur_ts = fpsgo_get_time();
fpsgo_queue_work(vpPush);
}
void fpsgo_notify_swap_buffer(int pid)
{
struct FPSGO_NOTIFIER_PUSH_TAG *vpPush;
FPSGO_LOGI("[FPSGO_CTRL] swap_buffer\n");
if (!fpsgo_is_enable())
return;
vpPush = (struct FPSGO_NOTIFIER_PUSH_TAG *)
fpsgo_alloc_atomic(sizeof(struct FPSGO_NOTIFIER_PUSH_TAG));
if (!vpPush) {
FPSGO_LOGE("[FPSGO_CTRL] OOM\n");
return;
}
if (!kfpsgo_tsk) {
FPSGO_LOGE("[FPSGO_CTRL] NULL WorkQueue\n");
fpsgo_free(vpPush, sizeof(struct FPSGO_NOTIFIER_PUSH_TAG));
return;
}
vpPush->ePushType = FPSGO_NOTIFIER_SWAP_BUFFER;
vpPush->pid = pid;
fpsgo_queue_work(vpPush);
}
void fpsgo_notify_sbe_rescue(int pid, int start, int enhance, unsigned long long frameID)
{
struct FPSGO_NOTIFIER_PUSH_TAG *vpPush;
FPSGO_LOGI("[FPSGO_CTRL] sbe_rescue\n");
if (!fpsgo_is_enable())
return;
vpPush = (struct FPSGO_NOTIFIER_PUSH_TAG *)
fpsgo_alloc_atomic(sizeof(struct FPSGO_NOTIFIER_PUSH_TAG));
if (!vpPush) {
FPSGO_LOGE("[FPSGO_CTRL] OOM\n");
return;
}
if (!kfpsgo_tsk) {
FPSGO_LOGE("[FPSGO_CTRL] NULL WorkQueue\n");
fpsgo_free(vpPush, sizeof(struct FPSGO_NOTIFIER_PUSH_TAG));
return;
}
vpPush->ePushType = FPSGO_NOTIFIER_SBE_RESCUE;
vpPush->pid = pid;
vpPush->enable = start;
vpPush->enhance = enhance;
vpPush->frameID = frameID;
fpsgo_queue_work(vpPush);
}
void fpsgo_get_fps(int *pid, int *fps)
{
//int pid = -1, fps = -1;
if (unlikely(powerhal_tid == 0))
powerhal_tid = current->pid;
fpsgo_ctrl2fstb_get_fps(pid, fps);
FPSGO_LOGI("[FPSGO_CTRL] get_fps %d %d\n", *pid, *fps);
//return fps;
}
void fpsgo_get_cmd(int *cmd, int *value1, int *value2)
{
int _cmd = -1, _value1 = -1, _value2 = -1;
fpsgo_ctrl2base_get_pwr_cmd(&_cmd, &_value1, &_value2);
FPSGO_LOGI("[FPSGO_CTRL] get_cmd %d %d %d\n", _cmd, _value1, _value2);
*cmd = _cmd;
*value1 = _value1;
*value2 = _value2;
}
int fpsgo_get_fstb_active(long long time_diff)
{
return is_fstb_active(time_diff);
}
int fpsgo_wait_fstb_active(void)
{
return fpsgo_ctrl2fstb_wait_fstb_active();
}
void fpsgo_notify_cpufreq(int cid, unsigned long freq)
{
FPSGO_LOGI("[FPSGO_CTRL] cid %d, cpufreq %lu\n", cid, freq);
if (rsu_cpufreq_notifier_fp)
rsu_cpufreq_notifier_fp(cid, freq);
if (!fpsgo_enable)
return;
fpsgo_ctrl2fbt_cpufreq_cb_exp(cid, freq);
}
void dfrc_fps_limit_cb(unsigned int fps_limit)
{
unsigned int vTmp = TARGET_UNLIMITED_FPS;
struct FPSGO_NOTIFIER_PUSH_TAG *vpPush;
if (fps_limit > 0 && fps_limit <= TARGET_UNLIMITED_FPS)
vTmp = fps_limit;
FPSGO_LOGI("[FPSGO_CTRL] dfrc_fps %d\n", vTmp);
vpPush =
(struct FPSGO_NOTIFIER_PUSH_TAG *)
fpsgo_alloc_atomic(sizeof(struct FPSGO_NOTIFIER_PUSH_TAG));
if (!vpPush) {
FPSGO_LOGE("[FPSGO_CTRL] OOM\n");
return;
}
if (!kfpsgo_tsk) {
FPSGO_LOGE("[FPSGO_CTRL] NULL WorkQueue\n");
fpsgo_free(vpPush, sizeof(struct FPSGO_NOTIFIER_PUSH_TAG));
return;
}
vpPush->ePushType = FPSGO_NOTIFIER_DFRC_FPS;
vpPush->dfrc_fps = vTmp;
fpsgo_queue_work(vpPush);
}
/* FPSGO control */
void fpsgo_switch_enable(int enable)
{
struct FPSGO_NOTIFIER_PUSH_TAG *vpPush = NULL;
if (!kfpsgo_tsk) {
FPSGO_LOGE("[FPSGO_CTRL] NULL WorkQueue\n");
return;
}
if (fpsgo_arch_nr_clusters() <= 0) {
FPSGO_LOGE("[%s] DON'T ENABLE FPSGO: nr_cluster <= 0", __func__);
return;
}
FPSGO_LOGI("[FPSGO_CTRL] switch enable %d\n", enable);
if (fpsgo_is_force_enable() !=
FPSGO_FREE && enable !=
fpsgo_is_force_enable())
return;
vpPush =
(struct FPSGO_NOTIFIER_PUSH_TAG *)
fpsgo_alloc_atomic(sizeof(struct FPSGO_NOTIFIER_PUSH_TAG));
if (!vpPush) {
FPSGO_LOGE("[FPSGO_CTRL] OOM\n");
return;
}
vpPush->ePushType = FPSGO_NOTIFIER_SWITCH_FPSGO;
vpPush->enable = enable;
fpsgo_queue_work(vpPush);
}
int fpsgo_is_force_enable(void)
{
int temp_onoff;
mutex_lock(&notify_lock);
temp_onoff = fpsgo_force_onoff;
mutex_unlock(&notify_lock);
return temp_onoff;
}
void fpsgo_force_switch_enable(int enable)
{
mutex_lock(&notify_lock);
fpsgo_force_onoff = enable;
mutex_unlock(&notify_lock);
fpsgo_switch_enable(enable?1:0);
}
/* FSTB control */
int fpsgo_is_fstb_enable(void)
{
return is_fstb_enable();
}
int fpsgo_switch_fstb(int enable)
{
return fpsgo_ctrl2fstb_switch_fstb(enable);
}
int fpsgo_fstb_fps_range(int nr_level,
struct fps_level *level)
{
return switch_fps_range(nr_level, level);
}
int fpsgo_fstb_process_fps_range(char *proc_name,
int nr_level, struct fps_level *level)
{
return switch_process_fps_range(proc_name, nr_level, level);
}
int fpsgo_fstb_thread_fps_range(pid_t pid,
int nr_level, struct fps_level *level)
{
return switch_thread_fps_range(pid, nr_level, level);
}
struct tracepoints_table {
const char *name;
void *func;
struct tracepoint *tp;
bool registered;
};
static void fpsgo_cpu_frequency_tracer(void *ignore, unsigned int frequency, unsigned int cpu_id)
{
int cpu = 0, cluster = 0;
struct cpufreq_policy *policy = NULL;
#if IS_ENABLED(CONFIG_MTK_IRQ_MONITOR_DEBUG)
u64 ts[2];
ts[0] = sched_clock();
#endif
policy = cpufreq_cpu_get(cpu_id);
if (!policy)
return;
if (cpu_id != cpumask_first(policy->related_cpus)) {
cpufreq_cpu_put(policy);
return;
}
cpufreq_cpu_put(policy);
for_each_possible_cpu(cpu) {
policy = cpufreq_cpu_get(cpu);
if (!policy)
break;
cpu = cpumask_first(policy->related_cpus);
if (cpu == cpu_id)
break;
cpu = cpumask_last(policy->related_cpus);
cluster++;
cpufreq_cpu_put(policy);
}
if (policy) {
fpsgo_notify_cpufreq(cluster, frequency);
cpufreq_cpu_put(policy);
}
#if IS_ENABLED(CONFIG_MTK_IRQ_MONITOR_DEBUG)
ts[1] = sched_clock();
if ((ts[1] - ts[0] > 100000ULL) && in_hardirq()) {
printk_deferred("%s duration %llu, ts[0]=%llu, ts[1]=%llu\n",
__func__, ts[1] - ts[0], ts[0], ts[1]);
}
#endif
}
struct tracepoints_table fpsgo_tracepoints[] = {
{.name = "cpu_frequency", .func = fpsgo_cpu_frequency_tracer},
};
#define FOR_EACH_INTEREST(i) \
for (i = 0; i < sizeof(fpsgo_tracepoints) / sizeof(struct tracepoints_table); i++)
static void lookup_tracepoints(struct tracepoint *tp, void *ignore)
{
int i;
FOR_EACH_INTEREST(i) {
if (strcmp(fpsgo_tracepoints[i].name, tp->name) == 0)
fpsgo_tracepoints[i].tp = tp;
}
}
void tracepoint_cleanup(void)
{
int i;
FOR_EACH_INTEREST(i) {
if (fpsgo_tracepoints[i].registered) {
tracepoint_probe_unregister(
fpsgo_tracepoints[i].tp,
fpsgo_tracepoints[i].func, NULL);
fpsgo_tracepoints[i].registered = false;
}
}
}
static void __exit fpsgo_exit(void)
{
fpsgo_notifier_wq_cb_enable(0);
if (kfpsgo_tsk)
kthread_stop(kfpsgo_tsk);
#if IS_ENABLED(CONFIG_DRM_MEDIATEK)
drm_unregister_fps_chg_callback(dfrc_fps_limit_cb);
#endif
fbt_cpu_exit();
mtk_fstb_exit();
fpsgo_composer_exit();
fpsgo_sysfs_exit();
/* game boost engine */
exit_gbe_common();
}
static int __init fpsgo_init(void)
{
int i;
int ret;
FPSGO_LOGI("[FPSGO_CTRL] init\n");
fpsgo_cpu_policy_init();
fpsgo_sysfs_init();
kfpsgo_tsk = kthread_create(kfpsgo, NULL, "kfps");
if (kfpsgo_tsk == NULL)
return -EFAULT;
wake_up_process(kfpsgo_tsk);
for_each_kernel_tracepoint(lookup_tracepoints, NULL);
FOR_EACH_INTEREST(i) {
if (fpsgo_tracepoints[i].tp == NULL) {
FPSGO_LOGE("FPSGO Error, %s not found\n", fpsgo_tracepoints[i].name);
tracepoint_cleanup();
return -1;
}
}
ret = tracepoint_probe_register(fpsgo_tracepoints[0].tp, fpsgo_tracepoints[0].func, NULL);
if (ret) {
FPSGO_LOGE("cpu_frequency: Couldn't activate tracepoint\n");
goto fail_reg_cpu_frequency_entry;
}
fpsgo_tracepoints[0].registered = true;
fail_reg_cpu_frequency_entry:
mutex_init(&notify_lock);
fpsgo_force_onoff = FPSGO_FREE;
gpu_boost_enable_perf = gpu_boost_enable_camera = -1;
init_fpsgo_common();
fbt_cpu_init();
mtk_fstb_init();
fpsgo_composer_init();
/* game boost engine*/
init_gbe_common();
if (fpsgo_arch_nr_clusters() > 0)
fpsgo_switch_enable(1);
fpsgo_notify_vsync_fp = fpsgo_notify_vsync;
fpsgo_notify_qudeq_fp = fpsgo_notify_qudeq;
fpsgo_notify_connect_fp = fpsgo_notify_connect;
fpsgo_notify_bqid_fp = fpsgo_notify_bqid;
fpsgo_notify_swap_buffer_fp = fpsgo_notify_swap_buffer;
fpsgo_notify_sbe_rescue_fp = fpsgo_notify_sbe_rescue;
fpsgo_get_fps_fp = fpsgo_get_fps;
fpsgo_get_cmd_fp = fpsgo_get_cmd;
fpsgo_get_fstb_active_fp = fpsgo_get_fstb_active;
fpsgo_wait_fstb_active_fp = fpsgo_wait_fstb_active;
#if IS_ENABLED(CONFIG_DRM_MEDIATEK)
drm_register_fps_chg_callback(dfrc_fps_limit_cb);
#endif
return 0;
}
module_init(fpsgo_init);
module_exit(fpsgo_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("MediaTek FPSGO");
MODULE_AUTHOR("MediaTek Inc.");