gaming_control, mali: more controls, optimizations

This commit is contained in:
xxmustafacooTR 2023-04-22 03:16:34 +03:00 committed by Mustafa Gökmen
parent 850830b157
commit 71e430b7c9
No known key found for this signature in database
GPG key ID: 3204D8100CFF21ED
9 changed files with 289 additions and 93 deletions

View file

@ -20,6 +20,8 @@
#include <linux/sti/abc_common.h>
#endif
#include <linux/gaming_control.h>
bool sleep_mode = false;
static enum power_supply_property sec_battery_props[] = {
@ -3501,6 +3503,9 @@ static void sec_bat_recov_full_capacity(struct sec_battery_info *battery)
static void sec_bat_check_full_capacity(struct sec_battery_info *battery)
{
int rechg_capacity = battery->batt_full_capacity - 2;
if(battery_idle_gaming() && battery->capacity >= 20)
goto warn;
if (battery->batt_full_capacity >= 100 || battery->batt_full_capacity <= 0 ||
battery->status == POWER_SUPPLY_STATUS_DISCHARGING) {
@ -3518,6 +3523,7 @@ static void sec_bat_check_full_capacity(struct sec_battery_info *battery)
sec_bat_recov_full_capacity(battery);
}
} else if (battery->capacity >= battery->batt_full_capacity) {
warn:
pr_info("%s : stop charging(%d, %d)\n", __func__, battery->capacity, battery->batt_full_capacity);
sec_bat_set_misc_event(battery, BATT_MISC_EVENT_FULL_CAPACITY,

View file

@ -18,6 +18,7 @@
#include <linux/cpufreq.h>
#include <linux/pm_opp.h>
#include <linux/exynos-ucc.h>
#include <linux/gaming_control.h>
#include <linux/sysfs_helpers.h>
#include <linux/ems_service.h>
@ -41,6 +42,9 @@ static bool unlock_freqs_switch = false;
bool exynos_cpufreq_get_unlock_freqs_status()
{
if (gaming_mode)
return true;
return unlock_freqs_switch;
}
@ -633,6 +637,11 @@ static void cpufreq_max_limit_update(int input_freq)
}
}
void exynos_cpufreq_set_gaming_mode(void) {
last_max_limit = -1;
cpufreq_max_limit_update(last_max_limit);
}
static ssize_t store_cpufreq_max_limit(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count)
{

View file

@ -31,10 +31,29 @@
#include <gpexbe_utilization.h>
#include <gpexbe_debug.h>
#include <linux/gaming_control.h>
#include "gpex_clock_internal.h"
#define CPU_MAX INT_MAX
int gpu_min_clock_custom = 0;
int gpu_custom_min_clock(int gpu_min_clock)
{
gpu_min_clock_custom = gpu_min_clock;
return 0;
}
int gpu_max_clock_custom = 0;
int gpu_custom_max_clock(int gpu_max_clock)
{
gpu_max_clock_custom = gpu_max_clock;
gpex_clock_set(gpu_max_clock_custom);
return 0;
}
static struct _clock_info clk_info;
int gpex_clock_get_boot_clock()
@ -43,14 +62,23 @@ int gpex_clock_get_boot_clock()
}
int gpex_clock_get_max_clock()
{
if (gpu_max_clock_custom > 0)
return gpu_max_clock_custom;
return clk_info.gpu_max_clock;
}
int gpex_clock_get_max_clock_limit()
{
if (gpu_max_clock_custom > 0)
return gpu_max_clock_custom;
return clk_info.gpu_max_clock_limit;
}
int gpex_clock_get_min_clock()
{
if (gpu_min_clock_custom > 0)
return gpu_min_clock_custom;
return clk_info.gpu_min_clock;
}
int gpex_clock_get_cur_clock()
@ -59,10 +87,16 @@ int gpex_clock_get_cur_clock()
}
int gpex_clock_get_max_lock()
{
if (gpu_max_clock_custom > 0)
return gpu_max_clock_custom;
return clk_info.max_lock;
}
int gpex_clock_get_min_lock()
{
if (gpu_min_clock_custom > 0)
return gpu_min_clock_custom;
return clk_info.min_lock;
}
int gpex_clock_get_clock(int level)
@ -75,6 +109,9 @@ u64 gpex_clock_get_time_busy(int level)
}
bool gpex_clock_get_unlock_freqs_status()
{
if (gaming_mode)
return false;
return clk_info.unlock_freqs;
}
int gpex_clock_update_config_data_from_dt()

