kernel-brax3-ubuntu-touch/drivers/misc/mediatek/performance/perf_ioctl/perf_ioctl.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

593 lines
14 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include "perf_ioctl.h"
#define TAG "PERF_IOCTL"
void (*fpsgo_notify_qudeq_fp)(int qudeq,
unsigned int startend,
int pid, unsigned long long identifier);
EXPORT_SYMBOL_GPL(fpsgo_notify_qudeq_fp);
void (*fpsgo_notify_connect_fp)(int pid,
int connectedAPI, unsigned long long identifier);
EXPORT_SYMBOL_GPL(fpsgo_notify_connect_fp);
void (*fpsgo_notify_bqid_fp)(int pid, unsigned long long bufID,
int queue_SF, unsigned long long identifier, int create);
EXPORT_SYMBOL_GPL(fpsgo_notify_bqid_fp);
void (*fpsgo_notify_vsync_fp)(void);
EXPORT_SYMBOL_GPL(fpsgo_notify_vsync_fp);
void (*fpsgo_get_fps_fp)(int *pid, int *fps);
EXPORT_SYMBOL_GPL(fpsgo_get_fps_fp);
void (*fpsgo_get_cmd_fp)(int *cmd, int *value1, int *value2);
EXPORT_SYMBOL_GPL(fpsgo_get_cmd_fp);
void (*gbe_get_cmd_fp)(int *cmd, int *value1, int *value2);
EXPORT_SYMBOL_GPL(gbe_get_cmd_fp);
int (*fpsgo_get_fstb_active_fp)(long long time_diff);
EXPORT_SYMBOL_GPL(fpsgo_get_fstb_active_fp);
int (*fpsgo_wait_fstb_active_fp)(void);
EXPORT_SYMBOL_GPL(fpsgo_wait_fstb_active_fp);
void (*fpsgo_notify_swap_buffer_fp)(int pid);
EXPORT_SYMBOL_GPL(fpsgo_notify_swap_buffer_fp);
void (*fpsgo_notify_sbe_rescue_fp)(int pid, int start, int enhance, unsigned long long frameID);
EXPORT_SYMBOL_GPL(fpsgo_notify_sbe_rescue_fp);
struct proc_dir_entry *perfmgr_root;
EXPORT_SYMBOL(perfmgr_root);
static unsigned long perfctl_copy_from_user(void *pvTo,
const void __user *pvFrom, unsigned long ulBytes)
{
if (access_ok(pvFrom, ulBytes))
return __copy_from_user(pvTo, pvFrom, ulBytes);
return ulBytes;
}
static unsigned long perfctl_copy_to_user(void __user *pvTo,
const void *pvFrom, unsigned long ulBytes)
{
if (access_ok(pvTo, ulBytes))
return __copy_to_user(pvTo, pvFrom, ulBytes);
return ulBytes;
}
/*--------------------SYNC------------------------*/
/* XGFF BOOST*/
int (*xgff_boost_startend_fp)(unsigned int startend,
int group_id,
int *dep_list,
int dep_list_num,
int prefer_cluster,
unsigned long long target_time,
int *param);
EXPORT_SYMBOL(xgff_boost_startend_fp);
static int xgff_boost_show(struct seq_file *m, void *v)
{
return 0;
}
static int xgff_boost_open(struct inode *inode, struct file *file)
{
return single_open(file, xgff_boost_show, inode->i_private);
}
static long xgff_boost_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg)
{
ssize_t ret = 0;
int *dep_list;
int dep_list_num;
int *param;
struct _XGFFRAME_BOOST_PACKAGE *msgKM = NULL,
*msgUM = (struct _XGFFRAME_BOOST_PACKAGE *)arg;
struct _XGFFRAME_BOOST_PACKAGE smsgKM;
msgKM = &smsgKM;
if (perfctl_copy_from_user(msgKM, msgUM,
sizeof(struct _XGFFRAME_BOOST_PACKAGE))) {
ret = -EFAULT;
goto ret_ioctl;
}
switch (cmd) {
case XGFFRAME_BOOST_START:
if (!xgff_boost_startend_fp) {
ret = -EAGAIN;
goto ret_ioctl;
}
if (msgKM->dep_list_num <= 0 || !msgKM->dep_list) {
ret = -EINVAL;
goto ret_ioctl;
}
dep_list_num = msgKM->dep_list_num;
dep_list = kcalloc(dep_list_num, sizeof(int), GFP_KERNEL);
if (!dep_list) {
ret = -ENOMEM;
goto ret_ioctl;
}
param = kzalloc(12 * sizeof(int), GFP_KERNEL);
if (!param) {
kfree(dep_list);
ret = -ENOMEM;
goto ret_ioctl;
}
if (perfctl_copy_from_user(dep_list, msgKM->dep_list,
dep_list_num * sizeof(__u32))) {
kfree(param);
kfree(dep_list);
ret = -EFAULT;
goto ret_ioctl;
}
param[0] = msgKM->param.rescue_pct_1;
param[1] = msgKM->param.rescue_f_1;
param[2] = msgKM->param.rescue_pct_2;
param[3] = msgKM->param.rescue_f_2;
param[4] = msgKM->param.gcc_std_filter;
param[5] = msgKM->param.gcc_history_window;
param[6] = msgKM->param.gcc_up_check;
param[7] = msgKM->param.gcc_up_thrs;
param[8] = msgKM->param.gcc_up_step;
param[9] = msgKM->param.gcc_down_check;
param[10] = msgKM->param.gcc_down_thrs;
param[11] = msgKM->param.gcc_down_step;
ret = xgff_boost_startend_fp(1, msgKM->group_id,
dep_list, dep_list_num, msgKM->prefer_cluster, msgKM->target_time, param);
kfree(dep_list);
kfree(param);
break;
case XGFFRAME_BOOST_END:
if (!xgff_boost_startend_fp) {
ret = -EAGAIN;
goto ret_ioctl;
}
ret = xgff_boost_startend_fp(0, msgKM->group_id, NULL, 0, msgKM->prefer_cluster,
msgKM->target_time, NULL);
break;
default:
pr_debug(TAG "%s %d: unknown cmd %x\n",
__FILE__, __LINE__, cmd);
ret = -1;
goto ret_ioctl;
}
ret_ioctl:
return ret;
}
static long xgff_boost_compat_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg)
{
return 0;
}
static const struct proc_ops xgff_boost_Fops = {
.proc_ioctl = xgff_boost_ioctl,
.proc_compat_ioctl = xgff_boost_compat_ioctl,
.proc_open = xgff_boost_open,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
.proc_release = single_release,
};
/*--------------------XGFFRAME------------------------*/
int (*xgff_frame_startend_fp)(unsigned int startend,
unsigned int tid,
unsigned long long queueid,
unsigned long long frameid,
unsigned long long *cputime,
unsigned int *area,
unsigned int *pdeplistsize,
unsigned int *pdeplist);
EXPORT_SYMBOL(xgff_frame_startend_fp);
void (*xgff_frame_getdeplist_maxsize_fp)(
unsigned int *pdeplistsize);
EXPORT_SYMBOL(xgff_frame_getdeplist_maxsize_fp);
void (*xgff_frame_min_cap_fp)(unsigned int min_cap);
EXPORT_SYMBOL(xgff_frame_min_cap_fp);
static int xgff_show(struct seq_file *m, void *v)
{
return 0;
}
static int xgff_open(struct inode *inode, struct file *file)
{
return single_open(file, xgff_show, inode->i_private);
}
static long xgff_ioctl_impl(struct file *filp,
unsigned int cmd, unsigned long arg, void *pKM)
{
ssize_t ret = 0;
struct _XGFFRAME_PACKAGE *msgKM = NULL,
*msgUM = (struct _XGFFRAME_PACKAGE *)arg;
struct _XGFFRAME_PACKAGE smsgKM;
__u32 *vpdeplist = NULL;
unsigned int maxsize_deplist = 0;
msgKM = (struct _XGFFRAME_PACKAGE *)pKM;
if (!msgKM) {
msgKM = &smsgKM;
if (perfctl_copy_from_user(msgKM, msgUM,
sizeof(struct _XGFFRAME_PACKAGE))) {
ret = -EFAULT;
goto ret_ioctl;
}
}
switch (cmd) {
case XGFFRAME_START:
if (!xgff_frame_startend_fp || !xgff_frame_getdeplist_maxsize_fp) {
ret = -EAGAIN;
goto ret_ioctl;
}
xgff_frame_getdeplist_maxsize_fp(&maxsize_deplist);
vpdeplist = kcalloc(msgKM->deplist_size, sizeof(__u32), GFP_KERNEL);
if (!vpdeplist) {
ret = -ENOMEM;
goto ret_ioctl;
}
if (perfctl_copy_from_user(vpdeplist,
msgKM->deplist, msgKM->deplist_size * sizeof(__s32))) {
kfree(vpdeplist);
ret = -EFAULT;
goto ret_ioctl;
}
if (msgKM->deplist_size > maxsize_deplist)
msgKM->deplist_size = maxsize_deplist;
ret = xgff_frame_startend_fp(1, msgKM->tid, msgKM->queueid,
msgKM->frameid, NULL, NULL, &msgKM->deplist_size, vpdeplist);
perfctl_copy_to_user(msgUM, msgKM, sizeof(struct _XGFFRAME_PACKAGE));
kfree(vpdeplist);
break;
case XGFFRAME_END:
if (!xgff_frame_startend_fp || !xgff_frame_getdeplist_maxsize_fp) {
ret = -EAGAIN;
goto ret_ioctl;
}
xgff_frame_getdeplist_maxsize_fp(&maxsize_deplist);
vpdeplist = kcalloc(msgKM->deplist_size, sizeof(__u32), GFP_KERNEL);
if (!vpdeplist) {
ret = -ENOMEM;
goto ret_ioctl;
}
if (perfctl_copy_from_user(vpdeplist,
msgKM->deplist, msgKM->deplist_size * sizeof(__s32))) {
kfree(vpdeplist);
ret = -EFAULT;
goto ret_ioctl;
}
if (msgKM->deplist_size > maxsize_deplist)
msgKM->deplist_size = maxsize_deplist;
ret = xgff_frame_startend_fp(0, msgKM->tid, msgKM->queueid,
msgKM->frameid, &msgKM->cputime, &msgKM->area,
&msgKM->deplist_size, vpdeplist);
perfctl_copy_to_user(msgUM, msgKM, sizeof(struct _XGFFRAME_PACKAGE));
kfree(vpdeplist);
break;
case XGFFRAME_MIN_CAP:
if (!xgff_frame_min_cap_fp) {
ret = -EAGAIN;
goto ret_ioctl;
}
xgff_frame_min_cap_fp((unsigned int)msgKM->min_cap);
break;
default:
pr_debug(TAG "%s %d: unknown cmd %x\n",
__FILE__, __LINE__, cmd);
ret = -1;
goto ret_ioctl;
}
ret_ioctl:
return ret;
}
static long xgff_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg)
{
return xgff_ioctl_impl(filp, cmd, arg, NULL);
}
static long xgff_compat_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg)
{
int ret = -EFAULT;
struct _XGFFRAME_PACKAGE_32 {
__u32 tid;
__u64 queueid;
__u64 frameid;
__u64 cputime;
__u32 area;
__u32 deplist_size;
union {
__u32 *deplist;
__u64 p_dummy_deplist;
};
};
struct _XGFFRAME_PACKAGE sEaraPackageKM64;
struct _XGFFRAME_PACKAGE_32 sEaraPackageKM32;
struct _XGFFRAME_PACKAGE_32 *psEaraPackageKM32 = &sEaraPackageKM32;
struct _XGFFRAME_PACKAGE_32 *psEaraPackageUM32 =
(struct _XGFFRAME_PACKAGE_32 *)arg;
if (perfctl_copy_from_user(psEaraPackageKM32,
psEaraPackageUM32, sizeof(struct _XGFFRAME_PACKAGE_32)))
goto unlock_and_return;
sEaraPackageKM64 = *((struct _XGFFRAME_PACKAGE *)psEaraPackageKM32);
sEaraPackageKM64.deplist =
(void *)((size_t) psEaraPackageKM32->deplist);
ret = xgff_ioctl_impl(filp, cmd, arg, &sEaraPackageKM64);
unlock_and_return:
return ret;
}
static const struct proc_ops xgff_Fops = {
.proc_ioctl = xgff_ioctl,
.proc_compat_ioctl = xgff_compat_ioctl,
.proc_open = xgff_open,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
.proc_release = single_release,
};
/*--------------------INIT------------------------*/
static int device_show(struct seq_file *m, void *v)
{
return 0;
}
static int device_open(struct inode *inode, struct file *file)
{
return single_open(file, device_show, inode->i_private);
}
static long device_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg)
{
ssize_t ret = 0;
int pwr_cmd = -1, value1 = -1, value2 = -1, pwr_pid = -1, pwr_fps = -1;
struct _FPSGO_PACKAGE *msgKM = NULL,
*msgUM = (struct _FPSGO_PACKAGE *)arg;
struct _FPSGO_PACKAGE smsgKM;
msgKM = &smsgKM;
if (perfctl_copy_from_user(msgKM, msgUM,
sizeof(struct _FPSGO_PACKAGE))) {
ret = -EFAULT;
goto ret_ioctl;
}
switch (cmd) {
#if defined(CONFIG_MTK_FPSGO_V3)
case FPSGO_QUEUE:
if (fpsgo_notify_qudeq_fp)
fpsgo_notify_qudeq_fp(1,
msgKM->start, msgKM->tid,
msgKM->identifier);
break;
case FPSGO_DEQUEUE:
if (fpsgo_notify_qudeq_fp)
fpsgo_notify_qudeq_fp(0,
msgKM->start, msgKM->tid,
msgKM->identifier);
break;
case FPSGO_QUEUE_CONNECT:
if (fpsgo_notify_connect_fp)
fpsgo_notify_connect_fp(msgKM->tid,
msgKM->connectedAPI, msgKM->identifier);
break;
case FPSGO_BQID:
if (fpsgo_notify_bqid_fp)
fpsgo_notify_bqid_fp(msgKM->tid, msgKM->bufID,
msgKM->queue_SF, msgKM->identifier,
msgKM->start);
break;
case FPSGO_TOUCH:
break;
case FPSGO_VSYNC:
if (fpsgo_notify_vsync_fp)
fpsgo_notify_vsync_fp();
break;
case FPSGO_SWAP_BUFFER:
if (fpsgo_notify_swap_buffer_fp)
fpsgo_notify_swap_buffer_fp(msgKM->tid);
break;
case FPSGO_GET_FPS:
if (fpsgo_get_fps_fp) {
fpsgo_get_fps_fp(&pwr_pid, &pwr_fps);
msgKM->tid = pwr_pid;
msgKM->value1 = pwr_fps;
} else
ret = -1;
perfctl_copy_to_user(msgUM, msgKM,
sizeof(struct _FPSGO_PACKAGE));
break;
case FPSGO_GET_CMD:
if (fpsgo_get_cmd_fp) {
fpsgo_get_cmd_fp(&pwr_cmd, &value1, &value2);
msgKM->cmd = pwr_cmd;
msgKM->value1 = value1;
msgKM->value2 = value2;
} else
ret = -1;
perfctl_copy_to_user(msgUM, msgKM,
sizeof(struct _FPSGO_PACKAGE));
break;
case FPSGO_GBE_GET_CMD:
if (gbe_get_cmd_fp) {
gbe_get_cmd_fp(&pwr_cmd, &value1, &value2);
msgKM->cmd = pwr_cmd;
msgKM->value1 = value1;
msgKM->value2 = value2;
} else
ret = -1;
perfctl_copy_to_user(msgUM, msgKM,
sizeof(struct _FPSGO_PACKAGE));
break;
case FPSGO_GET_FSTB_ACTIVE:
if (fpsgo_get_fstb_active_fp)
msgKM->active = fpsgo_get_fstb_active_fp(msgKM->time_diff);
else
ret = 0;
perfctl_copy_to_user(msgUM, msgKM,
sizeof(struct _FPSGO_PACKAGE));
break;
case FPSGO_WAIT_FSTB_ACTIVE:
if (fpsgo_wait_fstb_active_fp)
fpsgo_wait_fstb_active_fp();
break;
case FPSGO_SBE_RESCUE:
if (fpsgo_notify_sbe_rescue_fp)
fpsgo_notify_sbe_rescue_fp(msgKM->tid, msgKM->start, msgKM->value2,
msgKM->frame_id);
break;
#else
case FPSGO_TOUCH:
[[fallthrough]];
case FPSGO_QUEUE:
[[fallthrough]];
case FPSGO_DEQUEUE:
[[fallthrough]];
case FPSGO_QUEUE_CONNECT:
[[fallthrough]];
case FPSGO_VSYNC:
[[fallthrough]];
case FPSGO_BQID:
[[fallthrough]];
case FPSGO_SWAP_BUFFER:
[[fallthrough]];
case FPSGO_GET_FPS:
[[fallthrough]];
case FPSGO_GET_CMD:
[[fallthrough]];
case FPSGO_GBE_GET_CMD:
[[fallthrough]];
case FPSGO_GET_FSTB_ACTIVE:
[[fallthrough]];
case FPSGO_WAIT_FSTB_ACTIVE:
[[fallthrough]];
case FPSGO_SBE_RESCUE:
break;
#endif
default:
pr_debug(TAG "%s %d: unknown cmd %x\n",
__FILE__, __LINE__, cmd);
ret = -1;
goto ret_ioctl;
}
ret_ioctl:
return ret;
}
static const struct proc_ops Fops = {
.proc_compat_ioctl = device_ioctl,
.proc_ioctl = device_ioctl,
.proc_open = device_open,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
.proc_release = single_release,
};
/*--------------------INIT------------------------*/
static void __exit exit_perfctl(void) {}
//static int __init init_perfctl(struct proc_dir_entry *parent)
static int __init init_perfctl(void)
{
struct proc_dir_entry *pe, *parent;
int ret_val = 0;
pr_debug(TAG"Start to init perf_ioctl driver\n");
parent = proc_mkdir("perfmgr", NULL);
perfmgr_root = parent;
pe = proc_create("perf_ioctl", 0664, parent, &Fops);
if (!pe) {
pr_debug(TAG"%s failed with %d\n",
"Creating file node ",
ret_val);
ret_val = -ENOMEM;
goto out_wq;
}
pe = proc_create("xgff_ioctl", 0664, parent, &xgff_Fops);
if (!pe) {
pr_debug(TAG"%s failed with %d\n",
"Creating file node ",
ret_val);
ret_val = -ENOMEM;
goto out_wq;
}
pe = proc_create("xgff_boost_ioctl", 0664, parent, &xgff_boost_Fops);
if (!pe) {
pr_debug(TAG"%s failed with %d\n",
"Creating file node ",
ret_val);
ret_val = -ENOMEM;
goto out_wq;
}
pr_debug(TAG"init perf_ioctl driver done\n");
return 0;
out_wq:
return ret_val;
}
module_init(init_perfctl);
module_exit(exit_perfctl);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("MediaTek FPSGO perf_ioctl");
MODULE_AUTHOR("MediaTek Inc.");