mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-22 17:25:35 +03:00
devfreq: wmark: active: config params by sysfs
Configure governor parameters through sysfs instead of debugfs, add add spinlock for concurrency protection. Bug 200501949 Change-Id: I0131e6ab0d3befe380ef4774eb4d6193d2266011 Signed-off-by: Aaron Tian <atian@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/2267338 (cherry picked from commit 6d2e734e3b1a3d951a7b934c869c91f99dc3f2f7) Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2278103 Reviewed-by: automaticguardword <automaticguardword@nvidia.com> Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Mikko Perttunen <mperttunen@nvidia.com> Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> GVS: Gerrit_Virtual_Submit Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
committed by
Laxman Dewangan
parent
b2ef349be6
commit
cd1ab69066
@@ -25,17 +25,29 @@
|
|||||||
|
|
||||||
#include "governor.h"
|
#include "governor.h"
|
||||||
|
|
||||||
|
struct wmark_gov_param {
|
||||||
|
unsigned int block_window;
|
||||||
|
unsigned int load_target;
|
||||||
|
unsigned int load_max;
|
||||||
|
unsigned int smooth;
|
||||||
|
bool freq_boost_en;
|
||||||
|
};
|
||||||
|
|
||||||
struct wmark_gov_info {
|
struct wmark_gov_info {
|
||||||
/* probed from the devfreq */
|
/* probed from the devfreq */
|
||||||
unsigned long *freqlist;
|
unsigned long *freqlist;
|
||||||
int freq_count;
|
int freq_count;
|
||||||
|
|
||||||
/* algorithm parameters */
|
/* algorithm parameters */
|
||||||
unsigned int p_block_window;
|
struct wmark_gov_param param;
|
||||||
unsigned int p_load_target;
|
|
||||||
unsigned int p_load_max;
|
struct kobj_attribute block_window_attr;
|
||||||
unsigned int p_smooth;
|
struct kobj_attribute load_target_attr;
|
||||||
bool p_freq_boost_en;
|
struct kobj_attribute load_max_attr;
|
||||||
|
struct kobj_attribute smooth_attr;
|
||||||
|
struct kobj_attribute freq_boost_en_attr;
|
||||||
|
|
||||||
|
spinlock_t param_lock;
|
||||||
|
|
||||||
/* common data */
|
/* common data */
|
||||||
struct devfreq *df;
|
struct devfreq *df;
|
||||||
@@ -111,6 +123,15 @@ static void update_watermarks(struct devfreq *df,
|
|||||||
struct wmark_gov_info *wmarkinfo = df->data;
|
struct wmark_gov_info *wmarkinfo = df->data;
|
||||||
unsigned long long relation = 0, next_freq = 0;
|
unsigned long long relation = 0, next_freq = 0;
|
||||||
unsigned long long current_frequency_khz = current_frequency / 1000;
|
unsigned long long current_frequency_khz = current_frequency / 1000;
|
||||||
|
unsigned long flags;
|
||||||
|
struct wmark_gov_param param;
|
||||||
|
|
||||||
|
/* get governor parameters */
|
||||||
|
spin_lock_irqsave(&wmarkinfo->param_lock, flags);
|
||||||
|
|
||||||
|
param = wmarkinfo->param;
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&wmarkinfo->param_lock, flags);
|
||||||
|
|
||||||
if (ideal_frequency == wmarkinfo->freqlist[0]) {
|
if (ideal_frequency == wmarkinfo->freqlist[0]) {
|
||||||
/* disable the low watermark if we are at lowest clock */
|
/* disable the low watermark if we are at lowest clock */
|
||||||
@@ -121,7 +142,7 @@ static void update_watermarks(struct devfreq *df,
|
|||||||
* that we are running at the new frequency? */
|
* that we are running at the new frequency? */
|
||||||
next_freq = freqlist_down(wmarkinfo, ideal_frequency);
|
next_freq = freqlist_down(wmarkinfo, ideal_frequency);
|
||||||
relation = ((next_freq / current_frequency_khz) *
|
relation = ((next_freq / current_frequency_khz) *
|
||||||
wmarkinfo->p_load_target) / 1000;
|
param.load_target) / 1000;
|
||||||
df->profile->set_low_wmark(df->dev.parent, relation);
|
df->profile->set_low_wmark(df->dev.parent, relation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,8 +156,8 @@ static void update_watermarks(struct devfreq *df,
|
|||||||
* that we are running at the new frequency? */
|
* that we are running at the new frequency? */
|
||||||
next_freq = freqlist_up(wmarkinfo, ideal_frequency);
|
next_freq = freqlist_up(wmarkinfo, ideal_frequency);
|
||||||
relation = ((next_freq / current_frequency_khz) *
|
relation = ((next_freq / current_frequency_khz) *
|
||||||
wmarkinfo->p_load_target) / 1000;
|
param.load_target) / 1000;
|
||||||
relation = min((unsigned long long)wmarkinfo->p_load_max,
|
relation = min_t(unsigned long long, param.load_max,
|
||||||
relation);
|
relation);
|
||||||
df->profile->set_high_wmark(df->dev.parent, relation);
|
df->profile->set_high_wmark(df->dev.parent, relation);
|
||||||
}
|
}
|
||||||
@@ -151,6 +172,9 @@ static int devfreq_watermark_target_freq(struct devfreq *df,
|
|||||||
ktime_t current_time = ktime_get();
|
ktime_t current_time = ktime_get();
|
||||||
s64 dt = ktime_us_delta(current_time, wmarkinfo->last_frequency_update);
|
s64 dt = ktime_us_delta(current_time, wmarkinfo->last_frequency_update);
|
||||||
int err;
|
int err;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
struct wmark_gov_param param;
|
||||||
|
|
||||||
err = df->profile->get_dev_status(df->dev.parent, &dev_stat);
|
err = df->profile->get_dev_status(df->dev.parent, &dev_stat);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
@@ -163,11 +187,18 @@ static int devfreq_watermark_target_freq(struct devfreq *df,
|
|||||||
if (!dev_stat.total_time)
|
if (!dev_stat.total_time)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* calculate first load and relation load/p_load_target */
|
/* get governor parameters */
|
||||||
|
spin_lock_irqsave(&wmarkinfo->param_lock, flags);
|
||||||
|
|
||||||
|
param = wmarkinfo->param;
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&wmarkinfo->param_lock, flags);
|
||||||
|
|
||||||
|
/* calculate first load and relation load/load_target */
|
||||||
load = (dev_stat.busy_time * 1000) / dev_stat.total_time;
|
load = (dev_stat.busy_time * 1000) / dev_stat.total_time;
|
||||||
|
|
||||||
/* if we cross load max... */
|
/* if we cross load max... */
|
||||||
if (wmarkinfo->p_freq_boost_en && load >= wmarkinfo->p_load_max) {
|
if (param.freq_boost_en && load >= param.load_max) {
|
||||||
/* we go directly to the highest frequency. depending
|
/* we go directly to the highest frequency. depending
|
||||||
* on frequency table we might never go higher than
|
* on frequency table we might never go higher than
|
||||||
* the current frequency (i.e. load should be over 100%
|
* the current frequency (i.e. load should be over 100%
|
||||||
@@ -177,7 +208,7 @@ static int devfreq_watermark_target_freq(struct devfreq *df,
|
|||||||
/* otherwise, based on relation between current load and
|
/* otherwise, based on relation between current load and
|
||||||
* load target we calculate the "ideal" frequency
|
* load target we calculate the "ideal" frequency
|
||||||
* where we would be just at the target */
|
* where we would be just at the target */
|
||||||
relation = (load * 1000) / wmarkinfo->p_load_target;
|
relation = (load * 1000) / param.load_target;
|
||||||
ideal_freq = relation * (dev_stat.current_frequency / 1000);
|
ideal_freq = relation * (dev_stat.current_frequency / 1000);
|
||||||
|
|
||||||
/* round this frequency */
|
/* round this frequency */
|
||||||
@@ -186,11 +217,11 @@ static int devfreq_watermark_target_freq(struct devfreq *df,
|
|||||||
|
|
||||||
/* update average target frequency */
|
/* update average target frequency */
|
||||||
wmarkinfo->average_target_freq =
|
wmarkinfo->average_target_freq =
|
||||||
(wmarkinfo->p_smooth * wmarkinfo->average_target_freq +
|
(param.smooth * wmarkinfo->average_target_freq +
|
||||||
ideal_freq) / (wmarkinfo->p_smooth + 1);
|
ideal_freq) / (param.smooth + 1);
|
||||||
|
|
||||||
/* do not scale too often */
|
/* do not scale too often */
|
||||||
if (dt < wmarkinfo->p_block_window)
|
if (dt < param.block_window)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* update the frequency */
|
/* update the frequency */
|
||||||
@@ -206,59 +237,310 @@ static int devfreq_watermark_target_freq(struct devfreq *df,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void devfreq_watermark_debug_start(struct devfreq *df)
|
static ssize_t block_window_show(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr,
|
||||||
|
char *buf)
|
||||||
{
|
{
|
||||||
struct wmark_gov_info *wmarkinfo = df->data;
|
struct wmark_gov_info *wmarkinfo = NULL;
|
||||||
struct dentry *f;
|
ssize_t res;
|
||||||
char dirname[128];
|
unsigned int val;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
snprintf(dirname, sizeof(dirname), "%s_scaling",
|
wmarkinfo = container_of(attr,
|
||||||
to_platform_device(df->dev.parent)->name);
|
struct wmark_gov_info,
|
||||||
|
block_window_attr);
|
||||||
|
|
||||||
if (!wmarkinfo)
|
spin_lock_irqsave(&wmarkinfo->param_lock, flags);
|
||||||
return;
|
val = wmarkinfo->param.block_window;
|
||||||
|
spin_unlock_irqrestore(&wmarkinfo->param_lock, flags);
|
||||||
|
|
||||||
wmarkinfo->debugdir = debugfs_create_dir(dirname, NULL);
|
res = snprintf(buf, PAGE_SIZE, "%u\n", val);
|
||||||
if (!wmarkinfo->debugdir) {
|
|
||||||
pr_warn("cannot create debugfs directory\n");
|
return res;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CREATE_DBG_FILE(type, fname) \
|
static ssize_t block_window_store(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct wmark_gov_info *wmarkinfo = NULL;
|
||||||
|
unsigned long val = 0;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
wmarkinfo = container_of(attr,
|
||||||
|
struct wmark_gov_info,
|
||||||
|
block_window_attr);
|
||||||
|
|
||||||
|
if (kstrtoul(buf, 10, &val) < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&wmarkinfo->param_lock, flags);
|
||||||
|
wmarkinfo->param.block_window = val;
|
||||||
|
spin_unlock_irqrestore(&wmarkinfo->param_lock, flags);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t load_target_show(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct wmark_gov_info *wmarkinfo = NULL;
|
||||||
|
ssize_t res;
|
||||||
|
unsigned int val;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
wmarkinfo = container_of(attr,
|
||||||
|
struct wmark_gov_info,
|
||||||
|
load_target_attr);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&wmarkinfo->param_lock, flags);
|
||||||
|
val = wmarkinfo->param.load_target;
|
||||||
|
spin_unlock_irqrestore(&wmarkinfo->param_lock, flags);
|
||||||
|
|
||||||
|
res = snprintf(buf, PAGE_SIZE, "%u\n", val);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t load_target_store(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct wmark_gov_info *wmarkinfo = NULL;
|
||||||
|
unsigned long val = 0;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
wmarkinfo = container_of(attr,
|
||||||
|
struct wmark_gov_info,
|
||||||
|
load_target_attr);
|
||||||
|
|
||||||
|
if (kstrtoul(buf, 10, &val) < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&wmarkinfo->param_lock, flags);
|
||||||
|
wmarkinfo->param.load_target = val;
|
||||||
|
spin_unlock_irqrestore(&wmarkinfo->param_lock, flags);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t load_max_show(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct wmark_gov_info *wmarkinfo = NULL;
|
||||||
|
ssize_t res;
|
||||||
|
unsigned int val;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
wmarkinfo = container_of(attr,
|
||||||
|
struct wmark_gov_info,
|
||||||
|
load_max_attr);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&wmarkinfo->param_lock, flags);
|
||||||
|
val = wmarkinfo->param.load_max;
|
||||||
|
spin_unlock_irqrestore(&wmarkinfo->param_lock, flags);
|
||||||
|
|
||||||
|
res = snprintf(buf, PAGE_SIZE, "%u\n", val);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t load_max_store(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct wmark_gov_info *wmarkinfo = NULL;
|
||||||
|
unsigned long val = 0;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
wmarkinfo = container_of(attr,
|
||||||
|
struct wmark_gov_info,
|
||||||
|
load_max_attr);
|
||||||
|
|
||||||
|
if (kstrtoul(buf, 10, &val) < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&wmarkinfo->param_lock, flags);
|
||||||
|
wmarkinfo->param.load_max = val;
|
||||||
|
spin_unlock_irqrestore(&wmarkinfo->param_lock, flags);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t smooth_show(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct wmark_gov_info *wmarkinfo = NULL;
|
||||||
|
ssize_t res;
|
||||||
|
unsigned int val;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
wmarkinfo = container_of(attr,
|
||||||
|
struct wmark_gov_info,
|
||||||
|
smooth_attr);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&wmarkinfo->param_lock, flags);
|
||||||
|
val = wmarkinfo->param.smooth;
|
||||||
|
spin_unlock_irqrestore(&wmarkinfo->param_lock, flags);
|
||||||
|
|
||||||
|
res = snprintf(buf, PAGE_SIZE, "%u\n", val);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t smooth_store(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct wmark_gov_info *wmarkinfo = NULL;
|
||||||
|
unsigned long val = 0;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
wmarkinfo = container_of(attr,
|
||||||
|
struct wmark_gov_info,
|
||||||
|
smooth_attr);
|
||||||
|
|
||||||
|
if (kstrtoul(buf, 10, &val) < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&wmarkinfo->param_lock, flags);
|
||||||
|
wmarkinfo->param.smooth = val;
|
||||||
|
spin_unlock_irqrestore(&wmarkinfo->param_lock, flags);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t freq_boost_en_show(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct wmark_gov_info *wmarkinfo = NULL;
|
||||||
|
ssize_t res;
|
||||||
|
bool val;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
wmarkinfo = container_of(attr,
|
||||||
|
struct wmark_gov_info,
|
||||||
|
freq_boost_en_attr);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&wmarkinfo->param_lock, flags);
|
||||||
|
val = wmarkinfo->param.freq_boost_en;
|
||||||
|
spin_unlock_irqrestore(&wmarkinfo->param_lock, flags);
|
||||||
|
|
||||||
|
res = snprintf(buf, PAGE_SIZE, "%d\n", val);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t freq_boost_en_store(struct kobject *kobj,
|
||||||
|
struct kobj_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct wmark_gov_info *wmarkinfo = NULL;
|
||||||
|
unsigned long val = 0;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
wmarkinfo = container_of(attr,
|
||||||
|
struct wmark_gov_info,
|
||||||
|
freq_boost_en_attr);
|
||||||
|
|
||||||
|
if (kstrtoul(buf, 10, &val) < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&wmarkinfo->param_lock, flags);
|
||||||
|
wmarkinfo->param.freq_boost_en = !!val;
|
||||||
|
spin_unlock_irqrestore(&wmarkinfo->param_lock, flags);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define INIT_SYSFS_ATTR_RW(sysfs_name) \
|
||||||
do { \
|
do { \
|
||||||
f = debugfs_create_##type(#fname, S_IRUGO | S_IWUSR, \
|
attr->attr.name = #sysfs_name; \
|
||||||
wmarkinfo->debugdir, &wmarkinfo->p_##fname); \
|
attr->attr.mode = 0644; \
|
||||||
if (NULL == f) { \
|
attr->show = sysfs_name##_show; \
|
||||||
pr_warn("cannot create debug entry " #fname "\n"); \
|
attr->store = sysfs_name##_store; \
|
||||||
return; \
|
sysfs_attr_init(&attr->attr); \
|
||||||
} \
|
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define CREATE_DBG_FILE_BOOL(fname) CREATE_DBG_FILE(bool, fname)
|
static int devfreq_watermark_debug_start(struct devfreq *df)
|
||||||
#define CREATE_DBG_FILE_U32(fname) CREATE_DBG_FILE(u32, fname)
|
{
|
||||||
|
struct wmark_gov_info *wmarkinfo = df->data;
|
||||||
|
struct kobj_attribute *attr = NULL;
|
||||||
|
|
||||||
CREATE_DBG_FILE_U32(load_target);
|
if (!wmarkinfo)
|
||||||
CREATE_DBG_FILE_U32(load_max);
|
return 0;
|
||||||
CREATE_DBG_FILE_U32(block_window);
|
|
||||||
CREATE_DBG_FILE_U32(smooth);
|
|
||||||
CREATE_DBG_FILE_BOOL(freq_boost_en);
|
|
||||||
|
|
||||||
#undef CREATE_DBG_FILE_U32
|
spin_lock_init(&wmarkinfo->param_lock);
|
||||||
#undef CREATE_DBG_FILE_BOOL
|
|
||||||
#undef CREATE_DBG_FILE
|
|
||||||
|
|
||||||
|
attr = &wmarkinfo->block_window_attr;
|
||||||
|
INIT_SYSFS_ATTR_RW(block_window);
|
||||||
|
if (sysfs_create_file(&df->dev.parent->kobj, &attr->attr))
|
||||||
|
goto err_create_block_window_sysfs_entry;
|
||||||
|
|
||||||
|
attr = &wmarkinfo->load_target_attr;
|
||||||
|
INIT_SYSFS_ATTR_RW(load_target);
|
||||||
|
if (sysfs_create_file(&df->dev.parent->kobj, &attr->attr))
|
||||||
|
goto err_create_load_target_sysfs_entry;
|
||||||
|
|
||||||
|
attr = &wmarkinfo->load_max_attr;
|
||||||
|
INIT_SYSFS_ATTR_RW(load_max);
|
||||||
|
if (sysfs_create_file(&df->dev.parent->kobj, &attr->attr))
|
||||||
|
goto err_create_load_max_sysfs_entry;
|
||||||
|
|
||||||
|
attr = &wmarkinfo->smooth_attr;
|
||||||
|
INIT_SYSFS_ATTR_RW(smooth);
|
||||||
|
if (sysfs_create_file(&df->dev.parent->kobj, &attr->attr))
|
||||||
|
goto err_create_smooth_sysfs_entry;
|
||||||
|
|
||||||
|
attr = &wmarkinfo->freq_boost_en_attr;
|
||||||
|
INIT_SYSFS_ATTR_RW(freq_boost_en);
|
||||||
|
if (sysfs_create_file(&df->dev.parent->kobj, &attr->attr))
|
||||||
|
goto err_create_freq_boost_en_sysfs_entry;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_create_freq_boost_en_sysfs_entry:
|
||||||
|
sysfs_remove_file(&df->dev.parent->kobj,
|
||||||
|
&wmarkinfo->smooth_attr.attr);
|
||||||
|
err_create_smooth_sysfs_entry:
|
||||||
|
sysfs_remove_file(&df->dev.parent->kobj,
|
||||||
|
&wmarkinfo->load_max_attr.attr);
|
||||||
|
err_create_load_max_sysfs_entry:
|
||||||
|
sysfs_remove_file(&df->dev.parent->kobj,
|
||||||
|
&wmarkinfo->load_target_attr.attr);
|
||||||
|
err_create_load_target_sysfs_entry:
|
||||||
|
sysfs_remove_file(&df->dev.parent->kobj,
|
||||||
|
&wmarkinfo->block_window_attr.attr);
|
||||||
|
err_create_block_window_sysfs_entry:
|
||||||
|
|
||||||
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void devfreq_watermark_debug_stop(struct devfreq *df)
|
static void devfreq_watermark_debug_stop(struct devfreq *df)
|
||||||
{
|
{
|
||||||
struct wmark_gov_info *wmarkinfo = df->data;
|
struct wmark_gov_info *wmarkinfo = df->data;
|
||||||
debugfs_remove_recursive(wmarkinfo->debugdir);
|
|
||||||
|
sysfs_remove_file(&df->dev.parent->kobj,
|
||||||
|
&wmarkinfo->freq_boost_en_attr.attr);
|
||||||
|
sysfs_remove_file(&df->dev.parent->kobj,
|
||||||
|
&wmarkinfo->smooth_attr.attr);
|
||||||
|
sysfs_remove_file(&df->dev.parent->kobj,
|
||||||
|
&wmarkinfo->load_max_attr.attr);
|
||||||
|
sysfs_remove_file(&df->dev.parent->kobj,
|
||||||
|
&wmarkinfo->load_target_attr.attr);
|
||||||
|
sysfs_remove_file(&df->dev.parent->kobj,
|
||||||
|
&wmarkinfo->block_window_attr.attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int devfreq_watermark_start(struct devfreq *df)
|
static int devfreq_watermark_start(struct devfreq *df)
|
||||||
{
|
{
|
||||||
struct wmark_gov_info *wmarkinfo;
|
struct wmark_gov_info *wmarkinfo;
|
||||||
struct platform_device *pdev = to_platform_device(df->dev.parent);
|
struct platform_device *pdev = to_platform_device(df->dev.parent);
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (!df->profile->freq_table) {
|
if (!df->profile->freq_table) {
|
||||||
dev_err(&pdev->dev, "Frequency table missing\n");
|
dev_err(&pdev->dev, "Frequency table missing\n");
|
||||||
@@ -272,17 +554,17 @@ static int devfreq_watermark_start(struct devfreq *df)
|
|||||||
df->data = (void *)wmarkinfo;
|
df->data = (void *)wmarkinfo;
|
||||||
wmarkinfo->freqlist = df->profile->freq_table;
|
wmarkinfo->freqlist = df->profile->freq_table;
|
||||||
wmarkinfo->freq_count = df->profile->max_state;
|
wmarkinfo->freq_count = df->profile->max_state;
|
||||||
wmarkinfo->p_load_target = 700;
|
wmarkinfo->param.load_target = 700;
|
||||||
wmarkinfo->p_load_max = 900;
|
wmarkinfo->param.load_max = 900;
|
||||||
wmarkinfo->p_smooth = 10;
|
wmarkinfo->param.smooth = 10;
|
||||||
wmarkinfo->p_block_window = 50000;
|
wmarkinfo->param.block_window = 50000;
|
||||||
wmarkinfo->p_freq_boost_en = true;
|
wmarkinfo->param.freq_boost_en = true;
|
||||||
wmarkinfo->df = df;
|
wmarkinfo->df = df;
|
||||||
wmarkinfo->pdev = pdev;
|
wmarkinfo->pdev = pdev;
|
||||||
|
|
||||||
devfreq_watermark_debug_start(df);
|
ret = devfreq_watermark_debug_start(df);
|
||||||
|
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int devfreq_watermark_notifier_call(struct notifier_block *nb,
|
static int devfreq_watermark_notifier_call(struct notifier_block *nb,
|
||||||
@@ -350,6 +632,13 @@ static int devfreq_watermark_event_handler(struct devfreq *df,
|
|||||||
nb = &wmarkinfo->nb;
|
nb = &wmarkinfo->nb;
|
||||||
devm_devfreq_unregister_notifier(df->dev.parent,
|
devm_devfreq_unregister_notifier(df->dev.parent,
|
||||||
df, nb, DEVFREQ_TRANSITION_NOTIFIER);
|
df, nb, DEVFREQ_TRANSITION_NOTIFIER);
|
||||||
|
|
||||||
|
/* free wmark_gov_info struct */
|
||||||
|
if (df->data != NULL) {
|
||||||
|
kfree(df->data);
|
||||||
|
df->data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case DEVFREQ_GOV_SUSPEND:
|
case DEVFREQ_GOV_SUSPEND:
|
||||||
devfreq_monitor_suspend(df);
|
devfreq_monitor_suspend(df);
|
||||||
|
|||||||
Reference in New Issue
Block a user