View file

@ -27,6 +27,7 @@
#include <soc/samsung/cal-if.h>
#include <linux/sysfs_helpers.h>
#include <linux/regulator/consumer.h>
#include <linux/gaming_control.h>
#include "gpex_clock_internal.h"
@ -161,6 +162,9 @@ GPEX_STATIC ssize_t set_max_lock_dvfs(const char *buf, size_t count)
GPU_LOG(MALI_EXYNOS_WARNING, "%s: invalid value\n", __func__);
return -ENOENT;
}
if (gaming_mode)
clock = gpex_clock_get_max_clock();
clk_info->user_max_lock_input = clock;
@ -255,6 +259,9 @@ GPEX_STATIC ssize_t set_min_lock_dvfs(const char *buf, size_t count)
GPU_LOG(MALI_EXYNOS_WARNING, "%s: invalid value\n", __func__);
return -ENOENT;
}
if (gaming_mode)
clock = gpex_clock_get_min_clock();
clk_info->user_min_lock_input = clock;
@ -351,6 +358,9 @@ GPEX_STATIC ssize_t set_mm_min_lock_dvfs(const char *buf, size_t count)
GPU_LOG(MALI_EXYNOS_WARNING, "%s: invalid value\n", __func__);
return -ENOENT;
}
if (gaming_mode)
clock = gpex_clock_get_min_clock();
clock = gpex_get_valid_gpu_clock(clock, true);

View file

