Initial commit: Linux kernel 4.19 for Unplugged OS

This commit is contained in:
ziv committed 2025-10-06 13:52:42 +00:00
commit d30235b04c
80519 files changed
+35800681

No files matched your search

@@ -0,0 +1,23 @@
#
# Copyright (C) 2018 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 the
# GNU General Public License for more details.
#
obj-y += boostctrl_main.o
obj-y += dram_ctrl/
obj-y += cpu_ctrl/
obj-y += eas_ctrl/
obj-y += topo_ctrl/
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include <linux/proc_fs.h>
#include "boost_ctrl.h"
int init_boostctrl(struct proc_dir_entry *parent)
{
struct proc_dir_entry *bstctrl_root = NULL;
struct proc_dir_entry *easctrl_root = NULL;
pr_debug("__init %s\n", __func__);
bstctrl_root = proc_mkdir("boost_ctrl", parent);
/* init topology info first */
topo_ctrl_init(bstctrl_root);
cpu_ctrl_init(bstctrl_root);
dram_ctrl_init(bstctrl_root);
/* EAS */
easctrl_root = proc_mkdir("eas_ctrl", bstctrl_root);
uclamp_ctrl_init(easctrl_root);
eas_ctrl_init(easctrl_root);
return 0;
}
@@ -0,0 +1,69 @@
#
# Copyright (C) 2018 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 the
# GNU General Public License for more details.
#
ifeq ($(CONFIG_MTK_PPM),y)
obj-y += cpu_ctrl.o
else
# no CONFIG_MTK_PPM but specific lagacy platform
ifneq (,$(filter $(CONFIG_MTK_PLATFORM), "mt6761" "mt6765" "mt6768" "mt6873" "mt6885" "mt6893" "mt6771" "mt6785" "mt6853" "mt6739"))
ifeq ($(CONFIG_MTK_GKI_COMPAT),y)
obj-y += cpu_ctrl_dummy.o
else
obj-y += cpu_ctrl.o
endif # CONFIG_MTK_GKI_COMPAT
else
obj-y += cpu_ctrl_dummy.o
endif
endif # CONFIG_MTK_PPM
ifeq ($(CONFIG_MACH_MT6893),y)
ccflags-y += \
-DMTK_K14_CPU_BOOST
else ifeq ($(CONFIG_MACH_MT6885),y)
ccflags-y += \
-DMTK_K14_CPU_BOOST
else ifeq ($(CONFIG_MACH_MT6877),y)
ccflags-y += \
-DMTK_K14_CPU_BOOST
else ifeq ($(CONFIG_MACH_MT6873),y)
ccflags-y += \
-DMTK_K14_CPU_BOOST
else ifeq ($(CONFIG_MACH_MT6853),y)
ccflags-y += \
-DMTK_K14_CPU_BOOST
else ifeq ($(CONFIG_MACH_MT6781),y)
ccflags-y += \
-DMTK_K14_CPU_BOOST
else ifeq ($(CONFIG_MACH_MT6739),y)
ccflags-y += \
-DMTK_K14_CPU_BOOST
else ifeq ($(CONFIG_MACH_MT6833),y)
ccflags-y += \
-DMTK_K14_CPU_BOOST
else ifeq ($(CONFIG_MACH_MT6768),y)
ccflags-y += \
-DMTK_K14_CPU_BOOST
else ifeq ($(CONFIG_MACH_MT6771),y)
ccflags-y += \
-DMTK_K14_CPU_BOOST
else ifeq ($(CONFIG_MACH_MT6785),y)
ccflags-y += \
-DMTK_K14_CPU_BOOST
endif
obj-$(CONFIG_MTK_CPU_CTRL_CFP) += cpu_ctrl_cfp.o
ccflags-y += -I$(srctree)/drivers/misc/mediatek/base/power/include/
ccflags-y += -I$(srctree)drivers/misc/mediatek/performance/include/
@@ -0,0 +1,798 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#define pr_fmt(fmt) "[cpu_ctrl]"fmt
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/cpufreq.h>
#ifdef CONFIG_MTK_CORE_CTL
#include <mt-plat/core_ctl.h>
#endif
#include <mt-plat/cpu_ctrl.h>
#include <mt-plat/mtk_ppm_api.h>
#include "boost_ctrl.h"
#include "mtk_perfmgr_internal.h"
#include "topo_ctrl.h"
#ifdef CONFIG_MTK_CPU_CTRL_CFP
#include "cpu_ctrl_cfp.h"
#endif
#ifdef CONFIG_TRACING
#include <linux/kallsyms.h>
#include <linux/trace_events.h>
#endif
#include <linux/io.h>
#define MAX_CLUSTER_COUNT 3
static struct mutex boost_freq;
static struct mutex isolate_lock;
static struct ppm_limit_data *current_freq;
static struct ppm_limit_data *freq_set[CPU_MAX_KIR];
static int log_enable;
static unsigned long *policy_mask;
#ifdef CONFIG_MTK_CPU_CTRL_CFP
static int cfp_init_ret;
#endif
int powerhal_tid;
#include "eas_ctrl_plat.h"
#define MAX_CLUSTER_COUNT 3
static int num_cpu;
static struct mutex isolate_lock;
static int perfserv_isolation_cpu;
struct cluster_data {
int core_min;
int core_max;
};
static int *cpu_isolation[CPU_ISO_MAX_KIR];
static struct cluster_data core_set[CPU_ISO_MAX_KIR][MAX_CLUSTER_COUNT];
static struct cluster_data default_core_set[MAX_CLUSTER_COUNT];
static int isolation_used[CPU_ISO_MAX_KIR];
static int all_cpu_deisolated;
static int isBooting;
/*******************************************/
int update_userlimit_cpu_freq(int kicker, int num_cluster
, struct cpu_ctrl_data *freq_limit)
{
struct ppm_limit_data *final_freq;
int retval = 0;
int i, j, len = 0, len1 = 0;
char msg[LOG_BUF_SIZE];
char msg1[LOG_BUF_SIZE];
mutex_lock(&boost_freq);
final_freq = kcalloc(perfmgr_clusters
, sizeof(struct ppm_limit_data), GFP_KERNEL);
if (!final_freq) {
retval = -1;
perfmgr_trace_printk("cpu_ctrl", "!final_freq\n");
goto ret_update;
}
if (num_cluster != perfmgr_clusters) {
pr_debug(
"num_cluster : %d perfmgr_clusters: %d, doesn't match\n",
num_cluster, perfmgr_clusters);
retval = -1;
perfmgr_trace_printk("cpu_ctrl",
"num_cluster != perfmgr_clusters\n");
goto ret_update;
}
if (kicker < 0 || kicker >= CPU_MAX_KIR) {
pr_debug("kicker:%d, error\n", kicker);
retval = -1;
goto ret_update;
}
for_each_perfmgr_clusters(i) {
final_freq[i].min = -1;
final_freq[i].max = -1;
}
len += snprintf(msg + len, sizeof(msg) - len, "[%d] ", kicker);
if (len < 0) {
perfmgr_trace_printk("cpu_ctrl", "return -EIO 1\n");
mutex_unlock(&boost_freq);
return -EIO;
}
for_each_perfmgr_clusters(i) {
freq_set[kicker][i].min = freq_limit[i].min >= -1 ?
freq_limit[i].min : -1;
freq_set[kicker][i].max = freq_limit[i].max >= -1 ?
freq_limit[i].max : -1;
len += snprintf(msg + len, sizeof(msg) - len, "(%d)(%d) ",
freq_set[kicker][i].min, freq_set[kicker][i].max);
if (len < 0) {
perfmgr_trace_printk("cpu_ctrl", "return -EIO 2\n");
mutex_unlock(&boost_freq);
return -EIO;
}
if (freq_set[kicker][i].min == -1 &&
freq_set[kicker][i].max == -1)
clear_bit(kicker, &policy_mask[i]);
else
set_bit(kicker, &policy_mask[i]);
len1 += snprintf(msg1 + len1, sizeof(msg1) - len1,
"[0x %lx] ", policy_mask[i]);
if (len1 < 0) {
perfmgr_trace_printk("cpu_ctrl", "return -EIO 3\n");
mutex_unlock(&boost_freq);
return -EIO;
}
}
for (i = 0; i < CPU_MAX_KIR; i++) {
for_each_perfmgr_clusters(j) {
final_freq[j].min
= MAX(freq_set[i][j].min, final_freq[j].min);
#ifdef CONFIG_MTK_CPU_CTRL_CFP
final_freq[j].max
= final_freq[j].max != -1 &&
freq_set[i][j].max != -1 ?
MIN(freq_set[i][j].max, final_freq[j].max) :
MAX(freq_set[i][j].max, final_freq[j].max);
#else
final_freq[j].max
= MAX(freq_set[i][j].max, final_freq[j].max);
#endif
if (final_freq[j].min > final_freq[j].max &&
final_freq[j].max != -1)
final_freq[j].max = final_freq[j].min;
}
}
for_each_perfmgr_clusters(i) {
current_freq[i].min = final_freq[i].min;
current_freq[i].max = final_freq[i].max;
len += snprintf(msg + len, sizeof(msg) - len, "{%d}{%d} ",
current_freq[i].min, current_freq[i].max);
if (len < 0) {
perfmgr_trace_printk("cpu_ctrl", "return -EIO 4\n");
mutex_unlock(&boost_freq);
return -EIO;
}
}
if (len >= 0 && len < LOG_BUF_SIZE) {
len1 = LOG_BUF_SIZE - len - 1;
if (len1 > 0)
strncat(msg, msg1, len1);
}
if (log_enable)
pr_debug("%s", msg);
#ifdef CONFIG_TRACING
perfmgr_trace_printk("cpu_ctrl", msg);
#endif
#ifdef CONFIG_MTK_CPU_CTRL_CFP
if (!cfp_init_ret)
cpu_ctrl_cfp(final_freq);
else
mt_ppm_userlimit_cpu_freq(perfmgr_clusters, final_freq);
#else
mt_ppm_userlimit_cpu_freq(perfmgr_clusters, final_freq);
#endif
ret_update:
kfree(final_freq);
mutex_unlock(&boost_freq);
return retval;
return 0;
}
EXPORT_SYMBOL(update_userlimit_cpu_freq);
#ifdef CONFIG_MTK_CORE_CTL
int update_cpu_core_limit(int kicker, int cid, int min, int max)
{
int i, final_min, final_max;
if (kicker < 0 || cid < 0) {
pr_debug("kicker: %d, cid: %d errro\n", kicker, cid);
return -1;
}
perfmgr_trace_count(kicker,
"update_cpu_core_limit_%d_%d_%d_%d", kicker, cid, min, max);
mutex_lock(&boost_freq);
core_set[kicker][cid].core_min = min;
core_set[kicker][cid].core_max = max;
final_min = -1;
final_max = default_core_set[cid].core_max;
for (i = 0; i <= CPU_ISO_KIR_FPSGO; i++) {
if (core_set[i][cid].core_max >= 0 &&
final_min <= core_set[i][cid].core_max &&
core_set[i][cid].core_max <= final_max)
final_max = core_set[i][cid].core_max;
if (final_min < core_set[i][cid].core_min) {
if (core_set[i][cid].core_min <= final_max)
final_min = core_set[i][cid].core_min;
else
final_min = (final_max < 0) ?
core_set[i][cid].core_min : final_max;
}
}
if (final_max < 0)
final_max = default_core_set[cid].core_max;
if (final_min < 0)
final_min = MIN(default_core_set[cid].core_min, final_max);
perfmgr_trace_count(kicker,
"core_ctl_set_limit_cpus_%d_%d_%d", cid, final_min, final_max);
core_ctl_set_limit_cpus(cid, final_min, final_max);
mutex_unlock(&boost_freq);
return 0;
}
EXPORT_SYMBOL(update_cpu_core_limit);
#endif
/***************************************/
static ssize_t perfmgr_perfserv_freq_proc_write(struct file *filp
, const char __user *ubuf, size_t cnt, loff_t *pos)
{
int i = 0, data;
struct cpu_ctrl_data *freq_limit;
unsigned int arg_num = perfmgr_clusters * 2; /* for min and max */
char *tok, *tmp;
char *buf = perfmgr_copy_from_user_for_proc(ubuf, cnt);
if (!buf) {
pr_debug("buf is null\n");
goto out1;
}
freq_limit = kcalloc(perfmgr_clusters, sizeof(struct cpu_ctrl_data),
GFP_KERNEL);
if (!freq_limit)
goto out;
tmp = buf;
pr_debug("freq write_to_file\n");
while ((tok = strsep(&tmp, " ")) != NULL) {
if (i == arg_num) {
pr_debug(
"@%s: number of arguments > %d!\n",
__func__, arg_num);
goto out;
}
if (kstrtoint(tok, 10, &data)) {
pr_debug("@%s: Invalid input: %s\n",
__func__, tok);
goto out;
} else {
if (i % 2) /* max */
freq_limit[i/2].max = data;
else /* min */
freq_limit[i/2].min = data;
i++;
}
}
if (i < arg_num) {
pr_debug(
"@%s: number of arguments < %d!\n",
__func__, arg_num);
} else {
powerhal_tid = current->pid;
update_userlimit_cpu_freq(CPU_KIR_PERF
, perfmgr_clusters, freq_limit);
}
out:
free_page((unsigned long)buf);
kfree(freq_limit);
out1:
return cnt;
}
static int perfmgr_perfserv_freq_proc_show(struct seq_file *m, void *v)
{
int i;
for_each_perfmgr_clusters(i)
seq_printf(m, "cluster %d min:%d max:%d\n",
i, freq_set[CPU_KIR_PERF][i].min,
freq_set[CPU_KIR_PERF][i].max);
return 0;
}
/***************************************/
#define MAX_NR_FREQ 16
static ssize_t perfmgr_boot_freq_proc_write(struct file *filp,
const char __user *ubuf, size_t cnt, loff_t *pos)
{
int i = 0, data, cid;
struct cpu_ctrl_data *freq_limit;
unsigned int arg_num = perfmgr_clusters * 2; /* for min and max */
char *tok, *tmp;
char *buf = perfmgr_copy_from_user_for_proc(ubuf, cnt);
freq_limit = kcalloc(perfmgr_clusters,
sizeof(struct cpu_ctrl_data), GFP_KERNEL);
if (!freq_limit)
goto out;
for_each_perfmgr_clusters(cid)
freq_limit[cid].min = freq_limit[cid].max = -1;
tmp = buf;
while ((tok = strsep(&tmp, " ")) != NULL) {
if (i == arg_num) {
pr_debug("@%s: number of arguments > %d!\n",
__func__, arg_num);
break;
}
if (kstrtoint(tok, 10, &data)) {
pr_debug("@%s: Invalid input: %s\n", __func__, tok);
goto out;
} else {
if (i % 2) { /* max */
freq_limit[i/2].max =
(data < 0 || data > MAX_NR_FREQ - 1)
? -1 :
mt_cpufreq_get_freq_by_idx(i / 2, data);
}
else { /* min */
freq_limit[i/2].min =
(data < 0 || data > MAX_NR_FREQ - 1)
? -1 :
mt_cpufreq_get_freq_by_idx(i / 2, data);
}
i++;
}
}
isBooting = 0;
for_each_perfmgr_clusters(cid)
if (freq_limit[cid].min != -1 || freq_limit[cid].max != -1) {
isBooting = 1;
#ifdef CONFIG_MTK_CORE_CTL
core_ctl_set_boost(1);
#endif
break;
}
#ifdef CONFIG_MTK_CORE_CTL
if (!isBooting)
core_ctl_set_boost(all_cpu_deisolated);
#endif
if (i < arg_num)
pr_debug("@%s: number of arguments < %d!\n",
__func__, arg_num);
else
update_userlimit_cpu_freq(CPU_KIR_BOOT,
perfmgr_clusters, freq_limit);
out:
free_page((unsigned long)buf);
kfree(freq_limit);
return cnt;
}
static int perfmgr_boot_freq_proc_show(struct seq_file *m, void *v)
{
int i;
for_each_perfmgr_clusters(i)
seq_printf(m, "cluster %d min:%d max:%d\n",
i, freq_set[CPU_KIR_BOOT][i].min,
freq_set[CPU_KIR_BOOT][i].max);
return 0;
}
/***************************************/
static int perfmgr_current_freq_proc_show(struct seq_file *m, void *v)
{
int i, j;
for_each_perfmgr_clusters(i)
seq_printf(m, "cluster %d min:%d max:%d\n",
i, current_freq[i].min, current_freq[i].max);
seq_puts(m, "===== kicker =====\n");
for (i = 0; i < CPU_MAX_KIR; i++)
for_each_perfmgr_clusters(j)
if (freq_set[i][j].min != -1 ||
freq_set[i][j].max != -1)
seq_printf(m,
"KIR[%d] cluster %d min:%d max:%d\n",
i, j, freq_set[i][j].min, freq_set[i][j].max);
return 0;
}
/*******************************************/
static ssize_t perfmgr_perfmgr_log_proc_write(struct file *filp,
const char __user *ubuf, size_t cnt, loff_t *pos)
{
int data = 0;
int rv = check_proc_write(&data, ubuf, cnt);
if (rv != 0)
return rv;
log_enable = data > 0 ? 1 : 0;
return cnt;
}
static int perfmgr_perfmgr_log_proc_show(struct seq_file *m, void *v)
{
if (m)
seq_printf(m, "%d\n", log_enable);
return 0;
}
void update_isolation_cpu(int kicker, int enable, int cpu)
{
int i, final = -1;
mutex_lock(&isolate_lock);
if (kicker < 0 || kicker >= CPU_ISO_MAX_KIR) {
pr_debug("kicker:%d, error\n", kicker);
mutex_unlock(&isolate_lock);
return;
}
if (cpu < 0 || cpu >= num_cpu) {
pr_debug("cpu:%d, error\n", cpu);
mutex_unlock(&isolate_lock);
return;
}
if (enable == cpu_isolation[kicker][cpu]) {
mutex_unlock(&isolate_lock);
return;
}
cpu_isolation[kicker][cpu] = enable;
for (i = 0; i < CPU_ISO_MAX_KIR; i++) {
if (cpu_isolation[i][cpu] == 0) {
final = 0;
break;
} else if (cpu_isolation[i][cpu] == 1)
final = 1;
}
#ifdef CONFIG_TRACING
perfmgr_trace_count(enable, "cpu_ctrl_isolation_%d_%d", kicker, cpu);
#endif
if (final > 0)
sched_isolate_cpu(cpu);
else
sched_unisolate_cpu(cpu);
mutex_unlock(&isolate_lock);
}
EXPORT_SYMBOL(update_isolation_cpu);
static ssize_t perfmgr_perfserv_iso_cpu_proc_write(struct file *filp,
const char __user *ubuf, size_t cnt, loff_t *pos)
{
int i, data = 0, cid;
int rv = check_proc_write(&data, ubuf, cnt);
if (rv != 0)
return rv;
perfserv_isolation_cpu = data;
cid = 0;
#ifdef CONFIG_MTK_CORE_CTL
isolation_used[CPU_ISO_KIR_PERF_ISO] = (data > 0) ? 1 : 0;
for_each_perfmgr_clusters(i) {
core_set[CPU_ISO_KIR_PERF_ISO][i].core_min = -1;
core_set[CPU_ISO_KIR_PERF_ISO][i].core_max =
default_core_set[i].core_max;
}
for (i = 0; i < num_cpu; i++) {
if ((perfserv_isolation_cpu & (1 << i)) > 0) {
core_set[CPU_ISO_KIR_PERF_ISO][cid].core_max--;
core_ctl_set_not_preferred(cid, i, 1);
} else {
core_ctl_set_not_preferred(cid, i, 0);
}
if (i+1 >= topo_ctrl_get_cluster_cpu_id(cid+1))
cid++;
}
for_each_perfmgr_clusters(i)
update_cpu_core_limit(CPU_ISO_KIR_PERF_ISO, i,
core_set[CPU_ISO_KIR_PERF_ISO][i].core_min,
core_set[CPU_ISO_KIR_PERF_ISO][i].core_max);
#else
for (i = 0; i < num_cpu; i++) {
if ((perfserv_isolation_cpu & (1 << i)) > 0)
update_isolation_cpu(CPU_ISO_KIR_PERF_ISO, 1, i);
else
update_isolation_cpu(CPU_ISO_KIR_PERF_ISO, -1, i);
}
#endif
return cnt;
}
static int perfmgr_perfserv_iso_cpu_proc_show(struct seq_file *m, void *v)
{
if (m)
seq_printf(m, "0x%x\n", perfserv_isolation_cpu);
return 0;
}
static ssize_t perfmgr_perfserv_core_proc_write(struct file *filp
, const char __user *ubuf, size_t cnt, loff_t *pos)
{
int i = 0, data, isDefault = 1;
unsigned int arg_num = perfmgr_clusters * 2; /* for min and max */
char *tok, *tmp;
char *buf = perfmgr_copy_from_user_for_proc(ubuf, cnt);
if (!buf) {
pr_debug("buf is null\n");
goto out1;
}
tmp = buf;
pr_debug("freq write_to_file\n");
while ((tok = strsep(&tmp, " ")) != NULL) {
if (i == arg_num) {
pr_debug(
"@%s: number of arguments > %d!\n",
__func__, arg_num);
goto out;
}
if (kstrtoint(tok, 10, &data)) {
pr_debug("@%s: Invalid input: %s\n",
__func__, tok);
goto out;
} else {
if (i % 2)
core_set[CPU_ISO_KIR_PERF_CORE][i/2].core_max = data;
else
core_set[CPU_ISO_KIR_PERF_CORE][i/2].core_min = data;
i++;
}
}
if (i < arg_num) {
pr_debug(
"@%s: number of arguments < %d!\n",
__func__, arg_num);
} else {
powerhal_tid = current->pid;
for_each_perfmgr_clusters(i) {
if (core_set[CPU_ISO_KIR_PERF_CORE][i].core_min != -1 ||
core_set[CPU_ISO_KIR_PERF_CORE][i].core_max != -1) {
isDefault = 0;
break;
}
}
isolation_used[CPU_ISO_KIR_PERF_CORE] = (isDefault) ? 0 : 1;
#ifdef CONFIG_MTK_CORE_CTL
for_each_perfmgr_clusters(i)
update_cpu_core_limit(CPU_ISO_KIR_PERF_CORE, i,
core_set[CPU_ISO_KIR_PERF_CORE][i].core_min,
core_set[CPU_ISO_KIR_PERF_CORE][i].core_max);
#endif
}
out:
free_page((unsigned long)buf);
out1:
return cnt;
}
static int perfmgr_perfserv_core_proc_show(struct seq_file *m, void *v)
{
int i;
for_each_perfmgr_clusters(i)
seq_printf(m, "cluster %d min:%d max:%d\n",
i, core_set[CPU_ISO_KIR_PERF_CORE][i].core_min,
core_set[CPU_ISO_KIR_PERF_CORE][i].core_max);
return 0;
}
/*******************************************/
static ssize_t perfmgr_perfserv_all_cpu_deisolated_proc_write
(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *pos)
{
int data = 0;
int rv = check_proc_write(&data, ubuf, cnt);
if (rv != 0)
return rv;
all_cpu_deisolated = (data > 0) ? 1 : 0;
#ifdef CONFIG_MTK_CORE_CTL
if (isBooting)
core_ctl_set_boost(1);
else
core_ctl_set_boost(all_cpu_deisolated);
#endif
return cnt;
}
static int perfmgr_perfserv_all_cpu_deisolated_proc_show
(struct seq_file *m, void *v)
{
if (m)
seq_printf(m, "%d\n", all_cpu_deisolated);
return 0;
}
PROC_FOPS_RW(perfserv_freq);
PROC_FOPS_RW(boot_freq);
PROC_FOPS_RO(current_freq);
PROC_FOPS_RW(perfmgr_log);
PROC_FOPS_RW(perfserv_iso_cpu);
PROC_FOPS_RW(perfserv_core);
PROC_FOPS_RW(perfserv_all_cpu_deisolated);
/************************************************/
int cpu_ctrl_init(struct proc_dir_entry *parent)
{
struct proc_dir_entry *boost_dir = NULL;
int i, j, ret = 0;
size_t idx;
struct pentry {
const char *name;
const struct file_operations *fops;
};
const struct pentry entries[] = {
PROC_ENTRY(perfserv_freq),
PROC_ENTRY(boot_freq),
PROC_ENTRY(current_freq),
PROC_ENTRY(perfmgr_log),
PROC_ENTRY(perfserv_iso_cpu),
PROC_ENTRY(perfserv_core),
PROC_ENTRY(perfserv_all_cpu_deisolated),
};
mutex_init(&boost_freq);
mutex_init(&isolate_lock);
boost_dir = proc_mkdir("cpu_ctrl", parent);
if (!boost_dir)
pr_debug("boost_dir null\n ");
/* create procfs */
for (idx = 0; idx < ARRAY_SIZE(entries); idx++) {
if (!proc_create(entries[idx].name, 0644,
boost_dir, entries[idx].fops)) {
pr_debug("%s(), create /cpu_ctrl%s failed\n",
__func__, entries[idx].name);
ret = -EINVAL;
goto out;
}
}
#ifdef MTK_K14_CPU_BOOST
perfserv_isolation_cpu = 0;
#endif
#ifdef CONFIG_MTK_CPU_CTRL_CFP
cfp_init_ret = cpu_ctrl_cfp_init(boost_dir);
#endif
current_freq = kcalloc(perfmgr_clusters, sizeof(struct ppm_limit_data),
GFP_KERNEL);
policy_mask = kcalloc(perfmgr_clusters, sizeof(unsigned long),
GFP_KERNEL);
for (i = 0; i < CPU_MAX_KIR; i++)
freq_set[i] = kcalloc(perfmgr_clusters
, sizeof(struct ppm_limit_data)
, GFP_KERNEL);
for_each_perfmgr_clusters(i) {
current_freq[i].min = -1;
current_freq[i].max = -1;
policy_mask[i] = 0;
}
for (i = 0; i < CPU_MAX_KIR; i++) {
for_each_perfmgr_clusters(j) {
freq_set[i][j].min = -1;
freq_set[i][j].max = -1;
}
}
num_cpu = num_possible_cpus();
for (i = 0; i < CPU_ISO_MAX_KIR; i++) {
cpu_isolation[i] = kcalloc(num_cpu, sizeof(int),
GFP_KERNEL);
for (j = 0; j < num_cpu; j++)
cpu_isolation[i][j] = -1;
isolation_used[i] = 0;
for_each_perfmgr_clusters(j) {
core_set[i][j].core_min = -1;
core_set[i][j].core_max = -1;
}
}
perfserv_isolation_cpu = 0;
all_cpu_deisolated = 0;
// sync with core_ctl
for_each_perfmgr_clusters(i) {
if (i == 0) {
default_core_set[i].core_min = 4;
default_core_set[i].core_max = 4;
} else if (i == 1) {
default_core_set[i].core_min = 2;
default_core_set[i].core_max = 3;
} else if (i == 2) {
default_core_set[i].core_min = 0;
default_core_set[i].core_max = 1;
}
}
isBooting = 1;
out:
return ret;
}
void cpu_ctrl_exit(void)
{
int i;
kfree(current_freq);
kfree(policy_mask);
for (i = 0; i < CPU_MAX_KIR; i++)
kfree(freq_set[i]);
for (i = 0; i < CPU_ISO_MAX_KIR; i++)
kfree(cpu_isolation[i]);
#ifdef CONFIG_MTK_CPU_CTRL_CFP
if (!cfp_init_ret)
cpu_ctrl_cfp_exit();
#endif
}
@@ -0,0 +1,492 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#define pr_fmt(fmt) "[cpu_ctrl_cfp]"fmt
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/cpumask.h>
#include <mt-plat/cpu_ctrl.h>
#include <mt-plat/mtk_ppm_api.h>
#include "cpu_ctrl.h"
#include "boost_ctrl.h"
#include "mtk_perfmgr_internal.h"
#include "load_track.h"
#ifdef CONFIG_TRACING
#include <linux/kallsyms.h>
#include <linux/trace_events.h>
#endif
#define MAX_NR_FREQ 16
/* Configurable */
static int __cfp_enable;
static int __cfp_polling_ms;
static int __cfp_up_opp;
static int __cfp_down_opp;
static int __cfp_up_time;
static int __cfp_down_time;
static int __cfp_up_loading;
static int __cfp_down_loading;
/* Non-Configurable */
static int cc_is_ceiled;
static struct ppm_limit_data *cc_freq, *cfp_freq;
static int cfp_curr_headroom_opp;
static int cfp_curr_up_time;
static int cfp_curr_down_time;
static int cfp_curr_loading;
static int **freq_tbl;
DEFINE_MUTEX(cfp_mlock);
static inline void cfp_lock(const char *tag)
{
mutex_lock(&cfp_mlock);
}
static inline void cfp_unlock(const char *tag)
{
mutex_unlock(&cfp_mlock);
}
static inline void cfp_lockprove(const char *tag)
{
WARN_ON(!mutex_is_locked(&cfp_mlock));
}
static int cfp_get_idx_by_freq(int clu_idx, int freq)
{
int opp_idx;
cfp_lockprove(__func__);
for (opp_idx = 0; opp_idx < MAX_NR_FREQ &&
freq <= freq_tbl[clu_idx][opp_idx]; opp_idx++)
;
return opp_idx >= 1 ? opp_idx - 1 : 0;
}
static void set_cfp_ppm(struct ppm_limit_data *desired_freq, int headroom_opp)
{
int clu_idx, cfp_ceiling_opp;
cfp_lockprove(__func__);
for_each_perfmgr_clusters(clu_idx) {
cfp_freq[clu_idx].min = desired_freq[clu_idx].min;
if (headroom_opp > 0) {
cfp_ceiling_opp =
MAX(cfp_get_idx_by_freq(clu_idx,
desired_freq[clu_idx].max)
- headroom_opp, 0);
cfp_freq[clu_idx].max =
freq_tbl[clu_idx][cfp_ceiling_opp];
} else {
cfp_freq[clu_idx].max = desired_freq[clu_idx].max;
}
#ifdef CONFIG_TRACING
perfmgr_trace_count(cfp_freq[clu_idx].min,
"cfp_min%d", clu_idx);
perfmgr_trace_count(cfp_freq[clu_idx].max,
"cfp_max%d", clu_idx);
#endif
}
#ifdef CONFIG_TRACING
perfmgr_trace_count(cc_is_ceiled, "cfp_ceiled");
#endif
mt_ppm_userlimit_cpu_freq(perfmgr_clusters, cfp_freq);
}
static void cfp_lt_callback(int mask_loading, int loading)
{
cfp_lock(__func__);
cfp_curr_loading = loading;
if (loading > __cfp_up_loading) {
cfp_curr_down_time = 0;
cfp_curr_up_time =
MIN(cfp_curr_up_time + 1, __cfp_up_time);
if (cfp_curr_up_time >= __cfp_up_time) {
cfp_curr_headroom_opp =
MIN(cfp_curr_headroom_opp + __cfp_up_opp,
MAX_NR_FREQ - 1);
set_cfp_ppm(cc_freq, cfp_curr_headroom_opp);
}
} else if (loading > __cfp_down_loading) {
cfp_curr_down_time = cfp_curr_up_time = 0;
} else {
cfp_curr_up_time = 0;
cfp_curr_down_time =
MIN(cfp_curr_down_time + 1, __cfp_down_time);
if (cfp_curr_down_time >= __cfp_down_time) {
cfp_curr_headroom_opp =
MAX(cfp_curr_headroom_opp - __cfp_down_opp, 0);
set_cfp_ppm(cc_freq, cfp_curr_headroom_opp);
}
}
#ifdef CONFIG_TRACING
perfmgr_trace_count(cfp_curr_loading, "cfp_loading");
perfmgr_trace_count(cfp_curr_headroom_opp, "cfp_headroom_opp");
perfmgr_trace_count(cfp_curr_up_time, "cfp_up_time");
perfmgr_trace_count(cfp_curr_down_time, "cfp_down_time");
#endif
cfp_unlock(__func__);
}
static void start_cfp(void)
{
int reg_ret;
int poll_ms;
cfp_lockprove(__func__);
cc_is_ceiled = 1;
poll_ms = __cfp_polling_ms;
pr_debug("%s\n", __func__);
cfp_unlock(__func__);
reg_ret = reg_loading_tracking(cfp_lt_callback, poll_ms, cpu_possible_mask);
if (reg_ret)
pr_debug("%s reg_ret=%d\n", __func__, reg_ret);
cfp_lock(__func__);
}
static void stop_cfp(void)
{
int unreg_ret;
cfp_lockprove(__func__);
cfp_curr_headroom_opp = 0;
cfp_curr_up_time = 0;
cfp_curr_down_time = 0;
cfp_curr_loading = 0;
cc_is_ceiled = 0;
pr_debug("%s\n", __func__);
cfp_unlock(__func__);
unreg_ret = unreg_loading_tracking(cfp_lt_callback);
if (unreg_ret)
pr_debug("%s unreg_ret=%d\n", __func__, unreg_ret);
cfp_lock(__func__);
}
static void restart_cfp(void)
{
pr_debug("%s\n", __func__);
stop_cfp();
start_cfp();
}
static int cfp_check_ceiled(struct ppm_limit_data *freq)
{
int clu_idx;
int ret = 0;
cfp_lockprove(__func__);
for_each_perfmgr_clusters(clu_idx) {
if (freq[clu_idx].max != -1 &&
/* FPSGO jerk max is max freq not -1.
* cfp treated as ceiled to avoid ping-pong
*/
freq[clu_idx].max <= freq_tbl[clu_idx][0]) {
ret = 1;
break;
}
}
return ret;
}
void cpu_ctrl_cfp(struct ppm_limit_data *desired_freq)
{
int v_cc_is_ceiled;
cfp_lock(__func__);
memcpy(cc_freq, desired_freq,
perfmgr_clusters * sizeof(struct ppm_limit_data));
if (!__cfp_enable) {
set_cfp_ppm(desired_freq, cfp_curr_headroom_opp);
goto out_cpu_ctrl_cfp;
}
v_cc_is_ceiled = cfp_check_ceiled(desired_freq);
if (cc_is_ceiled && !v_cc_is_ceiled)
stop_cfp();
else if (!cc_is_ceiled && v_cc_is_ceiled)
start_cfp();
set_cfp_ppm(desired_freq, cfp_curr_headroom_opp);
out_cpu_ctrl_cfp:
cfp_unlock(__func__);
}
static int set_cfp_enable(int val)
{
int ret = 0;
cfp_lock(__func__);
if (__cfp_enable == !!val) {
ret = -EINVAL;
goto out;
}
__cfp_enable = !!val;
if (cfp_check_ceiled(cc_freq)) {
if (__cfp_enable)
start_cfp();
else
stop_cfp();
}
out:
cfp_unlock(__func__);
return ret;
}
static int perfmgr_cfp_curr_stat_proc_show(struct seq_file *m, void *v)
{
cfp_lock(__func__);
if (m) {
seq_printf(m,
"enable\tceiled\tloading\theadroom_opp\tup_time\tdown_time\n");
seq_printf(m, "%d\t%d\t%d\t%d\t\t%d\t%d\n",
__cfp_enable, cc_is_ceiled,
cfp_curr_loading, cfp_curr_headroom_opp,
cfp_curr_up_time, cfp_curr_down_time);
}
cfp_unlock(__func__);
return 0;
}
#define SET_CFP(name, lb, ub) \
static int set_cfp_##name(int val) \
{ \
int ret = 0; \
\
cfp_lock(__func__); \
if (__cfp_##name == val || val < (lb) || val > (ub)) { \
ret = -EINVAL; \
goto out; \
} \
\
__cfp_##name = val; \
\
if (cc_is_ceiled) \
restart_cfp(); \
\
out: \
cfp_unlock(__func__); \
return ret; \
\
}
#define GET_CFP(name) \
static int get_cfp_##name(void) \
{ \
int ret; \
\
cfp_lock(__func__); \
ret = __cfp_##name; \
cfp_unlock(__func__); \
\
return ret; \
}
#define CFP_WRITE(name) \
static ssize_t perfmgr_cfp_##name##_proc_write(struct file *filp, \
const char __user *ubuf, size_t cnt, loff_t *pos) \
{ \
int data = 0; \
\
int rv = check_proc_write(&data, ubuf, cnt); \
\
if (rv != 0) \
return rv; \
\
if (set_cfp_##name(data)) \
return -EINVAL; \
\
return cnt; \
}
#define CFP_SHOW(name) \
static int perfmgr_cfp_##name##_proc_show(struct seq_file *m, void *v) \
{ \
if (m) \
seq_printf(m, "%d\n", get_cfp_##name()); \
return 0; \
}
SET_CFP(polling_ms, 1, INT_MAX);
SET_CFP(up_opp, 0, MAX_NR_FREQ - 1);
SET_CFP(down_opp, 0, MAX_NR_FREQ - 1);
SET_CFP(up_time, 1, INT_MAX);
SET_CFP(down_time, 1, INT_MAX);
SET_CFP(up_loading, __cfp_down_loading, 100);
SET_CFP(down_loading, 0, __cfp_up_loading);
GET_CFP(enable);
GET_CFP(polling_ms);
GET_CFP(up_opp);
GET_CFP(down_opp);
GET_CFP(up_time);
GET_CFP(down_time);
GET_CFP(up_loading);
GET_CFP(down_loading);
CFP_WRITE(enable);
CFP_WRITE(polling_ms);
CFP_WRITE(up_opp);
CFP_WRITE(down_opp);
CFP_WRITE(up_time);
CFP_WRITE(down_time);
CFP_WRITE(up_loading);
CFP_WRITE(down_loading);
CFP_SHOW(enable);
CFP_SHOW(polling_ms);
CFP_SHOW(up_opp);
CFP_SHOW(down_opp);
CFP_SHOW(up_time);
CFP_SHOW(down_time);
CFP_SHOW(up_loading);
CFP_SHOW(down_loading);
PROC_FOPS_RW(cfp_enable);
PROC_FOPS_RW(cfp_polling_ms);
PROC_FOPS_RW(cfp_up_opp);
PROC_FOPS_RW(cfp_down_opp);
PROC_FOPS_RW(cfp_up_time);
PROC_FOPS_RW(cfp_down_time);
PROC_FOPS_RW(cfp_up_loading);
PROC_FOPS_RW(cfp_down_loading);
PROC_FOPS_RO(cfp_curr_stat);
int cpu_ctrl_cfp_init(struct proc_dir_entry *parent)
{
int i;
int clu_idx, opp_idx;
int ret = 0;
size_t idx;
struct pentry {
const char *name;
const struct file_operations *fops;
};
const struct pentry entries[] = {
PROC_ENTRY(cfp_enable),
PROC_ENTRY(cfp_polling_ms),
PROC_ENTRY(cfp_up_opp),
PROC_ENTRY(cfp_down_opp),
PROC_ENTRY(cfp_up_time),
PROC_ENTRY(cfp_down_time),
PROC_ENTRY(cfp_up_loading),
PROC_ENTRY(cfp_down_loading),
PROC_ENTRY(cfp_curr_stat),
};
for (idx = 0; idx < ARRAY_SIZE(entries); idx++) {
if (!proc_create(entries[idx].name, 0644,
parent, entries[idx].fops)) {
pr_debug("%s(), create /cpu_ctrl%s failed\n",
__func__, entries[idx].name);
ret = -EINVAL;
goto out_err;
}
}
cc_freq = kcalloc(perfmgr_clusters,
sizeof(struct ppm_limit_data), GFP_KERNEL);
if (!cc_freq) {
ret = -ENOMEM;
goto out_err;
}
cfp_freq = kcalloc(perfmgr_clusters,
sizeof(struct ppm_limit_data), GFP_KERNEL);
if (!cfp_freq) {
ret = -ENOMEM;
goto out_cfp_freq_alloc_err;
}
freq_tbl = kcalloc(perfmgr_clusters,
sizeof(int *), GFP_KERNEL);
if (!freq_tbl) {
ret = -ENOMEM;
goto out_freq_tbl_alloc_err;
}
for_each_perfmgr_clusters(clu_idx) {
freq_tbl[clu_idx] = kcalloc(MAX_NR_FREQ,
sizeof(int), GFP_KERNEL);
if (!freq_tbl[clu_idx]) {
ret = -ENOMEM;
goto out_freq_tbl_opp_alloc_err;
}
for (opp_idx = 0; opp_idx < MAX_NR_FREQ; opp_idx++)
freq_tbl[clu_idx][opp_idx] =
mt_cpufreq_get_freq_by_idx(clu_idx, opp_idx);
}
__cfp_enable = 1;
__cfp_polling_ms = 64;
__cfp_up_opp = 15;
__cfp_down_opp = 15;
__cfp_up_time = 1;
__cfp_down_time = 16;
__cfp_up_loading = 90;
__cfp_down_loading = 80;
return ret;
out_freq_tbl_opp_alloc_err:
for (i = 0; i < clu_idx; i++)
kfree(freq_tbl[i]);
out_freq_tbl_alloc_err:
kfree(freq_tbl);
out_cfp_freq_alloc_err:
kfree(cc_freq);
out_err:
return ret;
}
void cpu_ctrl_cfp_exit(void)
{
int clu_idx;
stop_cfp();
kfree(cc_freq);
kfree(cfp_freq);
for_each_perfmgr_clusters(clu_idx)
kfree(freq_tbl[clu_idx]);
kfree(freq_tbl);
}
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include <linux/module.h>
#include <mt-plat/cpu_ctrl.h>
#include <linux/proc_fs.h>
int powerhal_tid;
/*******************************************/
int update_userlimit_cpu_freq(int kicker, int num_cluster
, struct cpu_ctrl_data *freq_limit)
{
return 0;
}
EXPORT_SYMBOL(update_userlimit_cpu_freq);
int cpu_ctrl_init(struct proc_dir_entry *parent)
{
struct proc_dir_entry *boost_dir = NULL;
boost_dir = proc_mkdir("cpu_ctrl_dummy", parent);
if (!boost_dir)
pr_debug("boost_dir null\n ");
return 0;
}
@@ -0,0 +1,75 @@
#
# Copyright (C) 2018 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 the
# GNU General Public License for more details.
#
#DRAM_CONTROLLER
ifneq (,$(filter $(CONFIG_MTK_PLATFORM), "mt6739" "mt6763"))
ccflags-y += \
-DVCORE_DVFS_OPP_SUPPORT
else
ccflags-y += \
-DMTK_QOS_SUPPORT
ifneq (,$(filter $(CONFIG_MTK_PLATFORM), "mt6771"))
ccflags-y += \
-DMTK_QOS_EMI_OPP
endif # ifneq (,$(filter $(CONFIG_MTK_PLATFORM), "mt6771"))
endif # ifneq (,$(filter $(CONFIG_MTK_PLATFORM), "mt6739" "mt6763"))
ifeq ($(CONFIG_MACH_MT6893),y)
ccflags-y += \
-DMTK_K14_DRM_BOOST
else ifeq ($(CONFIG_MACH_MT6885),y)
ccflags-y += \
-DMTK_K14_DRM_BOOST
else ifeq ($(CONFIG_MACH_MT6877),y)
ccflags-y += \
-DMTK_K14_DRM_BOOST
else ifeq ($(CONFIG_MACH_MT6873),y)
ccflags-y += \
-DMTK_K14_DRM_BOOST
else ifeq ($(CONFIG_MACH_MT6853),y)
ccflags-y += \
-DMTK_K14_DRM_BOOST
else ifeq ($(CONFIG_MACH_MT6781),y)
ccflags-y += \
-DMTK_K14_DRM_BOOST
else ifeq ($(CONFIG_MACH_MT6739),y)
ccflags-y += \
-DMTK_K14_DRM_BOOST
else ifeq ($(CONFIG_MACH_MT6833),y)
ccflags-y += \
-DMTK_K14_DRM_BOOST
else ifeq ($(CONFIG_MACH_MT6768),y)
ccflags-y += \
-DMTK_K14_DRM_BOOST
else ifeq ($(CONFIG_MACH_MT6771),y)
ccflags-y += \
-DMTK_K14_DRM_BOOST
else ifeq ($(CONFIG_MACH_MT6785),y)
ccflags-y += \
-DMTK_K14_DRM_BOOST
endif
obj-y += dram_ctrl.o
ccflags-y += -I$(srctree)/drivers/misc/mediatek/base/power/include/
ccflags-y += -I$(srctree)/drivers/misc/mediatek/base/power/$(MTK_PLATFORM)/
ccflags-y += -I$(srctree)/drivers/misc/mediatek/dramc/$(MTK_PLATFORM)/
ccflags-y += -I$(srctree)/include/memory/mediatek/
#if PM_DEVFREQ
ccflags-y += -I$(srctree)/drivers/devfreq/
#endif # PM_DEVFREQ
@@ -0,0 +1,548 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_opp.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
#include <linux/soc/mediatek/mtk_dvfsrc.h>
#if !defined(CONFIG_MACH_MT6771)
#include <linux/soc/mediatek/mtk-pm-qos.h>
#endif
#ifdef MTK_K14_DRM_BOOST
#if defined(MTK_QOS_SUPPORT)
#include <linux/pm_qos.h>
#include <helio-dvfsrc-opp.h>
#if defined(CONFIG_MACH_MT6771)
#define MTK_PM_QOS_DDR_OPP_DEFAULT_VALUE PM_QOS_DDR_OPP_DEFAULT_VALUE
#define MTK_PM_QOS_DDR_OPP PM_QOS_DDR_OPP
#endif
#endif
#if defined(CONFIG_MTK_DRAMC)
#include "mtk_dramc.h"
#endif
#if defined(VCORE_DVFS_OPP_SUPPORT)
#include <mtk_vcorefs_governor.h>
#include <mtk_vcorefs_manager.h>
#endif
#include "mtk_perfmgr_internal.h"
#include "boost_ctrl.h"
#ifdef CONFIG_MEDIATEK_DRAMC
#include <dramc.h>
#endif
static int ddr_type;
char qos_has_dts_support;
#ifdef MTK_QOS_SUPPORT
/* QoS Method */
static int ddr_now;
static int ddr_lp5_now;
static int ddr_lp5_hfr_now;
static struct mtk_pm_qos_request emi_request;
static struct mtk_pm_qos_request emi_request_lp5;
static struct mtk_pm_qos_request emi_request_lp5_hfr;
static int emi_opp;
static int dfps;
static int hfr_fps;
#endif
#ifdef VCORE_DVFS_OPP_SUPPORT
static int vcore_now;
#endif
#endif
struct mtk_dram_ctrl {
struct device *dev;
struct proc_dir_entry *proc_dir;
int num_perf;
int *perfs;
int curr_opp;
int qos_ctrl;
};
struct proc_dir_entry *dram_proc_parent;
static struct mtk_pm_qos_request ddr_request;
void dram_ctl_update_dfrc_fps(int fps)
{
#ifdef MTK_K14_DRM_BOOST
#ifdef MTK_QOS_SUPPORT
if (fps == dfps || fps <= 0)
return;
dfps = fps;
#ifdef CONFIG_MEDIATEK_DRAMC
if (ddr_lp5_now == -1 && ddr_lp5_hfr_now == -1)
return;
if (mtk_dramc_get_ddr_type() != TYPE_LPDDR5)
return;
if (ddr_lp5_now != -1 && dfps <= hfr_fps)
mtk_pm_qos_update_request(&emi_request_lp5, ddr_lp5_now);
else if (ddr_lp5_hfr_now != -1 && dfps > hfr_fps)
mtk_pm_qos_update_request(&emi_request_lp5_hfr, ddr_lp5_hfr_now);
else if (ddr_lp5_now != -1)
mtk_pm_qos_update_request(&emi_request_lp5, -1);
else
mtk_pm_qos_update_request(&emi_request_lp5_hfr, -1);
#endif
#endif
#endif
}
static ssize_t ddr_ctrl_proc_write(struct file *filp, const char *ubuf,
size_t cnt, loff_t *data)
{
struct mtk_dram_ctrl *dram_ctrl = PDE_DATA(file_inode(filp));
char buf[64];
int val;
int ret;
if (cnt >= sizeof(buf)) {
pr_debug("ddr_write cnt >= sizeof\n");
return -EINVAL;
}
if (copy_from_user(buf, ubuf, cnt)) {
pr_debug("ddr_write copy_from_user\n");
return -EFAULT;
}
buf[cnt] = 0;
ret = kstrtoint(buf, 10, &val);
if (ret < 0) {
pr_debug("ddr_write ret < 0\n");
return ret;
}
if (dram_ctrl->qos_ctrl) {
if ((val > -1) && (val < dram_ctrl->num_perf))
mtk_pm_qos_update_request(&ddr_request,
dram_ctrl->perfs[val]);
else
mtk_pm_qos_update_request(&ddr_request,
MTK_PM_QOS_DDR_OPP_DEFAULT_VALUE);
} else {
if ((val > -1) && (val < dram_ctrl->num_perf))
dev_pm_genpd_set_performance_state(
dram_ctrl->dev,
dram_ctrl->perfs[val]);
else
dev_pm_genpd_set_performance_state(
dram_ctrl->dev, 0);
}
dram_ctrl->curr_opp = val;
return cnt;
}
static int ddr_ctrl_proc_show(struct seq_file *m, void *v)
{
struct mtk_dram_ctrl *dram_ctrl = m->private;
seq_printf(m, "%d\n", dram_ctrl->curr_opp);
return 0;
}
static int ddr_ctrl_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, ddr_ctrl_proc_show, PDE_DATA(inode));
}
static const struct file_operations ddr_ctrl_proc_fops = {
.owner = THIS_MODULE,
.open = ddr_ctrl_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.write = ddr_ctrl_proc_write,
};
static int mtk_dram_ctrl_probe(struct platform_device *pdev)
{
struct mtk_dram_ctrl *dram_ctrl;
struct device *dev = &pdev->dev;
struct device_node *node = pdev->dev.of_node;
int i;
dram_ctrl = devm_kzalloc(dev, sizeof(*dram_ctrl), GFP_KERNEL);
if (!dram_ctrl)
return -ENOMEM;
dram_ctrl->num_perf = of_count_phandle_with_args(node,
"required-opps", NULL);
if (dram_ctrl->num_perf > 0) {
dram_ctrl->perfs = devm_kzalloc(&pdev->dev,
dram_ctrl->num_perf * sizeof(int),
GFP_KERNEL);
if (!dram_ctrl->perfs)
return -ENOMEM;
for (i = 0; i < dram_ctrl->num_perf; i++) {
dram_ctrl->perfs[i] =
dvfsrc_get_required_opp_performance_state(node, i);
}
} else
dram_ctrl->num_perf = 0;
if (of_device_is_compatible(node, "mediatek,dram-qosctrl")) {
mtk_pm_qos_add_request(&ddr_request, MTK_PM_QOS_DDR_OPP,
MTK_PM_QOS_DDR_OPP_DEFAULT_VALUE);
dram_ctrl->qos_ctrl = 1;
}
dram_ctrl->curr_opp = dram_ctrl->num_perf;
dram_ctrl->dev = dev;
platform_set_drvdata(pdev, dram_ctrl);
dram_ctrl->proc_dir = proc_mkdir("dram_ctrl", dram_proc_parent);
if (!dram_ctrl->proc_dir) {
pr_debug("drams_dir not create success\n");
return -ENOMEM;
}
proc_create_data("ddr", 0644,
dram_ctrl->proc_dir, &ddr_ctrl_proc_fops, dram_ctrl);
#ifdef MTK_K14_DRM_BOOST
qos_has_dts_support = 1;
#endif
return 0;
}
static int mtk_dram_ctrl_remove(struct platform_device *pdev)
{
return 0;
}
static const struct of_device_id mtk_dram_ctrl_of_match[] = {
{
.compatible = "mediatek,dram-ctrl",
}, {
.compatible = "mediatek,dram-qosctrl",
}, {
/* sentinel */
},
};
static struct platform_driver mtk_dram_ctrl_driver = {
.probe = mtk_dram_ctrl_probe,
.remove = mtk_dram_ctrl_remove,
.driver = {
.name = "mtk-dram_ctrl",
.of_match_table = of_match_ptr(mtk_dram_ctrl_of_match),
},
};
#ifdef MTK_K14_DRM_BOOST
#ifdef MTK_QOS_SUPPORT
static ssize_t perfmgr_ddr_lp5_hfr_proc_write(struct file *filp,
const char *ubuf, size_t cnt, loff_t *data)
{
char buf[64];
int val;
int ret;
if (cnt >= sizeof(buf)) {
pr_debug("ddr_write cnt >= sizeof\n");
return -EINVAL;
}
if (copy_from_user(buf, ubuf, cnt)) {
pr_debug("ddr_write copy_from_user\n");
return -EFAULT;
}
buf[cnt] = 0;
ret = kstrtoint(buf, 10, &val);
if (ret < 0) {
pr_debug("ddr_write ret < 0\n");
return ret;
}
if (val < -1 || val > emi_opp) {
pr_debug("UNREQ\n");
return -1;
}
ddr_lp5_hfr_now = val;
#ifdef CONFIG_MEDIATEK_DRAMC
if (mtk_dramc_get_ddr_type() == TYPE_LPDDR5
&& dfps > hfr_fps)
mtk_pm_qos_update_request(&emi_request_lp5_hfr, val);
#endif
return cnt;
}
static int perfmgr_ddr_lp5_hfr_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "%d\n", ddr_lp5_hfr_now);
return 0;
}
PROC_FOPS_RW(ddr_lp5_hfr);
static ssize_t perfmgr_ddr_lp5_proc_write(struct file *filp, const char *ubuf,
size_t cnt, loff_t *data)
{
char buf[64];
int val;
int ret;
if (cnt >= sizeof(buf)) {
pr_debug("ddr_write cnt >= sizeof\n");
return -EINVAL;
}
if (copy_from_user(buf, ubuf, cnt)) {
pr_debug("ddr_write copy_from_user\n");
return -EFAULT;
}
buf[cnt] = 0;
ret = kstrtoint(buf, 10, &val);
if (ret < 0) {
pr_debug("ddr_write ret < 0\n");
return ret;
}
if (val < -1 || val > emi_opp) {
pr_debug("UNREQ\n");
return -1;
}
ddr_lp5_now = val;
#ifdef CONFIG_MEDIATEK_DRAMC
if (mtk_dramc_get_ddr_type() == TYPE_LPDDR5
&& dfps <= hfr_fps)
mtk_pm_qos_update_request(&emi_request_lp5, val);
#endif
return cnt;
}
static int perfmgr_ddr_lp5_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "%d\n", ddr_lp5_now);
return 0;
}
PROC_FOPS_RW(ddr_lp5);
static ssize_t perfmgr_ddr_proc_write(struct file *filp, const char *ubuf,
size_t cnt, loff_t *data)
{
char buf[64];
int val;
int ret;
if (cnt >= sizeof(buf)) {
pr_debug("ddr_write cnt >= sizeof\n");
return -EINVAL;
}
if (copy_from_user(buf, ubuf, cnt)) {
pr_debug("ddr_write copy_from_user\n");
return -EFAULT;
}
buf[cnt] = 0;
ret = kstrtoint(buf, 10, &val);
if (ret < 0) {
pr_debug("ddr_write ret < 0\n");
return ret;
}
if (val < -1 || val > emi_opp) {
pr_debug("UNREQ\n");
return -1;
}
mtk_pm_qos_update_request(&emi_request, val);
ddr_now = val;
return cnt;
}
static int perfmgr_ddr_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "%d\n", ddr_now);
return 0;
}
PROC_FOPS_RW(ddr);
#endif
#ifdef MTK_K14_DRM_BOOST
#ifdef VCORE_DVFS_OPP_SUPPORT
static ssize_t perfmgr_vcore_proc_write(struct file *filp, const char *ubuf,
size_t cnt, loff_t *data)
{
char buf[64];
int val;
int ret;
if (cnt >= sizeof(buf)) {
pr_debug("vcore_write cnt >= sizeof\n");
return -EINVAL;
}
if (copy_from_user(buf, ubuf, cnt)) {
pr_debug("vcore_write copy_from_user\n");
return -EFAULT;
}
buf[cnt] = 0;
ret = kstrtoint(buf, 10, &val);
if (ret < 0) {
pr_debug("vcore_write ret < 0\n");
return ret;
}
if (val < -1 || val > 4) {
pr_debug("UNREQ\n");
return -1;
}
ret = vcorefs_request_dvfs_opp(KIR_PERF, val);
if (ret == 0)
vcore_now = val;
return cnt;
}
static int perfmgr_vcore_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "%d\n", vcore_now);
return 0;
}
PROC_FOPS_RW(vcore);
#endif
#endif
static int perfmgr_dram_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "DDR_TYPE: %d\n", ddr_type);
return 0;
}
PROC_FOPS_RO(dram);
int dram_ctrl_init_with_no_dts_support(struct proc_dir_entry *parent)
{
int ret = 0;
size_t i;
#ifdef MTK_QOS_SUPPORT
char owner[20] = "dram_ctrl_lp5";
char owner_hfr[20] = "dram_ctrl_lp5_hfr";
#endif
struct proc_dir_entry *drams_dir;
struct pentry {
const char *name;
const struct file_operations *fops;
};
const struct pentry entries[] = {
PROC_ENTRY(dram),
#ifdef MTK_QOS_SUPPORT
PROC_ENTRY(ddr),
PROC_ENTRY(ddr_lp5),
PROC_ENTRY(ddr_lp5_hfr),
#endif
#ifdef VCORE_DVFS_OPP_SUPPORT
PROC_ENTRY(vcore),
#endif
};
pr_debug("init dram driver start\n");
drams_dir = proc_mkdir("dram_ctrl", parent);
if (!drams_dir) {
pr_debug("drams_dir not create success\n");
return -ENOMEM;
}
/* create procfs */
for (i = 0; i < ARRAY_SIZE(entries); i++) {
if (!proc_create(entries[i].name, 0644,
drams_dir, entries[i].fops)) {
pr_debug("%s(), create /dram_ctrl%s failed\n",
__func__, entries[i].name);
ret = -EINVAL;
goto out;
}
}
#ifdef MTK_QOS_SUPPORT
/* QoS Method */
hfr_fps = 66;
ddr_now = -1;
ddr_lp5_now = -1;
ddr_lp5_hfr_now = -1;
if (!mtk_pm_qos_request_active(&emi_request) ||
!mtk_pm_qos_request_active(&emi_request_lp5) ||
!mtk_pm_qos_request_active(&emi_request_lp5_hfr)) {
pr_debug("hh: emi pm_qos_add_request\n");
mtk_pm_qos_add_request(&emi_request, MTK_PM_QOS_DDR_OPP,
MTK_PM_QOS_DDR_OPP_DEFAULT_VALUE);
mtk_pm_qos_add_request(&emi_request_lp5, MTK_PM_QOS_DDR_OPP,
MTK_PM_QOS_DDR_OPP_DEFAULT_VALUE);
strncpy(emi_request_lp5.owner, owner,
sizeof(emi_request_lp5.owner) - 1);
mtk_pm_qos_add_request(&emi_request_lp5_hfr, MTK_PM_QOS_DDR_OPP,
MTK_PM_QOS_DDR_OPP_DEFAULT_VALUE);
strncpy(emi_request_lp5_hfr.owner, owner_hfr,
sizeof(emi_request_lp5_hfr.owner) - 1);
} else {
pr_debug("hh: emi pm_qos already request\n");
}
emi_opp = DDR_OPP_NUM - 1;
#endif
#ifdef VCORE_DVFS_OPP_SUPPORT
vcore_now = -1;
#endif
#ifdef CONFIG_MEDIATEK_DRAMC
ddr_type = mtk_dramc_get_ddr_type();
#else
ddr_type = -1;
#endif
pr_debug("init dram driver done\n");
out:
return ret;
}
#endif
int dram_ctrl_init(struct proc_dir_entry *parent)
{
int ret = 0;
dram_proc_parent = parent;
ret = platform_driver_register(&mtk_dram_ctrl_driver);
#ifdef MTK_K14_DRM_BOOST
if (!qos_has_dts_support)
dram_ctrl_init_with_no_dts_support(parent);
#endif
return ret;
}
void dram_ctrl_exit(void)
{
platform_driver_unregister(&mtk_dram_ctrl_driver);
}
@@ -0,0 +1,58 @@
#
# Copyright (C) 2018 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 the
# GNU General Public License for more details.
#
#EAS_CONTROLLER
MTK_TOP = $(srctree)/drivers/misc/mediatek/
ccflags-y += \
-I$(MTK_TOP)/base/power/include/ \
-I$(MTK_TOP)/base/power/$(MTK_PLATFORM)/ \
-I$(MTK_TOP)/dramc/$(MTK_PLATFORM)/ \
-I$(srctree)/drivers/misc/mediatek/performance/boost_ctrl/include/ \
-I$(srctree)/drivers/misc/mediatek/include/mt-plat/
ifeq ($(CONFIG_MACH_MT6893),y)
ccflags-y += \
-DMTK_K14_EAS_BOOST
else ifeq ($(CONFIG_MACH_MT6885),y)
ccflags-y += \
-DMTK_K14_EAS_BOOST
else ifeq ($(CONFIG_MACH_MT6877),y)
ccflags-y += \
-DMTK_K14_EAS_BOOST
else ifeq ($(CONFIG_MACH_MT6781),y)
ccflags-y += \
-DMTK_K14_EAS_BOOST
else ifeq ($(CONFIG_MACH_MT6739),y)
ccflags-y += \
-DMTK_K14_EAS_BOOST
else ifeq ($(CONFIG_MACH_MT6833),y)
ccflags-y += \
-DMTK_K14_EAS_BOOST
else ifeq ($(CONFIG_MACH_MT6768),y)
ccflags-y += \
-DMTK_K14_EAS_BOOST
else ifeq ($(CONFIG_MACH_MT6853),y)
ccflags-y += \
-DMTK_K14_EAS_BOOST
else ifeq ($(CONFIG_MACH_MT6873),y)
ccflags-y += \
-DMTK_K14_EAS_BOOST
else ifeq ($(CONFIG_MACH_MT6771),y)
ccflags-y += \
-DMTK_K14_EAS_BOOST
else ifeq ($(CONFIG_MACH_MT6785),y)
ccflags-y += \
-DMTK_K14_EAS_BOOST
endif
obj-y += eas_ctrl.o uclamp_ctrl.o
@@ -0,0 +1,854 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#define pr_fmt(fmt) "[eas_ctrl]"fmt
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include "boost_ctrl.h"
#include "eas_ctrl_plat.h"
#include <mt-plat/eas_ctrl.h>
#include "mtk_perfmgr_internal.h"
//#include <mt-plat/mtk_sched.h>
#include <linux/sched.h>
#ifdef CONFIG_TRACING
#include <linux/kallsyms.h>
#include <linux/trace_events.h>
#endif
/* boost value */
static struct mutex boost_eas;
static bool perf_sched_big_task_rotation;
static pid_t last_cpu_prefer_pid;
static int last_cpu_perfer_type;
#ifdef MTK_K14_EAS_BOOST
#include "eas_ctrl.h"
#define SCHED_API_READY 0
#define MAX_BOOST_VALUE (100)
#define MIN_BOOST_VALUE (-100)
#define MAX_UCLAMP_VALUE (100)
#define MIN_UCLAMP_VALUE (0)
#define MIN_DEBUG_UCLAMP_VALUE (-1)
static int uclamp_min[NR_CGROUP][EAS_UCLAMP_MAX_KIR];
static int boost_value[NR_CGROUP][EAS_MAX_KIR];
static unsigned long prefer_idle[NR_CGROUP];
static int perf_sched_stune_task_thresh;
static int debug_fix_boost;
static int debug_boost_value[NR_CGROUP];
/* log */
static int log_enable;
#ifdef CONFIG_SCHED_TUNE
static int current_boost_value[NR_CGROUP];
static unsigned long policy_mask[NR_CGROUP];
#endif
#endif
/************************/
/************************/
/********************************************************************/
/* Add procfs to control sysctl_sched_rotation_enable */
/* sysctl_sched_rotation_enable: eas_ctrl_plat.h */
static ssize_t perfmgr_sched_big_task_rotation_proc_write(struct file *filp,
const char *ubuf, size_t cnt, loff_t *pos)
{
int data = 0;
int rv = check_proc_write(&data, ubuf, cnt);
if (rv != 0)
return rv;
perf_sched_big_task_rotation = data;
#ifdef CONFIG_MTK_SCHED_BIG_TASK_MIGRATE
if (data)
set_sched_rotation_enable(true);
else
set_sched_rotation_enable(false);
#endif
return cnt;
}
static int perfmgr_sched_big_task_rotation_proc_show(struct seq_file *m,
void *v)
{
seq_printf(m, "%d\n", perf_sched_big_task_rotation);
return 0;
}
/* Add procfs to control sched_boost */
/* set_sched_boost_type: eas_ctrl_plat.h */
static ssize_t perfmgr_sched_boost_proc_write(struct file *filp,
const char *ubuf, size_t cnt, loff_t *pos)
{
int data = 0;
int rv = check_proc_write(&data, ubuf, cnt);
if (rv != 0)
return rv;
if (data < 0 || data > 2)
return -EINVAL;
#if defined(CONFIG_CGROUPS) && defined(CONFIG_MTK_SCHED_CPU_PREFER)
if (set_sched_boost_type(data) < 0)
return -EINVAL;
#endif
return cnt;
}
static int perfmgr_sched_boost_proc_show(struct seq_file *m, void *v)
{
int boost_type = 0;
#if defined(CONFIG_CGROUPS) && defined(CONFIG_MTK_SCHED_CPU_PREFER)
boost_type = get_sched_boost_type();
#endif
seq_printf(m, "sched_boost = %d ", boost_type);
if (boost_type == 0)
seq_puts(m, "(no boost)\n");
else if (boost_type == 1)
seq_puts(m, "(all boost)\n");
else if (boost_type == 2)
seq_puts(m, "(foreground boost)\n");
else
seq_puts(m, "(invalid setting)\n");
return 0;
}
/* Add procfs to control cpu_prefer */
/* set_sched_boost_type: eas_ctrl_plat.h */
static ssize_t perfmgr_cpu_prefer_proc_write(struct file *filp,
const char *ubuf, size_t cnt, loff_t *pos)
{
char buf[64];
pid_t pid, type;
if (cnt >= sizeof(buf))
return -EINVAL;
if (copy_from_user(buf, ubuf, cnt))
return -EFAULT;
buf[cnt] = '\0';
if (sscanf(buf, "%d %d", (int *)&pid, &type) != 2)
return -EFAULT;
#ifdef CONFIG_MTK_SCHED_CPU_PREFER
if (sched_set_cpuprefer(pid, type) != 0)
return -EINVAL;
#endif
last_cpu_prefer_pid = pid;
last_cpu_perfer_type = type;
return cnt;
}
static int perfmgr_cpu_prefer_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "last pid:%d, type:%d\n",
(int)last_cpu_prefer_pid, last_cpu_perfer_type);
return 0;
}
static int perfmgr_set_sched_isolation_proc_show(struct seq_file *m, void *v)
{
seq_puts(m, "");
return 0;
}
static ssize_t perfmgr_set_sched_isolation_proc_write(struct file *filp,
const char *ubuf, size_t cnt, loff_t *pos)
{
unsigned int cpu_id = -1;
char buf[64];
if (cnt >= sizeof(buf))
return -EINVAL;
if (copy_from_user(buf, ubuf, cnt))
return -EFAULT;
buf[cnt] = '\0';
if (sscanf(buf, "%iu", &cpu_id) != 1)
return -EINVAL;
if (cpu_id >= nr_cpu_ids)
return cnt;
sched_isolate_cpu(cpu_id);
return cnt;
}
static int perfmgr_set_sched_deisolation_proc_show(struct seq_file *m, void *v)
{
seq_puts(m, "");
return 0;
}
static ssize_t perfmgr_set_sched_deisolation_proc_write(struct file *filp,
const char *ubuf, size_t cnt, loff_t *pos)
{
unsigned int cpu_id = -1;
char buf[64];
if (cnt >= sizeof(buf))
return -EINVAL;
if (copy_from_user(buf, ubuf, cnt))
return -EFAULT;
buf[cnt] = '\0';
if (sscanf(buf, "%iu", &cpu_id) != 1)
return -EINVAL;
if (cpu_id >= nr_cpu_ids)
return cnt;
sched_unisolate_cpu(cpu_id);
return cnt;
}
static int perfmgr_sched_isolated_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "cpu_isolated_mask=0x%lx\n",
__cpu_isolated_mask.bits[0]);
return 0;
}
#ifdef MTK_K14_EAS_BOOST
static void walt_mode(int enable)
{
#ifdef CONFIG_SCHED_WALT
sched_walt_enable(LT_WALT_POWERHAL, enable);
#else
pr_debug("walt not be configured\n");
#endif
}
void ext_launch_start(void)
{
pr_debug("_ext_launch_start\n");
/*--feature start from here--*/
#ifdef CONFIG_TRACING
perfmgr_trace_begin("ext_launch_start", 0, 1, 0);
#endif
walt_mode(1);
#ifdef CONFIG_TRACING
perfmgr_trace_end();
#endif
}
void ext_launch_end(void)
{
pr_debug("_ext_launch_end\n");
/*--feature end from here--*/
#ifdef CONFIG_TRACING
perfmgr_trace_begin("ext_launch_end", 0, 0, 1);
#endif
walt_mode(0);
#ifdef CONFIG_TRACING
perfmgr_trace_end();
#endif
}
/************************/
static int check_boost_value(int boost_value)
{
return clamp(boost_value, MIN_BOOST_VALUE, MAX_BOOST_VALUE);
}
static int check_uclamp_value(int value)
{
return clamp(value, MIN_UCLAMP_VALUE, MAX_UCLAMP_VALUE);
}
#ifdef CONFIG_SCHED_TUNE
int update_eas_boost_value(int kicker, int cgroup_idx, int value)
{
int final_boost = 0;
int i, len = 0, len1 = 0;
char msg[LOG_BUF_SIZE];
char msg1[LOG_BUF_SIZE];
if (cgroup_idx >= NR_CGROUP || cgroup_idx < 0) {
pr_debug("cgroup_idx:%d, error\n", cgroup_idx);
perfmgr_trace_printk("cpu_ctrl", "cgroup_idx >= NR_CGROUP\n");
return -1;
}
if (kicker < 0 || kicker >= EAS_MAX_KIR) {
pr_debug("kicker:%d error\n", kicker);
return -1;
}
mutex_lock(&boost_eas);
boost_value[cgroup_idx][kicker] = value;
len += snprintf(msg + len, sizeof(msg) - len, "[%d] [%d] [%d]",
kicker, cgroup_idx, value);
/*ptr return error EIO:I/O error */
if (len < 0) {
perfmgr_trace_printk("cpu_ctrl", "return -EIO 1\n");
mutex_unlock(&boost_eas);
return -EIO;
}
for (i = 0; i < EAS_MAX_KIR; i++) {
if (boost_value[cgroup_idx][i] == 0) {
clear_bit(i, &policy_mask[cgroup_idx]);
continue;
}
/* Always set first to handle negative input */
if (final_boost == 0)
final_boost = boost_value[cgroup_idx][i];
else
final_boost = MAX(final_boost,
boost_value[cgroup_idx][i]);
set_bit(i, &policy_mask[cgroup_idx]);
}
current_boost_value[cgroup_idx] = check_boost_value(final_boost);
len += snprintf(msg + len, sizeof(msg) - len, "{%d} ", final_boost);
/*ptr return error EIO:I/O error */
if (len < 0) {
perfmgr_trace_printk("cpu_ctrl", "return -EIO 2\n");
mutex_unlock(&boost_eas);
return -EIO;
}
len1 += snprintf(msg1 + len1, sizeof(msg1) - len1, "[0x %lx] ",
policy_mask[cgroup_idx]);
if (len1 < 0) {
perfmgr_trace_printk("cpu_ctrl", "return -EIO 3\n");
mutex_unlock(&boost_eas);
return -EIO;
}
#if SCHED_API_READY
if (!debug_fix_boost)
boost_write_for_perf_idx(cgroup_idx,
current_boost_value[cgroup_idx]);
#endif
if (strlen(msg) + strlen(msg1) < LOG_BUF_SIZE)
strncat(msg, msg1, strlen(msg1));
if (log_enable)
pr_debug("%s\n", msg);
#ifdef CONFIG_TRACING
perfmgr_trace_printk("eas_ctrl", msg);
#endif
mutex_unlock(&boost_eas);
return current_boost_value[cgroup_idx];
}
#else
int update_eas_boost_value(int kicker, int cgroup_idx, int value)
{
return -1;
}
#endif
static ssize_t perfmgr_perfserv_prefer_idle_proc_write(
struct file *filp, const char *ubuf,
size_t cnt, loff_t *pos)
{
int cgroup = 0, data = 0;
int rv = check_group_proc_write(&cgroup, &data, ubuf, cnt);
if (rv != 0)
return rv;
if (data < 0 || data > 1)
return -EINVAL;
if (cgroup >= 0 && cgroup < NR_CGROUP) {
if (data != 0)
update_prefer_idle_value(EAS_PREFER_IDLE_KIR_PERF,
cgroup, 1);
else
update_prefer_idle_value(EAS_PREFER_IDLE_KIR_PERF,
cgroup, 0);
}
return cnt;
}
static int perfmgr_perfserv_prefer_idle_proc_show(struct seq_file *m, void *v)
{
int i;
for (i = 0; i < NR_CGROUP; i++)
seq_printf(m, "%d\n",
test_bit(EAS_PREFER_IDLE_KIR_PERF, &prefer_idle[i]));
return 0;
}
static ssize_t perfmgr_boot_boost_proc_write(
struct file *filp, const char *ubuf,
size_t cnt, loff_t *pos)
{
int cgroup = 0, data = 0;
int rv = check_group_proc_write(&cgroup, &data, ubuf, cnt);
if (rv != 0)
return rv;
data = check_uclamp_value(data);
if (cgroup >= 0 && cgroup < NR_CGROUP)
update_eas_uclamp_min(EAS_UCLAMP_KIR_BOOT, cgroup, data);
return cnt;
}
static int perfmgr_boot_boost_proc_show(struct seq_file *m, void *v)
{
int i;
for (i = 0; i < NR_CGROUP; i++)
seq_printf(m, "%d\n", uclamp_min[i][EAS_UCLAMP_KIR_BOOT]);
return 0;
}
static ssize_t perfmgr_perfserv_bg_boost_proc_write(struct file *filp,
const char *ubuf, size_t cnt, loff_t *pos)
{
int data = 0;
int rv = check_proc_write(&data, ubuf, cnt);
if (rv != 0)
return rv;
data = check_boost_value(data);
update_eas_boost_value(EAS_KIR_PERF, CGROUP_BG, data);
return cnt;
}
static int perfmgr_perfserv_bg_boost_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "%d\n", boost_value[CGROUP_BG][EAS_KIR_PERF]);
return 0;
}
static ssize_t perfmgr_perfserv_fg_boost_proc_write(struct file *filp
, const char *ubuf, size_t cnt, loff_t *pos)
{
int data = 0;
int rv = check_proc_write(&data, ubuf, cnt);
if (rv != 0)
return rv;
data = check_boost_value(data);
update_eas_boost_value(EAS_KIR_PERF, CGROUP_FG, data);
return cnt;
}
static int perfmgr_perfserv_fg_boost_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "%d\n", boost_value[CGROUP_FG][EAS_KIR_PERF]);
return 0;
}
static ssize_t perfmgr_perfserv_ta_boost_proc_write(
struct file *filp, const char *ubuf,
size_t cnt, loff_t *pos)
{
int data = 0;
int rv = check_proc_write(&data, ubuf, cnt);
if (rv != 0)
return rv;
data = check_boost_value(data);
update_eas_boost_value(EAS_KIR_PERF, CGROUP_TA, data);
return cnt;
}
static int perfmgr_perfserv_ta_boost_proc_show(
struct seq_file *m, void *v)
{
seq_printf(m, "%d\n", boost_value[CGROUP_TA][EAS_KIR_PERF]);
return 0;
}
/* Add procfs to control sysctl_sched_migration_cost */
/* sysctl_sched_migration_cost: eas_ctrl_plat.h */
static ssize_t perfmgr_m_sched_migrate_cost_n_proc_write(struct file *filp,
const char *ubuf, size_t cnt, loff_t *pos)
{
int data = 0;
int rv = check_proc_write(&data, ubuf, cnt);
if (rv != 0)
return rv;
sysctl_sched_migration_cost = data;
return cnt;
}
static int perfmgr_m_sched_migrate_cost_n_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "%d\n", sysctl_sched_migration_cost);
return 0;
}
static ssize_t perfmgr_sched_stune_task_thresh_proc_write(struct file *filp,
const char *ubuf, size_t cnt, loff_t *pos)
{
int data = 0;
int rv = check_proc_write(&data, ubuf, cnt);
if (rv != 0)
return rv;
perf_sched_stune_task_thresh = data;
#if SCHED_API_READY
#ifdef CONFIG_SCHED_TUNE
if (perf_sched_stune_task_thresh >= 0)
set_stune_task_threshold(perf_sched_stune_task_thresh);
else
set_stune_task_threshold(-1);
#endif
#endif
return cnt;
}
static int perfmgr_sched_stune_task_thresh_proc_show(struct seq_file *m,
void *v)
{
seq_printf(m, "%d\n", perf_sched_stune_task_thresh);
return 0;
}
static int ext_launch_state;
static ssize_t perfmgr_perfserv_ext_launch_mon_proc_write(struct file *filp,
const char *ubuf, size_t cnt, loff_t *pos)
{
int data = 0;
int rv = check_proc_write(&data, ubuf, cnt);
if (rv != 0)
return rv;
if (data) {
ext_launch_start();
ext_launch_state = 1;
} else {
ext_launch_end();
ext_launch_state = 0;
}
pr_debug("perfmgr_perfserv_ext_launch_mon");
return cnt;
}
static int
perfmgr_perfserv_ext_launch_mon_proc_show(
struct seq_file *m, void *v)
{
seq_printf(m, "%d\n", ext_launch_state);
return 0;
}
/************************************************/
static int perfmgr_current_fg_boost_proc_show(struct seq_file *m, void *v)
{
#ifdef CONFIG_SCHED_TUNE
seq_printf(m, "%d\n", current_boost_value[CGROUP_FG]);
#else
seq_printf(m, "%d\n", -1);
#endif
return 0;
}
/************************************************************/
static ssize_t perfmgr_debug_fg_boost_proc_write(
struct file *filp, const char *ubuf,
size_t cnt, loff_t *pos)
{
int data = 0;
int rv = check_proc_write(&data, ubuf, cnt);
if (rv != 0)
return rv;
debug_boost_value[CGROUP_FG] = check_boost_value(data);
debug_fix_boost = debug_boost_value[CGROUP_FG] > 0 ? 1:0;
#if SCHED_API_READY
#ifdef CONFIG_SCHED_TUNE
boost_write_for_perf_idx(CGROUP_FG,
debug_boost_value[CGROUP_FG]);
#endif
#endif
return cnt;
}
static int perfmgr_debug_fg_boost_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "%d\n", debug_boost_value[CGROUP_FG]);
return 0;
}
/*******************************************************/
static int perfmgr_current_bg_boost_proc_show(struct seq_file *m, void *v)
{
#ifdef CONFIG_SCHED_TUNE
seq_printf(m, "%d\n", current_boost_value[CGROUP_BG]);
#else
seq_printf(m, "%d\n", -1);
#endif
return 0;
}
/**************************************************/
static ssize_t perfmgr_debug_bg_boost_proc_write(
struct file *filp, const char *ubuf,
size_t cnt, loff_t *pos)
{
int data = 0;
int rv = check_proc_write(&data, ubuf, cnt);
if (rv != 0)
return rv;
debug_boost_value[CGROUP_BG] = check_boost_value(data);
debug_fix_boost = debug_boost_value[CGROUP_BG] > 0 ? 1:0;
#if SCHED_API_READY
#ifdef CONFIG_SCHED_TUNE
boost_write_for_perf_idx(CGROUP_BG,
debug_boost_value[CGROUP_BG]);
#endif
#endif
return cnt;
}
static int perfmgr_debug_bg_boost_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "%d\n", debug_boost_value[CGROUP_BG]);
return 0;
}
/************************************************/
static int perfmgr_current_ta_boost_proc_show(struct seq_file *m, void *v)
{
#ifdef CONFIG_SCHED_TUNE
seq_printf(m, "%d\n", current_boost_value[CGROUP_TA]);
#else
seq_printf(m, "%d\n", -1);
#endif
return 0;
}
/**********************************/
static ssize_t perfmgr_debug_ta_boost_proc_write(
struct file *filp, const char *ubuf,
size_t cnt, loff_t *pos)
{
int data = 0;
int rv = check_proc_write(&data, ubuf, cnt);
if (rv != 0)
return rv;
debug_boost_value[CGROUP_TA] = check_boost_value(data);
debug_fix_boost = debug_boost_value[CGROUP_TA] > 0 ? 1:0;
#if SCHED_API_READY
#ifdef CONFIG_SCHED_TUNE
boost_write_for_perf_idx(CGROUP_TA,
debug_boost_value[CGROUP_TA]);
#endif
#endif
return cnt;
}
static int perfmgr_debug_ta_boost_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "%d\n", debug_boost_value[CGROUP_TA]);
return 0;
}
#endif
/* others */
#ifdef MTK_K14_EAS_BOOST
PROC_FOPS_RW(m_sched_migrate_cost_n);
PROC_FOPS_RW(sched_stune_task_thresh);
#endif
PROC_FOPS_RW(sched_big_task_rotation);
PROC_FOPS_RW(sched_boost);
PROC_FOPS_RW(cpu_prefer);
#ifdef MTK_K14_EAS_BOOST
/* boost value */
PROC_FOPS_RW(perfserv_fg_boost);
PROC_FOPS_RW(perfserv_bg_boost);
PROC_FOPS_RW(perfserv_ta_boost);
PROC_FOPS_RW(boot_boost);
PROC_FOPS_RO(current_fg_boost);
PROC_FOPS_RW(debug_fg_boost);
PROC_FOPS_RO(current_bg_boost);
PROC_FOPS_RW(debug_bg_boost);
PROC_FOPS_RO(current_ta_boost);
PROC_FOPS_RW(debug_ta_boost);
#endif
#ifdef MTK_K14_EAS_BOOST
/*--ext_launch--*/
PROC_FOPS_RW(perfserv_ext_launch_mon);
PROC_FOPS_RW(perfserv_prefer_idle);
#endif
PROC_FOPS_RW(set_sched_isolation);
PROC_FOPS_RW(set_sched_deisolation);
PROC_FOPS_RO(sched_isolated);
/*******************************************/
int eas_ctrl_init(struct proc_dir_entry *parent)
{
#ifdef CONFIG_MTK_SCHED_EXTENSION
int ret = 0;
size_t i;
#ifdef MTK_K14_EAS_BOOST
#if defined(CONFIG_SCHED_TUNE)
int j;
#endif
#endif
struct pentry {
const char *name;
const struct file_operations *fops;
};
const struct pentry entries[] = {
/*--sched migrate cost n--*/
#ifdef MTK_K14_EAS_BOOST
PROC_ENTRY(m_sched_migrate_cost_n),
PROC_ENTRY(sched_stune_task_thresh),
#endif
PROC_ENTRY(sched_big_task_rotation),
PROC_ENTRY(sched_boost),
PROC_ENTRY(cpu_prefer),
PROC_ENTRY(set_sched_isolation),
PROC_ENTRY(set_sched_deisolation),
PROC_ENTRY(sched_isolated),
#ifdef MTK_K14_EAS_BOOST
PROC_ENTRY(perfserv_prefer_idle),
/*--ext_launch--*/
PROC_ENTRY(perfserv_ext_launch_mon),
/* boost value */
PROC_ENTRY(perfserv_fg_boost),
PROC_ENTRY(perfserv_bg_boost),
PROC_ENTRY(perfserv_ta_boost),
PROC_ENTRY(current_fg_boost),
PROC_ENTRY(debug_fg_boost),
PROC_ENTRY(current_bg_boost),
PROC_ENTRY(debug_bg_boost),
PROC_ENTRY(current_ta_boost),
PROC_ENTRY(debug_ta_boost),
PROC_ENTRY(boot_boost),
#endif
};
/* create procfs */
for (i = 0; i < ARRAY_SIZE(entries); i++) {
if (!proc_create(entries[i].name, 0644,
parent, entries[i].fops)) {
pr_debug("%s(), create /eas_ctrl%s failed\n",
__func__, entries[i].name);
ret = -EINVAL;
goto out;
}
}
perf_sched_big_task_rotation = 0;
#ifdef MTK_K14_EAS_BOOST
#if defined(CONFIG_SCHED_TUNE)
/* boost value */
for (i = 0; i < NR_CGROUP; i++) {
current_boost_value[i] = 0;
for (j = 0; j < EAS_MAX_KIR; j++)
boost_value[i][j] = 0;
prefer_idle[i] = 0;
}
#endif
#if defined(CONFIG_UCLAMP_TASK_GROUP) && defined(CONFIG_SCHED_TUNE)
/* uclamp */
for (i = 0; i < NR_CGROUP; i++) {
//cur_uclamp_min[i] = 0;
//debug_uclamp_min[i] = -1;
for (j = 0; j < EAS_UCLAMP_MAX_KIR; j++)
uclamp_min[i][j] = 0;
}
#endif
perf_sched_stune_task_thresh = -1;
debug_fix_boost = 0;
#endif
last_cpu_prefer_pid = (pid_t)0;
last_cpu_perfer_type = 0;
out:
#endif
mutex_init(&boost_eas);
return 0;
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,17 @@
#
# Copyright (C) 2018 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 the
# GNU General Public License for more details.
#
ccflags-y += \
-I$(srctree)/kernel/
obj-y += topo_ctrl.o
@@ -0,0 +1,53 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef __MT_CPU_TOPO_PLATFORM_H__
#define __MT_CPU_TOPO_PLATFORM_H__
#ifdef __cplusplus
extern "C" {
#endif
/*==============================================================*/
/* Macros */
/*==============================================================*/
/* TODO: remove these workaround for k49 migration */
#define NO_SCHEDULE_API (1)
#define TOTAL_CORE_NUM (CORE_NUM_L)
#define CORE_NUM_L (4)
#define get_cluster_cpu_core(id) \
(id ? 0 : CORE_NUM_L)
/*==============================================================*/
/* Enum */
/*==============================================================*/
enum ppm_cluster {
PPM_CLUSTER_L = 0,
NR_PPM_CLUSTERS,
};
/*==============================================================*/
/* Data Structures */
/*==============================================================*/
/*==============================================================*/
/* Global Variables */
/*==============================================================*/
/*==============================================================*/
/* APIs */
/*==============================================================*/
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,55 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef __MT_CPU_TOPO_PLATFORM_H__
#define __MT_CPU_TOPO_PLATFORM_H__
#ifdef __cplusplus
extern "C" {
#endif
/*==============================================================*/
/* Macros */
/*==============================================================*/
/* TODO: remove these workaround for k49 migration */
#define NO_SCHEDULE_API (1)
#define TOTAL_CORE_NUM (CORE_NUM_L+CORE_NUM_B)
#define CORE_NUM_L (6)
#define CORE_NUM_B (2)
#define get_cluster_cpu_core(id) \
(id ? CORE_NUM_B : CORE_NUM_L)
/*==============================================================*/
/* Enum */
/*==============================================================*/
enum ppm_cluster {
PPM_CLUSTER_L = 0,
PPM_CLUSTER_B,
NR_PPM_CLUSTERS,
};
/*==============================================================*/
/* Data Structures */
/*==============================================================*/
/*==============================================================*/
/* Global Variables */
/*==============================================================*/
/*==============================================================*/
/* APIs */
/*==============================================================*/
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,54 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef __MT_CPU_TOPO_PLATFORM_H__
#define __MT_CPU_TOPO_PLATFORM_H__
#ifdef __cplusplus
extern "C" {
#endif
/*==============================================================*/
/* Macros */
/*==============================================================*/
/* TODO: remove these workaround for k49 migration */
#define NO_SCHEDULE_API (1)
#define TOTAL_CORE_NUM (CORE_NUM_L+CORE_NUM_B)
#define CORE_NUM_L (6)
#define CORE_NUM_B (2)
#define get_cluster_cpu_core(id) \
(id ? CORE_NUM_B : CORE_NUM_L)
/*==============================================================*/
/* Enum */
/*==============================================================*/
enum ppm_cluster {
PPM_CLUSTER_L = 0,
PPM_CLUSTER_B,
NR_PPM_CLUSTERS,
};
/*==============================================================*/
/* Data Structures */
/*==============================================================*/
/*==============================================================*/
/* Global Variables */
/*==============================================================*/
/*==============================================================*/
/* APIs */
/*==============================================================*/
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,56 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef __MT_CPU_TOPO_PLATFORM_H__
#define __MT_CPU_TOPO_PLATFORM_H__
#ifdef __cplusplus
extern "C" {
#endif
/*==============================================================*/
/* Macros */
/*==============================================================*/
/* TODO: remove these workaround for k49 migration */
#define NO_SCHEDULE_API (1)
#define TOTAL_CORE_NUM (CORE_NUM_L+CORE_NUM_B)
#define CORE_NUM_L (6)
#define CORE_NUM_B (2)
#define get_cluster_cpu_core(id) \
(id ? CORE_NUM_B : CORE_NUM_L)
/*==============================================================*/
/* Enum */
/*==============================================================*/
enum ppm_cluster {
PPM_CLUSTER_L = 0,
PPM_CLUSTER_B,
NR_PPM_CLUSTERS,
};
/*==============================================================*/
/* Data Structures */
/*==============================================================*/
/*==============================================================*/
/* Global Variables */
/*==============================================================*/
/*==============================================================*/
/* APIs */
/*==============================================================*/
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,55 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef __MT_CPU_TOPO_PLATFORM_H__
#define __MT_CPU_TOPO_PLATFORM_H__
#ifdef __cplusplus
extern "C" {
#endif
/*==============================================================*/
/* Macros */
/*==============================================================*/
/* TODO: remove these workaround for k49 migration */
#define NO_SCHEDULE_API (1)
#define TOTAL_CORE_NUM (CORE_NUM_L+CORE_NUM_B)
#define CORE_NUM_L (4)
#define CORE_NUM_B (4)
#define get_cluster_cpu_core(id) \
(id ? CORE_NUM_B : CORE_NUM_L)
/*==============================================================*/
/* Enum */
/*==============================================================*/
enum ppm_cluster {
PPM_CLUSTER_L = 0,
PPM_CLUSTER_B,
NR_PPM_CLUSTERS,
};
/*==============================================================*/
/* Data Structures */
/*==============================================================*/
/*==============================================================*/
/* Global Variables */
/*==============================================================*/
/*==============================================================*/
/* APIs */
/*==============================================================*/
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,88 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef __MT_CPU_TOPO_PLATFORM_H__
#define __MT_CPU_TOPO_PLATFORM_H__
#ifdef __cplusplus
extern "C" {
#endif
/*==============================================================*/
/* Macros */
/*==============================================================*/
/* TODO: remove these workaround for k49 migration */
#define NO_SCHEDULE_API (1)
#if defined(CONFIG_MTK_SCHED_MULTI_GEARS)
#define TOTAL_CORE_NUM (CORE_NUM_L+CORE_NUM_B+CORE_NUM_BB)
#define CORE_NUM_L (4)
#define CORE_NUM_B (3)
#define CORE_NUM_BB (1)
static inline unsigned int get_cluster_cpu_core(unsigned int id)
{
if (id == 0)
return CORE_NUM_L;
else if (id == 1)
return CORE_NUM_B;
else if (id == 2)
return CORE_NUM_BB;
return 0;
}
/*==============================================================*/
/* Enum */
/*==============================================================*/
enum ppm_cluster {
PPM_CLUSTER_L = 0,
PPM_CLUSTER_B,
PPM_CLUSTER_BB,
NR_PPM_CLUSTERS,
};
#else
#define TOTAL_CORE_NUM (CORE_NUM_L+CORE_NUM_B)
#define CORE_NUM_L (4)
#define CORE_NUM_B (4)
#define get_cluster_cpu_core(id) \
(id ? CORE_NUM_B : CORE_NUM_L)
/*==============================================================*/
/* Enum */
/*==============================================================*/
enum ppm_cluster {
PPM_CLUSTER_L = 0,
PPM_CLUSTER_B,
NR_PPM_CLUSTERS,
};
#endif /* CONFIG_MTK_SCHED_MULTI_GEARS */
/*==============================================================*/
/* Data Structures */
/*==============================================================*/
/*==============================================================*/
/* Global Variables */
/*==============================================================*/
/*==============================================================*/
/* APIs */
/*==============================================================*/
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,256 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#define pr_fmt(fmt) "[topo_ctrl]"fmt
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/topology.h>
#include <sched/sched.h>
#include "topo_ctrl.h"
#include "mtk_perfmgr_internal.h"
/* data type */
struct topo_plat_cluster_info {
unsigned int core_num;
unsigned int cpu_id; /* cpu id of the dvfs policy owner */
struct cpumask cpus;
};
/* global variable */
int topo_cluster_num;
static int *calc_cpu_cap, *calc_cpu_num;
static int s_clstr_core, b_clstr_core;
static struct topo_plat_cluster_info *topo_cluster_info;
int topo_ctrl_get_nr_clusters(void)
{
return topo_cluster_num;
}
EXPORT_SYMBOL(topo_ctrl_get_nr_clusters);
int topo_ctrl_get_cluster_cpu_id(int id)
{
if (id < 0 || id >= topo_cluster_num)
return -1;
return topo_cluster_info[id].cpu_id;
}
EXPORT_SYMBOL(topo_ctrl_get_cluster_cpu_id);
/***************************************/
static void topo_platform_init(void)
{
int i, j, bit = 0, cpu, clus_id;
/* get cluster num */
topo_cluster_num = arch_nr_clusters();
if (topo_cluster_num <= 0)
return;
topo_cluster_info = kcalloc(topo_cluster_num,
sizeof(struct topo_plat_cluster_info), GFP_KERNEL);
if (!topo_cluster_info) {
topo_cluster_num = 0;
return;
}
/* init value */
for (i = 0; i < topo_cluster_num; i++)
topo_cluster_info[i].core_num = 0;
/* calculate cpu number */
for_each_possible_cpu(cpu) {
clus_id = arch_cpu_cluster_id(cpu);
if (clus_id < topo_cluster_num && clus_id >= 0)
topo_cluster_info[clus_id].core_num += 1;
}
for (i = 0; i < topo_cluster_num; i++) {
if (i > 0)
topo_cluster_info[i].cpu_id =
topo_cluster_info[i-1].cpu_id +
topo_cluster_info[i-1].core_num;
else
topo_cluster_info[i].cpu_id = 0;
cpumask_clear(&topo_cluster_info[i].cpus);
for (j = 0; j < topo_cluster_info[i].core_num; j++) {
cpumask_set_cpu(bit, &topo_cluster_info[i].cpus);
bit++;
}
}
}
static void calc_min_cpucap(void)
{
int i, cpu_num = 0, min = INT_MAX, max = 0;
int cpu;
struct cpumask cpus;
struct cpumask cpu_online_cpumask;
unsigned long cap_orig;
for (i = 0; i < topo_cluster_num ; i++) {
memcpy(&cpus, &topo_cluster_info[i].cpus,
sizeof(struct cpumask));
cpumask_and(&cpu_online_cpumask,
&cpus, cpu_possible_mask);
calc_cpu_num[i] = cpumask_weight(&cpu_online_cpumask);
for_each_possible_cpu(cpu) {
if (arch_cpu_cluster_id(cpu) == i) {
cap_orig = capacity_orig_of(cpu);
break;
}
}
calc_cpu_cap[i] = (int)cap_orig;
if (calc_cpu_cap[i] < min) {
s_clstr_core = i;
min = calc_cpu_cap[i];
}
if (calc_cpu_cap[i] > max) {
b_clstr_core = i;
max = calc_cpu_cap[i];
}
cpu_num += calc_cpu_num[i];
}
}
int get_min_clstr_cap(void)
{
/*get smallest cluster num*/
return s_clstr_core;
}
int get_max_clstr_cap(void)
{
/*get biggest cluster num*/
return b_clstr_core;
}
static int perfmgr_glb_info_proc_show(struct seq_file *m, void *v)
{
int i;
seq_printf(m, "perfmgr_clusters : %d\n", topo_cluster_num);
for (i = 0 ; i < topo_cluster_num ; i++) {
seq_printf(m, "calc_cpu_cap[%d]:%d\n", i, calc_cpu_cap[i]);
seq_printf(m, "calc_cpu_num[%d]:%d\n", i, calc_cpu_num[i]);
}
seq_printf(m, "s_clstr_core : %d\n", s_clstr_core);
seq_printf(m, "b_clstr_core : %d\n", b_clstr_core);
return 0;
}
static int perfmgr_topo_ctrl_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "%d\n", topo_cluster_num);
return 0;
}
static int perfmgr_is_big_little_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "%d\n", (topo_cluster_num) > 1 ? 1 : 0);
return 0;
}
static int perfmgr_nr_clusters_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "%d\n", topo_cluster_num);
return 0;
}
static int perfmgr_cpus_per_cluster_proc_show(struct seq_file *m, void *v)
{
int i;
for (i = 0; i < topo_cluster_num; i++)
seq_printf(m, "cluster%d: %0lx\n", i,
*cpumask_bits(&topo_cluster_info[i].cpus));
return 0;
}
PROC_FOPS_RO(topo_ctrl);
PROC_FOPS_RO(glb_info);
PROC_FOPS_RO(is_big_little);
PROC_FOPS_RO(nr_clusters);
PROC_FOPS_RO(cpus_per_cluster);
/************************************************/
int topo_ctrl_init(struct proc_dir_entry *parent)
{
struct proc_dir_entry *topo_dir = NULL;
int ret = 0;
size_t i;
struct pentry {
const char *name;
const struct file_operations *fops;
};
const struct pentry entries[] = {
PROC_ENTRY(topo_ctrl),
PROC_ENTRY(glb_info),
PROC_ENTRY(is_big_little),
PROC_ENTRY(nr_clusters),
PROC_ENTRY(cpus_per_cluster),
};
topo_dir = proc_mkdir("topo_ctrl", parent);
if (!topo_dir)
pr_debug("topo_dir null\n ");
/* create procfs */
for (i = 0; i < ARRAY_SIZE(entries); i++) {
if (!proc_create(entries[i].name, 0644,
topo_dir, entries[i].fops)) {
pr_debug("%s(), create /topo_ctrl%s failed\n",
__func__, entries[i].name);
ret = -EINVAL;
goto out;
}
}
topo_cluster_num = 0;
topo_cluster_info = NULL;
topo_platform_init();
if (topo_cluster_num > 0) {
calc_cpu_cap = kcalloc(topo_cluster_num,
sizeof(int), GFP_KERNEL);
calc_cpu_num = kcalloc(topo_cluster_num,
sizeof(int), GFP_KERNEL);
if (!calc_cpu_cap || !calc_cpu_num)
goto out;
} else {
calc_cpu_cap = NULL;
calc_cpu_num = NULL;
}
calc_min_cpucap();
out:
return ret;
}
void topo_ctrl_exit(void)
{
kfree(topo_cluster_info);
kfree(calc_cpu_cap);
kfree(calc_cpu_num);
}