mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 10:58:48 +09:00
soc: rockchip: add different performance level support
CONFIG_ROCKCHIP_PERFORMANCE_LEVEL=0 for low performance, low power consumption CONFIG_ROCKCHIP_PERFORMANCE_LEVEL=1 for normal performance CONFIG_ROCKCHIP_PERFORMANCE_LEVEL=2 for high performance, high power consumption Change-Id: I7a88f1a2e43513f647a860b427d8344e34165fa6 Signed-off-by: Liang Chen <cl@rock-chips.com>
This commit is contained in:
@@ -68,6 +68,27 @@ config ROCKCHIP_OPP
|
||||
help
|
||||
Say y here to enable rockchip OPP support.
|
||||
|
||||
config ROCKCHIP_PERFORMANCE
|
||||
bool "Rockchip performance configuration support"
|
||||
depends on NO_GKI
|
||||
help
|
||||
This config aims to support different requests between power consumption
|
||||
and performance.
|
||||
|
||||
config ROCKCHIP_PERFORMANCE_LEVEL
|
||||
int "Rockchip performance default level"
|
||||
depends on ROCKCHIP_PERFORMANCE
|
||||
range 0 2
|
||||
default 1
|
||||
help
|
||||
Select default performance level:
|
||||
|
||||
0 for low-performance (powersave),
|
||||
1 for normal performance,
|
||||
2 for high-performance.
|
||||
|
||||
This can also be changed at runtime (via the level module parameter).
|
||||
|
||||
config ROCKCHIP_PM_DOMAINS
|
||||
tristate "Rockchip generic power domain"
|
||||
depends on PM
|
||||
|
||||
@@ -14,6 +14,7 @@ obj-$(CONFIG_ROCKCHIP_FLASH_VENDOR_STORAGE) += flash_vendor_storage.o
|
||||
obj-$(CONFIG_ROCKCHIP_MTD_VENDOR_STORAGE) += mtd_vendor_storage.o
|
||||
obj-$(CONFIG_ROCKCHIP_IPA) += rockchip_ipa.o
|
||||
obj-$(CONFIG_ROCKCHIP_OPP) += rockchip_opp_select.o
|
||||
obj-$(CONFIG_ROCKCHIP_PERFORMANCE) += rockchip_performance.o
|
||||
obj-$(CONFIG_ROCKCHIP_PVTM) += rockchip_pvtm.o
|
||||
obj-$(CONFIG_ROCKCHIP_RAMDISK) += rockchip_ramdisk.o
|
||||
obj-$(CONFIG_ROCKCHIP_SUSPEND_MODE) += rockchip_pm_config.o
|
||||
|
||||
162
drivers/soc/rockchip/rockchip_performance.c
Normal file
162
drivers/soc/rockchip/rockchip_performance.c
Normal file
@@ -0,0 +1,162 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2022 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <soc/rockchip/rockchip_performance.h>
|
||||
#include <../../kernel/sched/sched.h>
|
||||
|
||||
static int perf_level = CONFIG_ROCKCHIP_PERFORMANCE_LEVEL;
|
||||
static cpumask_var_t cpul_mask, cpub_mask;
|
||||
static bool perf_init_done;
|
||||
static DEFINE_MUTEX(update_mutex);
|
||||
|
||||
#ifdef CONFIG_UCLAMP_TASK
|
||||
static inline void set_uclamp_util_min_rt(unsigned int util)
|
||||
{
|
||||
sysctl_sched_uclamp_util_min_rt_default = util;
|
||||
static_branch_enable(&sched_uclamp_used);
|
||||
rockchip_perf_uclamp_sync_util_min_rt_default();
|
||||
}
|
||||
#else
|
||||
static inline void set_uclamp_util_min_rt(unsigned int util) { };
|
||||
#endif
|
||||
|
||||
static void update_perf_level_locked(int level)
|
||||
{
|
||||
struct em_perf_domain *em;
|
||||
unsigned long target_cost, target_freq, max_freq;
|
||||
unsigned long scale_cpu0 = arch_scale_cpu_capacity(0);
|
||||
unsigned int uclamp_util_min_rt = scale_cpu0 * 2 / 3;
|
||||
int i;
|
||||
|
||||
if (perf_init_done && perf_level == level)
|
||||
return;
|
||||
|
||||
perf_level = level;
|
||||
|
||||
if (level == 0) {
|
||||
set_uclamp_util_min_rt(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((level == 1) || (level == 2)) {
|
||||
set_uclamp_util_min_rt(SCHED_CAPACITY_SCALE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* find a better efficient frequency and consider performance */
|
||||
em = em_cpu_get(0);
|
||||
if (em) {
|
||||
target_cost = em->table[0].cost + (em->table[0].cost >> 2);
|
||||
|
||||
for (i = 1; i < em->nr_perf_states; i++) {
|
||||
if (em->table[i].cost >= target_cost)
|
||||
break;
|
||||
}
|
||||
target_freq = em->table[i-1].frequency;
|
||||
max_freq = em->table[em->nr_perf_states-1].frequency;
|
||||
uclamp_util_min_rt = scale_cpu0 * target_freq / max_freq;
|
||||
}
|
||||
|
||||
/* schedutil will reserve 20% util, and we need more 5% for debounce */
|
||||
uclamp_util_min_rt = uclamp_util_min_rt * 3 / 4;
|
||||
set_uclamp_util_min_rt(uclamp_util_min_rt);
|
||||
}
|
||||
|
||||
static void update_perf_level(int level)
|
||||
{
|
||||
mutex_lock(&update_mutex);
|
||||
update_perf_level_locked(level);
|
||||
mutex_unlock(&update_mutex);
|
||||
}
|
||||
|
||||
static int param_set_level(const char *buf, const struct kernel_param *kp)
|
||||
{
|
||||
int ret, level;
|
||||
|
||||
ret = kstrtoint(buf, 10, &level);
|
||||
if (ret || (level < 0) || (level > 2))
|
||||
return -EINVAL;
|
||||
|
||||
if (!perf_init_done)
|
||||
return 0;
|
||||
|
||||
update_perf_level(level);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct kernel_param_ops level_param_ops = {
|
||||
.set = param_set_level,
|
||||
.get = param_get_int,
|
||||
};
|
||||
module_param_cb(level, &level_param_ops, &perf_level, 0644);
|
||||
|
||||
static __init int rockchip_perf_init(void)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
if (!zalloc_cpumask_var(&cpul_mask, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
if (!zalloc_cpumask_var(&cpub_mask, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
if (arch_scale_cpu_capacity(cpu) == SCHED_CAPACITY_SCALE)
|
||||
cpumask_set_cpu(cpu, cpub_mask);
|
||||
else
|
||||
cpumask_set_cpu(cpu, cpul_mask);
|
||||
}
|
||||
|
||||
update_perf_level(perf_level);
|
||||
|
||||
perf_init_done = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
late_initcall_sync(rockchip_perf_init);
|
||||
|
||||
int rockchip_perf_get_level(void)
|
||||
{
|
||||
return perf_level;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
int rockchip_perf_select_rt_cpu(int prev_cpu, struct cpumask *lowest_mask)
|
||||
{
|
||||
int cpu = nr_cpu_ids;
|
||||
|
||||
if (!perf_init_done)
|
||||
return prev_cpu;
|
||||
|
||||
if (static_branch_unlikely(&sched_asym_cpucapacity)) {
|
||||
if (perf_level == 0)
|
||||
cpu = cpumask_first_and(lowest_mask, cpul_mask);
|
||||
if (perf_level == 2)
|
||||
cpu = cpumask_first_and(lowest_mask, cpub_mask);
|
||||
|
||||
if (cpu < nr_cpu_ids)
|
||||
return cpu;
|
||||
}
|
||||
|
||||
return prev_cpu;
|
||||
}
|
||||
|
||||
bool rockchip_perf_misfit_rt(int cpu)
|
||||
{
|
||||
if (!perf_init_done)
|
||||
return false;
|
||||
|
||||
if (static_branch_unlikely(&sched_asym_cpucapacity)) {
|
||||
if ((perf_level == 0) && cpumask_test_cpu(cpu, cpub_mask))
|
||||
return true;
|
||||
if ((perf_level == 2) && cpumask_test_cpu(cpu, cpul_mask))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_SMP */
|
||||
23
include/soc/rockchip/rockchip_performance.h
Normal file
23
include/soc/rockchip/rockchip_performance.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2022 Rockchip Electronics Co., Ltd
|
||||
*/
|
||||
#ifndef __SOC_ROCKCHIP_PERFORMANCE_H
|
||||
#define __SOC_ROCKCHIP_PERFORMANCE_H
|
||||
|
||||
#ifdef CONFIG_ROCKCHIP_PERFORMANCE
|
||||
extern int rockchip_perf_get_level(void);
|
||||
extern int rockchip_perf_select_rt_cpu(int prev_cpu, struct cpumask *lowest_mask);
|
||||
extern bool rockchip_perf_misfit_rt(int cpu);
|
||||
extern void rockchip_perf_uclamp_sync_util_min_rt_default(void);
|
||||
#else
|
||||
static inline int rockchip_perf_get_level(void) { return 1; }
|
||||
static inline int rockchip_perf_select_rt_cpu(int prev_cpu, struct cpumask *lowest_mask)
|
||||
{
|
||||
return prev_cpu;
|
||||
}
|
||||
static inline bool rockchip_perf_misfit_rt(int cpu) { return false; }
|
||||
static inline void rockchip_perf_uclamp_sync_util_min_rt_default(void) {}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1098,6 +1098,14 @@ static void uclamp_sync_util_min_rt_default(void)
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_ROCKCHIP_PERFORMANCE)
|
||||
void rockchip_perf_uclamp_sync_util_min_rt_default(void)
|
||||
{
|
||||
uclamp_sync_util_min_rt_default();
|
||||
}
|
||||
EXPORT_SYMBOL(rockchip_perf_uclamp_sync_util_min_rt_default);
|
||||
#endif
|
||||
|
||||
static inline struct uclamp_se
|
||||
uclamp_tg_restrict(struct task_struct *p, enum uclamp_id clamp_id)
|
||||
{
|
||||
|
||||
@@ -6745,6 +6745,10 @@ static int find_energy_efficient_cpu(struct task_struct *p, int prev_cpu, int sy
|
||||
prev_delta = compute_energy(p, prev_cpu, pd);
|
||||
prev_delta -= base_energy_pd;
|
||||
best_delta = min(best_delta, prev_delta);
|
||||
if (IS_ENABLED(CONFIG_ROCKCHIP_PERFORMANCE)) {
|
||||
if (prev_delta == best_delta)
|
||||
best_energy_cpu = prev_cpu;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -6804,6 +6808,11 @@ unlock:
|
||||
if (prev_delta == ULONG_MAX)
|
||||
return best_energy_cpu;
|
||||
|
||||
if (IS_ENABLED(CONFIG_ROCKCHIP_PERFORMANCE)) {
|
||||
if (rockchip_perf_get_level() == 0)
|
||||
return best_energy_cpu;
|
||||
}
|
||||
|
||||
if ((prev_delta - best_delta) > ((prev_delta + base_energy) >> 4))
|
||||
return best_energy_cpu;
|
||||
|
||||
|
||||
@@ -1546,6 +1546,8 @@ select_task_rq_rt(struct task_struct *p, int cpu, int sd_flag, int flags)
|
||||
(unlikely(rt_task(curr)) &&
|
||||
(curr->nr_cpus_allowed < 2 || curr->prio <= p->prio))));
|
||||
|
||||
if (IS_ENABLED(CONFIG_ROCKCHIP_PERFORMANCE))
|
||||
test |= rockchip_perf_misfit_rt(cpu);
|
||||
/*
|
||||
* Respect the sync flag as long as the task can run on this CPU.
|
||||
*/
|
||||
@@ -1815,6 +1817,8 @@ static int find_lowest_rq(struct task_struct *task)
|
||||
|
||||
cpu = task_cpu(task);
|
||||
|
||||
if (IS_ENABLED(CONFIG_ROCKCHIP_PERFORMANCE))
|
||||
cpu = rockchip_perf_select_rt_cpu(cpu, lowest_mask);
|
||||
/*
|
||||
* At this point we have built a mask of CPUs representing the
|
||||
* lowest priority tasks in the system. Now we want to elect
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
|
||||
#include <asm/tlb.h>
|
||||
#include <asm-generic/vmlinux.lds.h>
|
||||
#include <soc/rockchip/rockchip_performance.h>
|
||||
|
||||
#ifdef CONFIG_PARAVIRT
|
||||
# include <asm/paravirt.h>
|
||||
|
||||
Reference in New Issue
Block a user