@ -3,6 +3,7 @@
*
* Copyright (C) 2019
* Diep Quynh Nguyen <remilia.1505@gmail.com>
* Mustafa Gökmen <mustafa.gokmen2004@gmail.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@ -15,53 +16,74 @@
*
*/
#include <linux/binfmts.h>
#include <linux/module.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <linux/device.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/gaming_control.h>
#include <linux/pm_qos.h>
#include <linux/gaming_control.h>
#define GAME_LIST_LENGTH 1024
#define NUM_SUPPORTED_RUNNING_GAMES 20
#define GAMING_CONTROL_VERSION "0.2"
#define TASK_STARTED 1
extern void exynos_cpufreq_set_gaming_mode(void);
/* PM QoS implementation */
struct pm_qos_request gaming_control_min_mif_qos;
struct pm_qos_request gaming_control_min_big_qos;
struct pm_qos_request gaming_control_max_big_qos;
struct pm_qos_request gaming_control_max_little_qos;
static struct pm_qos_request gaming_control_min_int_qos;
static struct pm_qos_request gaming_control_min_mif_qos;
static struct pm_qos_request gaming_control_min_big_qos;
static struct pm_qos_request gaming_control_max_big_qos;
static struct pm_qos_request gaming_control_min_little_qos;
static struct pm_qos_request gaming_control_max_little_qos;
static unsigned int min_int_freq = 534000;
static unsigned int min_mif_freq = 1794000;
static unsigned int max_little_freq = 1456000;
static unsigned int min_big_freq = 1703000;
static unsigned int max_big_freq = 2002000;
static unsigned int min_little_freq = 1456000;
static unsigned int max_little_freq = 2002000;
static unsigned int min_big_freq = 1469000;
static unsigned int max_big_freq = 2886000;
static unsigned int min_gpu_freq = 598000;
static unsigned int max_gpu_freq = 598000;
static int nr_running_games = 0;
static bool always_on = 0;
static bool battery_idle = 0;
bool gaming_mode;
char games_list[GAME_LIST_LENGTH] = {0};
int games_pid[NUM_SUPPORTED_RUNNING_GAMES] = {
pid_t games_pid[NUM_SUPPORTED_RUNNING_GAMES] = {
[0 ... (NUM_SUPPORTED_RUNNING_GAMES - 1)] = -1
};
static int nr_running_games = 0;
static void set_gaming_mode(int mode)
static inline void set_gaming_mode(bool mode, bool force)
{
if (mode == 0) {
pm_qos_update_request(&gaming_control_min_mif_qos, PM_QOS_BUS_THROUGHPUT_DEFAULT_VALUE);
pm_qos_update_request(&gaming_control_max_little_qos, PM_QOS_CLUSTER0_FREQ_MAX_DEFAULT_VALUE);
pm_qos_update_request(&gaming_control_min_big_qos, PM_QOS_CLUSTER1_FREQ_MIN_DEFAULT_VALUE);
pm_qos_update_request(&gaming_control_max_big_qos, PM_QOS_CLUSTER1_FREQ_MAX_DEFAULT_VALUE);
} else if (mode == 1) {
pm_qos_update_request(&gaming_control_min_mif_qos, min_mif_freq);
pm_qos_update_request(&gaming_control_max_little_qos, max_little_freq);
pm_qos_update_request(&gaming_control_min_big_qos, min_big_freq);
pm_qos_update_request(&gaming_control_max_big_qos, max_big_freq);
}
if (always_on)
mode = 1;
if (mode == gaming_mode && !force)
return;
else
gaming_mode = mode;
exynos_cpufreq_set_gaming_mode();
pm_qos_update_request(&gaming_control_min_int_qos, mode && min_int_freq ? min_int_freq : PM_QOS_DEVICE_THROUGHPUT_DEFAULT_VALUE);
pm_qos_update_request(&gaming_control_min_mif_qos, mode && min_mif_freq ? min_mif_freq : PM_QOS_BUS_THROUGHPUT_DEFAULT_VALUE);
pm_qos_update_request(&gaming_control_min_little_qos, mode && min_little_freq ? min_little_freq : PM_QOS_CLUSTER0_FREQ_MIN_DEFAULT_VALUE);
pm_qos_update_request(&gaming_control_max_little_qos, mode && max_little_freq ? max_little_freq : PM_QOS_CLUSTER0_FREQ_MAX_DEFAULT_VALUE);
pm_qos_update_request(&gaming_control_min_big_qos, mode && min_big_freq ? min_big_freq : PM_QOS_CLUSTER1_FREQ_MIN_DEFAULT_VALUE);
pm_qos_update_request(&gaming_control_max_big_qos, mode && max_big_freq ? max_big_freq : PM_QOS_CLUSTER1_FREQ_MAX_DEFAULT_VALUE);
gpu_custom_max_clock(mode ? max_gpu_freq : 0);
gpu_custom_min_clock(mode ? min_gpu_freq : 0);
}
static void store_game_pid(int pid)
bool battery_idle_gaming(void) {
if (gaming_mode && battery_idle)
return 1;
return 0;
}
static inline void store_game_pid(pid_t pid)
{
int i;
@ -69,25 +91,53 @@ static void store_game_pid(int pid)
if (games_pid[i] == -1) {
games_pid[i] = pid;
nr_running_games++;
} }
break;
}
}
}
static void clear_dead_pids(void)
static inline int check_game_pid(pid_t pid)
{
int i;
for (i = 0; i < NUM_SUPPORTED_RUNNING_GAMES; i++) {
if (games_pid[i] != -1) {
if (find_task_by_vpid(games_pid[i]) == NULL) {
if (games_pid[i] == pid)
return 1;
}
}
return 0;
}
static inline void clear_dead_pids(void)
{
int i;
for (i = 0; i < NUM_SUPPORTED_RUNNING_GAMES; i++) {
if (games_pid[i] != -1) {
rcu_read_lock();
if (!find_task_by_vpid(games_pid[i])) {
games_pid[i] = -1;
nr_running_games--;
}
rcu_read_unlock();
}
}
/* If there's no running games, turn off game mode */
if (nr_running_games == 0)
set_gaming_mode(0);
set_gaming_mode(false, false);
}
static inline void removeSubstringAfterChar(char *str, char ch) {
char *ptr = str;
while (*ptr != '\0') {
if (*ptr == ch) {
*(ptr) = '\0';
return;
}
ptr++;
}
}
static int check_for_games(struct task_struct *tsk)
@ -105,8 +155,11 @@ static int check_for_games(struct task_struct *tsk)
return 0;
}
/* clean extra process identifier */
removeSubstringAfterChar(cmdline, ':');
/* Invalid Android process name. Bail out */
if (strlen(cmdline) < 7) {
if (!strcmp(cmdline, "android") || strlen(cmdline) < 7) {
kfree(cmdline);
return 0;
}
@ -124,10 +177,16 @@ static int check_for_games(struct task_struct *tsk)
void game_option(struct task_struct *tsk, enum game_opts opts)
{
pid_t pid;
int ret;
/* Remove all zombie tasks PIDs */
clear_dead_pids();
if(always_on) {
set_gaming_mode(true, false);
return;
}
ret = check_for_games(tsk);
if (!ret)
@ -135,18 +194,19 @@ void game_option(struct task_struct *tsk, enum game_opts opts)
switch (opts) {
case GAME_START:
if (tsk->app_state == TASK_STARTED)
return;
store_game_pid(tsk->pid);
tsk->app_state = TASK_STARTED;
set_gaming_mode(1);
break;
case GAME_RUNNING:
set_gaming_mode(1);
set_gaming_mode(true, false);
pid = task_pid_vnr(tsk);
if (tsk->app_state == TASK_STARTED || check_game_pid(pid))
break;
store_game_pid(pid);
tsk->app_state = TASK_STARTED;
break;
case GAME_PAUSE:
set_gaming_mode(0);
set_gaming_mode(false, false);
break;
default:
break;
@ -172,36 +232,58 @@ static ssize_t game_packages_store(struct kobject *kobj,
return count;
}
/* Show maximum freq */
#define show_freq(type) \
/* Show/Store value */
#define attr_value(type) \
static ssize_t type##_store(struct kobject *kobj, \
struct kobj_attribute *attr, const char *buf, size_t count) \
{ \
unsigned int value; \
\
sscanf(buf, "%u\n", &value); \
type = value; \
\
set_gaming_mode(gaming_mode, gaming_mode); \
\
return count; \
} \
\
static ssize_t type##_show(struct kobject *kobj, \
struct kobj_attribute *attr, char *buf) \
{ \
return sprintf(buf, "%u\n", type); \
} \
\
static struct kobj_attribute type##_attribute = \
__ATTR(type, 0644, type##_show, type##_store);
show_freq(min_mif_freq);
show_freq(max_little_freq);
show_freq(min_big_freq);
show_freq(max_big_freq);
attr_value(always_on);
attr_value(battery_idle);
attr_value(min_int_freq);
attr_value(min_mif_freq);
attr_value(min_little_freq);
attr_value(max_little_freq);
attr_value(min_big_freq);
attr_value(max_big_freq);
attr_value(min_gpu_freq);
attr_value(max_gpu_freq);
/* Store maximum freq */
#define store_freq(type) \
static ssize_t type##_store(struct kobject *kobj, \
struct kobj_attribute *attr, const char *buf, size_t count) \
{ \
unsigned int freq; \
\
sscanf(buf, "%u\n", &freq); \
type = freq; \
\
return count; \
} \
static ssize_t status_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
ssize_t len = 0;
int i;
store_freq(min_mif_freq);
store_freq(max_little_freq);
store_freq(min_big_freq);
store_freq(max_big_freq);
len += sprintf(buf + len, "%d\n\n", nr_running_games);
for (i = 0; i < NUM_SUPPORTED_RUNNING_GAMES; i++) {
if (games_pid[i] != -1)
len += sprintf(buf + len, "%d\n", games_pid[i]);
}
buf[len] = '\0';
return len;
}
static ssize_t version_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
@ -209,31 +291,29 @@ static ssize_t version_show(struct kobject *kobj,
return sprintf(buf, "%s\n", GAMING_CONTROL_VERSION);
}
static struct kobj_attribute game_packages_attribute =
__ATTR(game_packages, 0644, game_packages_show, game_packages_store);
static struct kobj_attribute status_attribute =
__ATTR(status, 0444, status_show, NULL);
static struct kobj_attribute version_attribute =
__ATTR(version, 0444, version_show, NULL);
static struct kobj_attribute min_mif_freq_attribute =
__ATTR(min_mif, 0644, min_mif_freq_show, min_mif_freq_store);
static struct kobj_attribute max_little_freq_attribute =
__ATTR(little_freq_max, 0644, max_little_freq_show, max_little_freq_store);
static struct kobj_attribute min_big_freq_attribute =
__ATTR(big_freq_min, 0644, min_big_freq_show, min_big_freq_store);
static struct kobj_attribute max_big_freq_attribute =
__ATTR(big_freq_max, 0644, max_big_freq_show, max_big_freq_store);
static struct kobj_attribute game_packages_attribute =
__ATTR(game_packages, 0644, game_packages_show, game_packages_store);
static struct attribute *gaming_control_attributes[] = {
&game_packages_attribute.attr,
&status_attribute.attr,
&version_attribute.attr,
&always_on_attribute.attr,
&battery_idle_attribute.attr,
&min_int_freq_attribute.attr,
&min_mif_freq_attribute.attr,
&min_little_freq_attribute.attr,
&max_little_freq_attribute.attr,
&min_big_freq_attribute.attr,
&max_big_freq_attribute.attr,
&min_gpu_freq_attribute.attr,
&max_gpu_freq_attribute.attr,
NULL
};
@ -247,7 +327,9 @@ static int gaming_control_init(void)
{
int sysfs_result;
pm_qos_add_request(&gaming_control_min_int_qos, PM_QOS_DEVICE_THROUGHPUT, PM_QOS_DEVICE_THROUGHPUT_DEFAULT_VALUE);
pm_qos_add_request(&gaming_control_min_mif_qos, PM_QOS_BUS_THROUGHPUT, PM_QOS_BUS_THROUGHPUT_DEFAULT_VALUE);
pm_qos_add_request(&gaming_control_min_little_qos, PM_QOS_CLUSTER0_FREQ_MIN, PM_QOS_CLUSTER0_FREQ_MIN_DEFAULT_VALUE);
pm_qos_add_request(&gaming_control_max_little_qos, PM_QOS_CLUSTER0_FREQ_MAX, PM_QOS_CLUSTER0_FREQ_MAX_DEFAULT_VALUE);
pm_qos_add_request(&gaming_control_min_big_qos, PM_QOS_CLUSTER1_FREQ_MIN, PM_QOS_CLUSTER1_FREQ_MIN_DEFAULT_VALUE);
pm_qos_add_request(&gaming_control_max_big_qos, PM_QOS_CLUSTER1_FREQ_MAX, PM_QOS_CLUSTER1_FREQ_MAX_DEFAULT_VALUE);
@ -272,7 +354,9 @@ static int gaming_control_init(void)
static void gaming_control_exit(void)
{
pm_qos_remove_request(&gaming_control_min_int_qos);
pm_qos_remove_request(&gaming_control_min_mif_qos);
pm_qos_remove_request(&gaming_control_min_little_qos);
pm_qos_remove_request(&gaming_control_max_little_qos);
pm_qos_remove_request(&gaming_control_min_big_qos);
pm_qos_remove_request(&gaming_control_max_big_qos);
@ -282,4 +366,4 @@ static void gaming_control_exit(void)
}
module_init(gaming_control_init);
module_exit(gaming_control_exit);
module_exit(gaming_control_exit);

View file

@ -18,6 +18,7 @@
#include <linux/notifier.h>
#include <linux/spinlock.h>
#include <linux/sysfs.h>
#include <linux/gaming_control.h>
/*********************************************************************
* CPUFREQ INTERFACE *
@ -381,9 +382,11 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver_data);
const char *cpufreq_get_current_driver(void);
void *cpufreq_get_driver_data(void);
static inline void cpufreq_verify_within_limits(struct cpufreq_policy *policy,
unsigned int min, unsigned int max)
static inline void cpufreq_verify_within_cpu_limits(struct cpufreq_policy *policy)
{
unsigned int min = policy->cpuinfo.min_freq;
unsigned int max = policy->cpuinfo.max_freq;
if (policy->min < min)
policy->min = min;
if (policy->max < min)
@ -397,11 +400,23 @@ static inline void cpufreq_verify_within_limits(struct cpufreq_policy *policy,
return;
}
static inline void
cpufreq_verify_within_cpu_limits(struct cpufreq_policy *policy)
static inline void cpufreq_verify_within_limits(struct cpufreq_policy *policy,
unsigned int min, unsigned int max)
{
cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
policy->cpuinfo.max_freq);
if (gaming_mode)
cpufreq_verify_within_cpu_limits(policy);
if (policy->min < min)
policy->min = min;
if (policy->max < min)
policy->max = min;
if (policy->min > max)
policy->min = max;
if (policy->max > max)
policy->max = max;
if (policy->min > policy->max)
policy->min = policy->max;
return;
}
#ifdef CONFIG_CPU_FREQ

View file

@ -3,6 +3,7 @@
*
* Copyright (C) 2019
* Diep Quynh Nguyen <remilia.1505@gmail.com>
* Mustafa Gökmen <mustafa.gokmen2004@gmail.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@ -18,16 +19,45 @@
#ifndef _GAMING_CONTROL_H_
#define _GAMING_CONTROL_H_
#define GAME_LIST_LENGTH 1024
#define NUM_SUPPORTED_RUNNING_GAMES 20
#define GAMING_CONTROL_VERSION "0.4"
#define TASK_STARTED 1
enum game_opts {
GAME_START,
GAME_RUNNING,
GAME_PAUSE
};
enum dvfs_id {
DVFS_MIF = 0,
DVFS_INT,
DVFS_CPUCL0,
DVFS_CPUCL1,
DVFS_G3D,
DVFS_INTCAM,
DVFS_FSYS0,
DVFS_CAM,
DVFS_DISP_EVT1,
DVFS_AUD,
DVFS_IVA,
DVFS_SCORE,
DVFS_CP,
};
int gpu_custom_min_clock(int gpu_min_clock);
int gpu_custom_max_clock(int gpu_max_clock);
#ifdef CONFIG_GAMING_CONTROL
extern bool gaming_mode;
extern void game_option(struct task_struct *tsk, enum game_opts opts);
extern bool battery_idle_gaming(void);
#else
static void game_option(struct task_struct *tsk, enum game_opts opts) {}
static bool gaming_mode = 0;
static void game_option(struct task_struct *tsk, enum game_opts opts) {};
static bool battery_idle_gaming(void) {return false;};
#endif /* CONFIG_GAMING_CONTROL */
#endif /* _GAMING_CONTROL_H_ */
#endif /* _GAMING_CONTROL_H_ */

View file

@ -71,6 +71,15 @@
/* Gaming control */
#include <linux/gaming_control.h>
/* Check if the task is a game */
static void cgroup_game_check(struct task_struct *tsk, const char *name)
{
if (!strcmp(name, "top-app"))
game_option(tsk, GAME_RUNNING);
else if (!strcmp(name, "background"))
game_option(tsk, GAME_PAUSE);
}
/*
* pidlists linger the following amount before being destroyed. The goal
* is avoiding frequent destruction in the middle of consecutive read calls
@ -2925,12 +2934,8 @@ static ssize_t __cgroup_procs_write(struct kernfs_open_file *of, char *buf,
if (!ret)
ret = cgroup_attach_task(cgrp, tsk, threadgroup);
/* Check if the task is a game */
if (!memcmp(cgrp->kn->name, "top-app", sizeof("top-app")) && !ret) {
game_option(tsk, GAME_RUNNING);
} else if (!memcmp(cgrp->kn->name, "background", sizeof("background")) && !ret) {
game_option(tsk, GAME_PAUSE);
}
if (!ret)
cgroup_game_check(tsk, of->kn->parent->name);
put_task_struct(tsk);
goto out_unlock_threadgroup;

View file

@ -2175,7 +2175,7 @@ long _do_fork(unsigned long clone_flags,
struct task_struct *p;
int trace = 0;
long nr;
game_option(current, GAME_START);
/*