886 lines
19 KiB
C
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(¬ify_lock);
|
|
enable = fpsgo_enable;
|
|
mutex_unlock(¬ify_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(¬ify_lock);
|
|
if (enable == fpsgo_enable) {
|
|
mutex_unlock(¬ify_lock);
|
|
return;
|
|
}
|
|
|
|
if (fpsgo_force_onoff != FPSGO_FREE &&
|
|
enable != fpsgo_force_onoff) {
|
|
mutex_unlock(¬ify_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(¬ify_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(¬ifier_wq_lock);
|
|
list_add_tail(&vpPush->queue_list, &head);
|
|
condition_notifier_wq = 1;
|
|
mutex_unlock(¬ifier_wq_lock);
|
|
|
|
wake_up_interruptible(¬ifier_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(¬ifier_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(¬ifier_wq_lock);
|
|
} else {
|
|
condition_notifier_wq = 0;
|
|
mutex_unlock(¬ifier_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(¬ify_lock);
|
|
value = perfserv_ta;
|
|
mutex_unlock(¬ify_lock);
|
|
|
|
return value;
|
|
}
|
|
|
|
void fpsgo_set_perfserv_ta(int value)
|
|
{
|
|
mutex_lock(¬ify_lock);
|
|
perfserv_ta = value;
|
|
mutex_unlock(¬ify_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(¬ify_lock);
|
|
temp_onoff = fpsgo_force_onoff;
|
|
mutex_unlock(¬ify_lock);
|
|
|
|
return temp_onoff;
|
|
}
|
|
|
|
void fpsgo_force_switch_enable(int enable)
|
|
{
|
|
mutex_lock(¬ify_lock);
|
|
fpsgo_force_onoff = enable;
|
|
mutex_unlock(¬ify_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(¬ify_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.");
|