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,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;
}