Files
threeeye bc1d038eac REVVL 6 Pro kernel bring-up: full working tree snapshot (2026-09-12)
Squashed backup commit (no shallow-clone history issues) of
xiaomi-mt6833-dev/kernel_xiaomi_mt6833 (lineage-23.2 branch, upstream
commit 9eece662e) plus all fixes applied to get everpal_defconfig building
clean against a modern (GCC 15.2.0) toolchain -- see the previous commit
message on the lineage-23.2 branch (also in this repo history is not
available here since this is a squashed snapshot; full incremental history
lives in the local DL380 checkout and the upstream GitHub remote).

Upstream: https://github.com/xiaomi-mt6833-dev/kernel_xiaomi_mt6833 (lineage-23.2)
2026-09-12 13:36:46 +00:00

1018 lines
22 KiB
C

/*
* Copyright (C) 2017 MediaTek Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See http://www.gnu.org/licenses/gpl-2.0.html for more details.
*/
#include <linux/cpu.h>
#include <linux/sysfs.h>
#include <linux/kthread.h>
#include <linux/kobject.h>
#include <linux/irq_work.h>
#include <linux/sched/task.h>
#include <uapi/linux/sched/types.h>
#include <trace/events/sched.h>
#include "rq_stats.h"
#include "sched_ctl.h"
//TODO: remove comment after met ready
//#include <mt-plat/met_drv.h>
#include <mt-plat/mtk_sched.h>
#ifdef CONFIG_MTK_TASK_TURBO
#include <mt-plat/turbo_common.h>
#endif
#ifdef CONFIG_MACH_MT6873
#include "mtk_devinfo.h"
#endif
#define SCHED_HINT_THROTTLE_NSEC 10000000 /* 10ms for throttle */
struct sched_hint_data {
struct task_struct *task;
struct irq_work irq_work;
int sys_cap;
int sys_util;
ktime_t throttle;
struct attribute_group *attr_group;
struct kobject *kobj;
};
/* global */
static u64 sched_hint_check_timestamp;
static u64 sched_hint_check_interval;
static struct sched_hint_data g_shd;
static int sched_hint_inited;
static struct kobj_attribute sched_iso_attr;
static struct kobj_attribute set_sched_iso_attr;
static struct kobj_attribute set_sched_deiso_attr;
#ifdef CONFIG_MTK_SCHED_SYSHINT
static int sched_hint_on = 1; /* default on */
#else
static int sched_hint_on; /* default off */
#endif
static enum sched_status_t kthread_status = SCHED_STATUS_INIT;
static enum sched_status_t sched_status = SCHED_STATUS_INIT;
static int sched_hint_loading_thresh = 5; /* 5% (max 100%) */
static BLOCKING_NOTIFIER_HEAD(sched_hint_notifier_list);
static DEFINE_SPINLOCK(status_lock);
#ifdef CONFIG_MTK_SCHED_BOOST
static struct kobj_attribute sched_boost_attr;
static struct kobj_attribute sched_cpu_prefer_attr;
#endif
static int sched_ramup_factor; /*0 means disable (min:1%,max 100%)*/
static int sched_hint_status(int util, int cap)
{
enum sched_status_t status;
if (((util * 100) / cap) > sched_hint_loading_thresh)
status = SCHED_STATUS_OVERUTIL;
else
status = SCHED_STATUS_UNDERUTIL;
return status;
}
/* kernel thread */
static int sched_hint_thread(void *data)
{
do {
set_current_state(TASK_INTERRUPTIBLE);
schedule();
if (kthread_should_stop())
break;
/* status change from scheduler hint */
if (kthread_status != sched_status) {
int ret;
kthread_status = sched_status;
//TODO: remove comment after met ready
//met_tag_oneshot(0, "sched_hint", kthread_status);
ret = blocking_notifier_call_chain
(&sched_hint_notifier_list,
kthread_status, NULL);
/* reset throttle time */
g_shd.throttle = ktime_add_ns(
ktime_get(),
SCHED_HINT_THROTTLE_NSEC);
}
#if 0
if (true) { /* debugging code */
int iter_cpu;
for (iter_cpu = 0; iter_cpu < nr_cpu_ids; iter_cpu++)
#ifdef CONFIG_MTK_SCHED_CPULOAD
met_tag_oneshot(0, met_cpu_load[iter_cpu],
sched_get_cpu_load(iter_cpu));
#endif
}
#endif
} while (!kthread_should_stop());
return 0;
}
static void sched_irq_work(struct irq_work *irq_work)
{
struct sched_hint_data *shd;
if (!irq_work)
return;
shd = container_of(irq_work, struct sched_hint_data, irq_work);
wake_up_process(shd->task);
}
static bool hint_need(void)
{
return (kthread_status == sched_status) ? false : true;
}
static bool do_check(u64 wallclock)
{
bool do_check = false;
unsigned long flags;
/* check interval */
spin_lock_irqsave(&status_lock, flags);
if ((wallclock - sched_hint_check_timestamp)
>= sched_hint_check_interval) {
sched_hint_check_timestamp = wallclock;
do_check = true;
}
spin_unlock_irqrestore(&status_lock, flags);
/* is throttled ? */
if (ktime_before(ktime_get(), g_shd.throttle))
do_check = false;
return do_check;
}
void sched_hint_check(u64 wallclock)
{
if (!sched_hint_inited || !sched_hint_on)
return;
if (do_check(wallclock)) {
if (hint_need())
/* wake up ksched_hint */
wake_up_process(g_shd.task);
}
}
/* scheduler update hint in fair.c */
void update_sched_hint(int sys_util, int sys_cap)
{
ktime_t throttle = g_shd.throttle;
ktime_t now = ktime_get();
if (!sched_hint_inited || !sched_hint_on)
return;
if (ktime_before(now, throttle)) {
/* met_tag_oneshot(0, "sched_hint_throttle", 1); */
return;
}
if (!sys_cap)
return;
g_shd.sys_util = sys_util;
g_shd.sys_cap = sys_cap;
sched_status = sched_hint_status(sys_util, sys_cap);
if (kthread_status != sched_status)
irq_work_queue_on(&g_shd.irq_work, smp_processor_id());
}
/* A user-space interfaces: */
static ssize_t store_sched_enable(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
unsigned int val = 0;
if (sscanf(buf, "%iu", &val) != 0)
sched_hint_on = (val) ? 1 : 0;
return count;
}
static ssize_t store_sched_load_thresh(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
unsigned int val = 0;
if (sscanf(buf, "%iu", &val) != 0) {
if (val >= 0 && val < 100)
sched_hint_loading_thresh = val;
}
return count;
}
static ssize_t show_sched_info(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
unsigned int len = 0;
unsigned int max_len = 4096;
len += snprintf(buf, max_len, "capacity total=%d\n", g_shd.sys_cap);
len += snprintf(buf+len, max_len - len,
"capacity used=%d\n", g_shd.sys_util);
if (sched_hint_on) {
if (kthread_status != SCHED_STATUS_INIT)
len += snprintf(buf+len,
max_len - len,
"status=(%s)\n",
(kthread_status !=
SCHED_STATUS_OVERUTIL) ?
"under" : "over");
else
len += snprintf(buf+len,
max_len - len,
"status=(init)\n");
} else
len += snprintf(buf+len, max_len - len, "status=(off)\n");
len += snprintf(buf+len, max_len - len, "load thresh=%d%c\n",
sched_hint_loading_thresh, '%');
return len;
}
static ssize_t show_walt_info(struct kobject *kobj,
struct kobj_attribute *attr, char *buf);
static ssize_t store_walt_info(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count);
static struct kobj_attribute sched_enable_attr =
__ATTR(hint_enable, 0200 /* S_IWUSR */, NULL, store_sched_enable);
static struct kobj_attribute sched_load_thresh_attr =
__ATTR(hint_load_thresh, 0200 /* S_IWUSR */, NULL, store_sched_load_thresh);
static struct kobj_attribute sched_info_attr =
__ATTR(hint_info, 0400 /* S_IRUSR */, show_sched_info, NULL);
static struct kobj_attribute sched_walt_info_attr =
__ATTR(walt_debug, 0600 /* S_IWUSR | S_IRUSR */,
show_walt_info, store_walt_info);
static ssize_t store_sched_forked_ramup_factor(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
unsigned int val = 0;
if (sscanf(buf, "%iu", &val) != 0) {
if (val >= 0 && val <= 100)
sched_ramup_factor = val;
}
return count;
}
static ssize_t show_sched_forked_ramup_factor(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
unsigned int len = 0;
unsigned int max_len = 4096;
len += snprintf(buf, max_len, "%d\n", sched_ramup_factor);
return len;
}
int sched_forked_ramup_factor(void)
{
return sched_ramup_factor;
}
static struct kobj_attribute sched_forked_ramup_factor_attr =
__ATTR(sched_forked_ramup_factor, 0644, show_sched_forked_ramup_factor,
store_sched_forked_ramup_factor);
static struct attribute *sched_attrs[] = {
&sched_info_attr.attr,
&sched_load_thresh_attr.attr,
&sched_enable_attr.attr,
&sched_walt_info_attr.attr,
#ifdef CONFIG_MTK_SCHED_BOOST
&sched_cpu_prefer_attr.attr,
&sched_boost_attr.attr,
#endif
&sched_iso_attr.attr,
&set_sched_iso_attr.attr,
&set_sched_deiso_attr.attr,
&sched_forked_ramup_factor_attr.attr,
NULL,
};
static struct attribute_group sched_attr_group = {
.attrs = sched_attrs,
};
int register_sched_hint_notifier(struct notifier_block *nb)
{
return blocking_notifier_chain_register(&sched_hint_notifier_list, nb);
}
EXPORT_SYMBOL(register_sched_hint_notifier);
int unregister_sched_hint_notifier(struct notifier_block *nb)
{
return blocking_notifier_chain_unregister
(&sched_hint_notifier_list, nb);
}
EXPORT_SYMBOL(unregister_sched_hint_notifier);
/* init function */
static int __init sched_hint_init(void)
{
int ret;
/* create thread */
g_shd.task = kthread_create(sched_hint_thread, NULL, "ksched_hint");
if (IS_ERR_OR_NULL(g_shd.task)) {
printk_deferred("%s: failed to create ksched_hint thread.\n",
__func__);
goto err;
}
/* keep thread alive */
get_task_struct(g_shd.task);
/* init throttle time */
g_shd.throttle = ktime_get();
wake_up_process(g_shd.task);
/* init irq_work */
init_irq_work(&g_shd.irq_work, sched_irq_work);
/* check interval 20ms */
sched_hint_check_interval = CPU_LOAD_AVG_DEFAULT_MS * NSEC_PER_MSEC;
/* enable sched hint */
sched_hint_inited = 1;
/*
* create a sched in cpu_subsys:
* /sys/devices/system/cpu/sched/...
*/
g_shd.attr_group = &sched_attr_group;
g_shd.kobj = kobject_create_and_add("sched",
&cpu_subsys.dev_root->kobj);
if (g_shd.kobj) {
ret = sysfs_create_group(g_shd.kobj, g_shd.attr_group);
if (ret)
kobject_put(g_shd.kobj);
else
kobject_uevent(g_shd.kobj, KOBJ_ADD);
}
return 0;
err:
return -ENOMEM;
}
late_initcall(sched_hint_init);
#ifdef CONFIG_MTK_SCHED_BOOST
static int sched_boost_type = SCHED_NO_BOOST;
inline int valid_cpu_prefer(int task_prefer)
{
if (task_prefer < SCHED_PREFER_NONE || task_prefer >= SCHED_PREFER_END)
return 0;
return 1;
}
int sched_set_cpuprefer(pid_t pid, unsigned int prefer_type)
{
struct task_struct *p;
unsigned long flags;
int retval = 0;
if (!valid_cpu_prefer(prefer_type) || pid < 0)
return -EINVAL;
rcu_read_lock();
retval = -ESRCH;
p = find_task_by_vpid(pid);
if (p != NULL) {
raw_spin_lock_irqsave(&p->pi_lock, flags);
p->cpu_prefer = prefer_type;
raw_spin_unlock_irqrestore(&p->pi_lock, flags);
trace_sched_set_cpuprefer(p);
retval = 0;
}
rcu_read_unlock();
return retval;
}
inline int hinted_cpu_prefer(int task_prefer)
{
if (task_prefer <= SCHED_PREFER_NONE || task_prefer >= SCHED_PREFER_END)
return 0;
return 1;
}
/*
* check if the task or the whole system to prefer to put on big core
*
*/
int cpu_prefer(struct task_struct *p)
{
if (sched_boost_type == SCHED_ALL_BOOST)
return SCHED_PREFER_BIG;
if (p->cpu_prefer == SCHED_PREFER_LITTLE &&
schedtune_task_boost(p))
return SCHED_PREFER_NONE;
return p->cpu_prefer;
}
int task_prefer_little(struct task_struct *p)
{
if (cpu_prefer(p) == SCHED_PREFER_LITTLE)
return 1;
return 0;
}
int task_prefer_big(struct task_struct *p)
{
if (cpu_prefer(p) == SCHED_PREFER_BIG)
return 1;
return 0;
}
int task_prefer_fit(struct task_struct *p, int cpu)
{
if (cpu_prefer(p) == SCHED_PREFER_NONE)
return 0;
if (task_prefer_little(p) && hmp_cpu_is_slowest(cpu))
return 1;
if (task_prefer_big(p) && hmp_cpu_is_fastest(cpu))
return 1;
return 0;
}
int task_prefer_match(struct task_struct *p, int cpu)
{
if (cpu_prefer(p) == SCHED_PREFER_NONE)
return 1;
if (task_prefer_little(p) && hmp_cpu_is_slowest(cpu))
return 1;
if (task_prefer_big(p) && hmp_cpu_is_fastest(cpu))
return 1;
return 0;
}
int
task_prefer_match_on_cpu(struct task_struct *p, int src_cpu, int target_cpu)
{
/* No need to migrate*/
if (is_intra_domain(src_cpu, target_cpu))
return 1;
if (cpu_prefer(p) == SCHED_PREFER_NONE)
return 1;
if (task_prefer_little(p) && hmp_cpu_is_slowest(src_cpu))
return 1;
if (task_prefer_big(p) && hmp_cpu_is_fastest(src_cpu))
return 1;
return 0;
}
#ifdef CONFIG_MACH_MT6873
int calc_cpu_util(const struct sched_group_energy *sge, int cpu,
struct task_struct *p, int calc_dvfs_opp)
{
unsigned long wake_util, new_util;
unsigned long max_capacity = cluster_max_capacity();
unsigned long min_util = uclamp_task_effective_util(p, UCLAMP_MIN);
unsigned long max_util = uclamp_task_effective_util(p, UCLAMP_MAX);
int opp_idx;
wake_util = cpu_util_without(cpu, p);
new_util = wake_util + task_util_est(p);
max_util = min(max_capacity, max_util);
new_util = clamp(new_util, min_util, max_util);
new_util = new_util * capacity_margin >> SCHED_CAPACITY_SHIFT;
new_util = min_t(unsigned long, new_util,
(unsigned long) sge->cap_states[sge->nr_cap_states-1].cap);
if (calc_dvfs_opp) {
for (opp_idx = 0; opp_idx < sge->nr_cap_states ; opp_idx++) {
if (sge->cap_states[opp_idx].cap >= new_util) {
new_util = sge->cap_states[opp_idx].cap;
break;
}
}
}
return new_util;
}
int aware_big_thermal(int cpu, struct task_struct *p)
{
struct hmp_domain *hmp_domain = NULL;
struct sched_domain *sd;
struct sched_group *sg;
const unsigned long *cpus;
const struct sched_group_energy *sge;
int cpu_idx, last_cpu;
int new_cpu = cpu;
unsigned long min_new_util, new_util;
if (hmp_cpu_is_fastest(cpu)) {
hmp_domain = hmp_cpu_domain(cpu);
cpus = cpumask_bits(&hmp_domain->possible_cpus);
last_cpu = find_last_bit(cpus, num_possible_cpus());
if (cpu == last_cpu)
return cpu;
rcu_read_lock();
sd = rcu_dereference_check_sched_domain(cpu_rq(cpu)->sd);
if (sd) {
sg = sd->groups;
sge = sg->sge;
} else
goto out;
min_new_util = calc_cpu_util(sge, cpu, p, 1);
for (cpu_idx = last_cpu; cpu_idx > cpu; --cpu_idx) {
if (idle_cpu(cpu_idx)) {
new_util = calc_cpu_util(sge, cpu_idx, p, 0);
if (min_new_util >= new_util) {
new_cpu = cpu_idx;
break;
}
}
}
out:
rcu_read_unlock();
}
return new_cpu;
}
#endif
#ifdef CONFIG_MACH_MT6873
static int efuse_aware_big_thermal;
void __init init_efuse_info(void)
{
efuse_aware_big_thermal = (get_devinfo_with_index(7) & 0xFF) == 0x30;
}
#endif
int select_task_prefer_cpu(struct task_struct *p, int new_cpu)
{
int task_prefer;
struct hmp_domain *domain;
struct hmp_domain *tmp_domain[5] = {0, 0, 0, 0, 0};
int i, iter_domain, domain_cnt = 0;
int iter_cpu;
struct cpumask *tsk_cpus_allow = &p->cpus_allowed;
#ifdef CONFIG_MTK_TASK_TURBO
unsigned long spare_cap, max_spare_cap = 0;
int max_spare_cpu = -1;
#endif
task_prefer = cpu_prefer(p);
if (!hinted_cpu_prefer(task_prefer))
goto out;
for_each_hmp_domain_L_first(domain) {
tmp_domain[domain_cnt] = domain;
domain_cnt++;
}
for (i = 0; i < domain_cnt; i++) {
iter_domain = (task_prefer == SCHED_PREFER_BIG) ?
domain_cnt-i-1 : i;
domain = tmp_domain[iter_domain];
#ifdef CONFIG_MTK_TASK_TURBO
/* check fastest domain for turbo task*/
if (is_turbo_task(p) && i != 0)
break;
#endif
if (cpumask_test_cpu(new_cpu, &domain->possible_cpus) && !cpu_isolated(new_cpu))
goto out;
for_each_cpu(iter_cpu, &domain->possible_cpus) {
/* tsk with prefer idle to find bigger idle cpu */
if (!cpu_online(iter_cpu) ||
!cpumask_test_cpu(iter_cpu, tsk_cpus_allow) ||
cpu_isolated(iter_cpu))
continue;
/* favoring tasks that prefer idle cpus
* to improve latency.
*/
if (idle_cpu(iter_cpu)) {
new_cpu = iter_cpu;
goto out;
}
#ifdef CONFIG_MTK_TASK_TURBO
if (is_turbo_task(p)) {
spare_cap = capacity_spare_without(iter_cpu, p);
if (spare_cap > max_spare_cap) {
max_spare_cap = spare_cap;
max_spare_cpu = iter_cpu;
}
}
#endif
}
}
#ifdef CONFIG_MTK_TASK_TURBO
if (is_turbo_task(p) && (max_spare_cpu > 0))
new_cpu = max_spare_cpu;
#endif
out:
#ifdef CONFIG_MACH_MT6873
if (efuse_aware_big_thermal)
new_cpu = aware_big_thermal(new_cpu, p);
#endif
return new_cpu;
}
void sched_set_boost_fg(void)
{
struct cpumask cpus;
int nr;
/* 1: Root
* 2: foreground
* 3: Foregrond/boost
* 4: background
* 5: system-background
* 6: top-app
*/
nr = arch_get_nr_clusters();
arch_get_cluster_cpus(&cpus, nr-1);
set_user_space_global_cpuset(&cpus, 3);
set_user_space_global_cpuset(&cpus, 2);
set_user_space_global_cpuset(&cpus, 6);
}
void sched_unset_boost_fg(void)
{
unset_user_space_global_cpuset(2);
unset_user_space_global_cpuset(3);
unset_user_space_global_cpuset(6);
}
/* A mutex for scheduling boost switcher */
static DEFINE_MUTEX(sched_boost_mutex);
int set_sched_boost(unsigned int val)
{
static unsigned int sysctl_sched_isolation_hint_enable_backup = -1;
if ((val < SCHED_NO_BOOST) || (val >= SCHED_UNKNOWN_BOOST))
return -1;
if (sched_boost_type == val)
return 0;
mutex_lock(&sched_boost_mutex);
/* back to original setting*/
if (sched_boost_type == SCHED_ALL_BOOST)
sched_scheduler_switch(SCHED_HYBRID_LB);
else if (sched_boost_type == SCHED_FG_BOOST)
sched_unset_boost_fg();
sched_boost_type = val;
if (val == SCHED_NO_BOOST) {
if (sysctl_sched_isolation_hint_enable_backup > 0)
sysctl_sched_isolation_hint_enable =
sysctl_sched_isolation_hint_enable_backup;
} else if ((val > SCHED_NO_BOOST) && (val < SCHED_UNKNOWN_BOOST)) {
sysctl_sched_isolation_hint_enable_backup =
sysctl_sched_isolation_hint_enable;
sysctl_sched_isolation_hint_enable = 0;
if (val == SCHED_ALL_BOOST)
sched_scheduler_switch(SCHED_HMP_LB);
else if (val == SCHED_FG_BOOST)
sched_set_boost_fg();
}
printk_deferred("[name:sched_boost&] sched boost: set %d\n",
sched_boost_type);
mutex_unlock(&sched_boost_mutex);
return 0;
}
EXPORT_SYMBOL(set_sched_boost);
/* turn on/off sched boost scheduling */
static ssize_t show_cpu_prefer(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
unsigned int len = 0;
return len;
}
static ssize_t store_cpu_prefer(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
pid_t pid;
unsigned int prefer_type;
/*
* 0: NO sched boost
* 1: boost ALL task
* 2: boost foreground task
*/
if (sscanf(buf, "%d %u", &pid, &prefer_type) != 0)
sched_set_cpuprefer(pid, prefer_type);
else
return -1;
return count;
}
static struct kobj_attribute sched_cpu_prefer_attr =
__ATTR(cpu_prefer, 0600, show_cpu_prefer,
store_cpu_prefer);
/* turn on/off sched boost scheduling */
static ssize_t show_sched_boost(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
unsigned int len = 0;
unsigned int max_len = 4096;
switch (sched_boost_type) {
case SCHED_ALL_BOOST:
len += snprintf(buf, max_len, "sched boost= all boost\n\n");
break;
case SCHED_FG_BOOST:
len += snprintf(buf, max_len,
"sched boost= foreground boost\n\n");
break;
default:
len += snprintf(buf, max_len, "sched boost= no boost\n\n");
break;
}
return len;
}
static ssize_t store_sched_boost(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
unsigned int val = 0;
/*
* 0: NO sched boost
* 1: boost ALL task
* 2: boost foreground task
*/
if (sscanf(buf, "%iu", &val) != 0)
set_sched_boost(val);
return count;
}
static struct kobj_attribute sched_boost_attr =
__ATTR(sched_boost, 0600, show_sched_boost,
store_sched_boost);
#else
inline int task_prefer_little(struct task_struct *p)
{
return 0;
}
inline int task_prefer_big(struct task_struct *p)
{
return 0;
}
inline int task_prefer_fit(struct task_struct *p, int cpu)
{
return 0;
}
inline int task_prefer_match(struct task_struct *p, int cpu)
{
return 1;
}
int select_task_prefer_cpu(struct task_struct *p, int new_cpu)
{
return new_cpu;
}
int sched_set_cpuprefer(pid_t pid, unsigned int prefer_type)
{
return -EINVAL;
}
#endif
/* schedule loading trackign change
* 0: default
* 1: walt
*/
static int lt_walt_table[LT_UNKNOWN_USER];
static int walt_dbg;
static char walt_maker_name[LT_UNKNOWN_USER+1][32] = {
"powerHAL",
"fpsGO",
"sched",
"debug",
"unknown"
};
int sched_walt_enable(int user, int en)
{
int walted = 0;
int i;
unsigned int user_mask = 0;
if ((user < 0) || (user >= LT_UNKNOWN_USER))
return -1;
lt_walt_table[user] = en;
for (i = 0; i < LT_UNKNOWN_USER; i++) {
walted |= lt_walt_table[i];
user_mask |= (lt_walt_table[i] << i);
}
if (walt_dbg) {
walted = lt_walt_table[LT_WALT_DEBUG];
user_mask = 0xFFFF;
}
#ifdef CONFIG_SCHED_WALT
sysctl_sched_use_walt_cpu_util = walted;
sysctl_sched_use_walt_task_util = walted;
trace_sched_ctl_walt(user_mask, walted);
#endif
return 0;
}
EXPORT_SYMBOL(sched_walt_enable);
static ssize_t show_walt_info(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
unsigned int len = 0;
unsigned int max_len = 4096;
int i;
int supported = 0;
for (i = 0; i < LT_UNKNOWN_USER; i++)
len += snprintf(buf+len, max_len - len, "walt[%d] = %d (%s)\n",
i, lt_walt_table[i], walt_maker_name[i]);
#ifdef CONFIG_SCHED_WALT
supported = 1;
#endif
len += snprintf(buf+len, max_len - len,
"\nWALT support:%d\n", supported);
len += snprintf(buf+len, max_len - len,
"debug mode:%d\n", walt_dbg);
len += snprintf(buf+len, max_len - len,
"format: echo (debug:walt)\n");
return len;
}
/*
* argu1: enable debug mode
* argu2: walted or not.
*
* echo 1 0 : enable debug mode, foring walted off.
*/
static ssize_t store_walt_info(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
int walted = -1;
if (sscanf(buf, "%d:%d", &walt_dbg, &walted) <= 0)
return count;
if (walted < 0 || walted > 1 || walt_dbg < 0 || walt_dbg > 1)
return count;
if (walt_dbg)
sched_walt_enable(LT_WALT_DEBUG, walted);
else
sched_walt_enable(LT_WALT_DEBUG, 0);
return count;
}
/* turn on/off sched boost scheduling */
static ssize_t show_sched_iso(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
unsigned int len = 0;
unsigned int max_len = 4096;
len += snprintf(buf+len, max_len-len, "cpu_isolated_mask=0x%lx\n",
cpu_isolated_mask->bits[0]);
len += snprintf(buf+len, max_len-len, "iso_prio=%d\n", iso_prio);
return len;
}
static ssize_t set_sched_iso(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
unsigned int val = 0;
if (sscanf(buf, "%iu", &val) < nr_cpu_ids)
sched_isolate_cpu(val);
return count;
}
static ssize_t set_sched_deiso(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
unsigned int val = 0;
if (sscanf(buf, "%iu", &val) < nr_cpu_ids)
sched_deisolate_cpu(val);
return count;
}
static struct kobj_attribute sched_iso_attr =
__ATTR(sched_isolation, 0400, show_sched_iso, NULL);
static struct kobj_attribute set_sched_iso_attr =
__ATTR(set_sched_isolation, 0200, NULL, set_sched_iso);
static struct kobj_attribute set_sched_deiso_attr =
__ATTR(set_sched_deisolation, 0200, NULL, set_sched_deiso);